比较列表中字符串的日期

Compare dates from a String in list

我在继续时遇到问题。我有一个列表,每个位置都包含一个字符串(在短语末尾有一个日期)

示例:

I am new here 20/8/2019 

我想这样排序列表: 在零位置,我想要包含最旧日期的短语,而以下位置的日期将更近。

我试过用SimpleDateFormat和Date,但是不知道怎么做。

String variable, variable2, c;
int d = 0;
for(int i = 0; i < lista.size(); i++) {
    for(int j = 1; j <lista.size(); j++) {
        variable = lista.get(i);
        variable2 = lista.get(j);
        c = compareDates(variable, variable2);
        lista.add(d,c);
        d++;
    }
}

private static Date compareDates(String variable, String variable2) throws ParseException {
    SimpleDateFormat formateador = new SimpleDateFormat("dd/MM/yyyy");
    String var = formateador.format(variable);
    String var2 = formateador.format(variable2);
    if (var.before(var2)) {
        return var;
    } else {
        if (var2.before(var1)) {

        } else {

        }
        return null;
    }
}

线程异常"main"java.lang.Error:未解决的编译问题: 类型不匹配:无法从 Date 转换为 String

at Ejercicio.ClaseMain.leerDes(ClaseMain.java:124)

Line 124: c = compareDates(variable, variable2);

视觉示例:列表中的每个位置都有一个带日期的短语:

问题是,我读取了一个 .txt 文件,其中有几行。 文件内容:

Sevilla reserves himself to Apoel and wins without brilliance; sport Julen Lopetegui revolutionized the eleven with the aim of giving rest to the regulars, which did not prevent his team from adding his second triumph of the competition sportyou 10/10/2019

A painting by Banksy of the British Parliament occupied by chimpanzees, sold >for 11 million euros culture An oil of artist Banksy representing the British House of Commons full of chimpanzees was topped on Thursday at an auction in London for 9.8 million pounds (11 million euros) 10/2019

我用了一会儿读取文件行并在列表中的每个位置保存每一行,我想对列表进行排序。旧日期 ---> 最近日期。

请不要使用遗留日期库,而是使用 java.time API,因此如果您使用 Java 8,您的解决方案可以是:

String[] strs = {"20/10/2019", "5/2/2019", "12/12/2019",
        "1/8/2019", "25/12/2019", "2/1/2019", "6/9/2019"};
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/uuuu");
List<LocalDate> collect = Stream.of(strs)
        .map(s -> LocalDate.parse(s, formatter))  // convert your strings to dates
        .sorted() // sort the dates
        .collect(Collectors.toList()); // collect the result in a collection

输出

[2019-01-02, 2019-02-05, 2019-08-01, 2019-09-06, 2019-10-20, 2019-12-12, 2019-12-25]

“20/8/2019”等日期与模式不匹配 "dd/MM/yyyy"。正确的格式应该类似于“20/08/2019”。 排序的最短解决方案是

list.sort(Comparator.comparing(
    source -> LocalDate.parse(source, DateTimeFormatter.ofPattern("dd/MM/yyyy"))));

发生错误是因为在 compareDates 方法 return 类型是 Date 而 return 是 String.

现在开始解决方案,如果目的只是获取从短语中提取的排序日期,这应该可行。但是查看 OP 中的代码,我感觉到您正在尝试对按日期排序的短语列表进行冒泡排序,这也可以按照相同的行来实现。

重要的部分是通过Regex提取日期。

代码:

List<LocalDate> ld = new ArrayList<LocalDate>();
for(int i = 0; i < lista.size(); i++){
  ld.add(getDateFromString(lista.get(i)));
}
//sorting the list of dates extracted
ld = ld.stream().sorted().collect(Collectors.toCollection(ArrayList::new));

private static LocalDate getDateFromString(String str){
  LocalDate d;
  //looks for pattern dd/mm/yyyy in the passed string
  Matcher m = Pattern.compile("(\d{1,2}/\d{1,2}/\d{4})").matcher(str);
  if(m.find()) {
   String match = m.group(1);
   d = LocalDate.parse(match, DateTimeFormatter.ofPattern("d/MM/yyyy"));
  }
  return d;
}

注: 这假设每个短语都有一个 dd/mm/yyyy

形式的日期字符串

考虑到 List 中的所有字符串都具有相同的格式,并且在拆分后的第四个索引处具有 date,如下所示

List<String> list = new ArrayList<>();
list.add("I am new here 20/11/2019 ");
list.add("I am Deadpool here 20/7/2019 ");
list.add("I am IronMan here 20/6/2019 ");

现在使用比较器根据 LocalDate

List 进行排序
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/M/yyyy");
list.sort(Comparator.comparing(str->LocalDate.parse(str.split(" ")[4],formatter)));

    System.out.println(list);  //I am IronMan here 20/6/2019 , I am Deadpool here 20/7/2019 , I am new here 20/11/2019 ]

简单地说,如果您不知道日期字符串的格式,则无法将字符串转换为日期。 “10/11/12”是 12 年的 10 月 11 日还是 11 月 10 日,还是 10 年的 11 月 12 日?参见 How to convert String to Date without knowing the format?

在您的文本示例中,最后日期只是“10/2019”,您使用“20/8/2019”作为另一个示例,因此您似乎混合了多种可能的格式。如果您可以限制可能性,则可能找到最佳匹配。

如果您可以使用正则表达式提取该日期作为文本末尾的数字序列和正斜杠(参见 ambianBeing 的回答),那么您可以尝试使用可能的格式解析此字符串从最严格到最宽松,捕获 'DateTimeParseException' 异常并在第一次成功解析时停止。如果没有成功,请标记它,以便您可以确定要修复的内容 - 文本、添加新格式或更好的正则表达式。

使用上面的示例,您可以从格式模式开始

  • dd/MM/yyyy
  • dd/M/yyyy
  • MM/yyyy

如果一切都失败了,请使用空日期来标记该条目。

如果您将其放在 returns 日期的方法中,则可以使用流解决方案按照其他几个人的建议对列表进行排序。

我的解决方案是:

    List<String> lista = List.of(
            "Sevilla reserves himself to Apoel … sportyou 10/10/2019",
            "I am new here 20/8/2019",
            "A painting by Banksy … 19/10/2019");
    List<String> sortedList = lista.stream()
            .map(s -> new Object() {
                String theString = s;
                LocalDate date = extractDate(s);
            })
            .sorted(Comparator.comparing(obj -> obj.date))
            .map(obj -> obj.theString)
            .collect(Collectors.toList());
    sortedList.forEach(System.out::println);

这个输出是:

I am new here 20/8/2019
Sevilla reserves himself to Apoel … sportyou 10/10/2019
A painting by Banksy … 19/10/2019

我使用的extractDate方法是:

private static Pattern datePattern = Pattern.compile("\d{1,2}/\d{1,2}/\d{4}$");
private static DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("d/M/u");

private static LocalDate extractDate(String fullString) {
    Matcher m = datePattern.matcher(fullString);
    if (m.find()) {
        String dateString = m.group();
        return LocalDate.parse(dateString, dateFormatter);
    } else {
        throw new IllegalArgumentException("String doesn’t end with a date: " + fullString);
    }
}

为了有效地对字符串进行排序——只有当有很多字符串时才重要——我正在提取尾随日期并为每个字符串只解析一次(不是每次比较)。我正在解析为 LocalDate 并使用它们进行排序。为了在排序后得到原始字符串,我将 StringLocalDate 都放入一个对象中,然后对这些对象进行排序。我可以用这种方式使用 Object 的匿名子类,这可能会让一些人感到惊讶,但它工作得很好。

我建议您不要使用 SimpleDateFormatDate。那些 类 设计不佳且早已过时,前者尤其是出了名的麻烦。相反,我使用 LocalDateDateTimeFormatter,两者都来自 java.time,现代 Java 日期和时间 API.

Java 内置了很好的排序工具。如果编写自己的排序算法是为了练习,那是一个很好的练习。坦率地说,在排序工作之前,您还有很长的路要走。您可能想阅读有关排序算法的内容,在 WWW 上也有很多内容。对于生产代码,您应该依赖库方法。

Link: Oracle tutorial: Date Time 解释如何使用 java.time.