【问题标题】:How to sort files entries correctly using Java and regex如何使用 Java 和正则表达式正确排序文件条目
【发布时间】:2021-07-06 13:52:26
【问题描述】:

我有一个包含以下条目的文本文件“unsorted.txt”输入:

37060635563
37067264426
37061457700
37067116332
37068672376
37068669157

我希望 Java 按以下方式在输出文件“sorted.txt”中整理和格式化这些数字。

+370 606 35563
+370 614 57700
+370 686 69157
+370 686 72376
+370 671 16332
+370 672 64426

我已经对 Java 代码进行了排序,但它只产生一个条目,我找不到原因?

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Scanner;
import java.io.File;
import java.io.FileWriter;
        
public class PhoneSort {

    public static void main(String[] args) {
        
        final String regex = "(\\\\d{3})(\\\\d{3})(\\\\d*)";
        final String subst = "+$1 $2 $3";
        final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
        
        File us = new File("unsorted.txt");
        File st = new File("sorted.txt");
        String result = "";
        
        try (Scanner sc = new Scanner(us)){
                 while (sc.hasNextLine()) {
                        try (FileWriter writer = new FileWriter(st)) {
                          writer.write(pattern.matcher(sc.nextLine()).replaceAll(subst)); 
                         } catch(IOException e){}
                    }
                }
        catch (IOException e){}   
    }
}

【问题讨论】:

  • 永远不要只消耗错误,而是将其打印到控制台,以便您查看失败的原因catch (IOException e){e.printStackTrace();},此外,您需要在每次写入后关闭文件写入器,或者您需要声明您的文件编写器在您的 while 循环之外,而不是每次都尝试创建一个新的。
  • 686 之前出现了哪些条目671

标签: java regex sorting text java-io


【解决方案1】:

如果您想知道为什么您的代码只运行一次,那么您需要进行一些调试,并且您需要将任何捕获的异常打印到控制台,这样您就可以看到您的代码失败的原因catch (IOException e){e.printStackTrace();}。除非您确切地知道自己在做什么以及如果出现问题会发生什么,否则永远不要只消耗错误。

现在我们有两个问题之一,第一个是您的代码失败,如果是这样,那么正在打印的错误将显示您的文件编写器有问题,这可能意味着您需要关闭文件编写器每次写入后,都会产生不同的问题(见下文)。

但是,更可能的问题是您每次都在创建一个新的 FileWriter 并覆盖您以前的文件。要解决这个问题,您需要在 while 循环之外声明文件编写器,而不是每次都尝试创建一个新的。

以下应该可以工作,注意我们现在如何将错误打印到控制台,以及我们如何只创建一次 FileWriter:

    //We can also add the true flag to append data to the file writer
    try (Scanner sc = new Scanner(us);
      FileWriter writer = new FileWriter(st, true);){            
        while (sc.hasNextLine()) {
            writer.write(pattern.matcher(sc.nextLine()).replaceAll(subst)); 
        }
        writer.close();
    }
    catch (IOException e){
        e.printStackTrace();
    }   

【讨论】:

  • @user15358848 我已经更新了我的答案,我认为你一针见血。
  • 如果录制过程中出现异常,文件写入器的工作不正确,文件将保持打开状态,必须在 try-with-resources 中声明或在 finally 块中手动关闭
  • 亲爱的@sorifiend,您还没有修复关闭文件的代码,这被认为是使用 java.io 的错误示例,请修复。
  • FileWriter 也是应该关闭的资源。为什么它和 Scanner 一起不在 try-with-resources 的第一部分,所以它会自动关闭?现在writer.close();try 部分内,所以如果在该行之前抛出一些异常,它将阻止调用writer.close();
【解决方案2】:

假设您希望输出是,我正在写这个答案,

+370 606 35563
+370 614 57700
+370 671 16332
+370 672 64426
+370 686 69157
+370 686 72376

我的方法不使用正则表达式,而是将文件读入内存。

  1. 将文件中的所有行读入List
  2. 根据要求对以上列表进行排序。 (按前三位数字排序 - 如果它们相同,则按接下来的三位数字排序。即使它们相等,也按其余数字排序)。
  3. 将排序后的列表写入结果文件。

Path path = Paths.get("<fill_the_path>/unsorted.txt");
List<String> lines = Files.readAllLines(path); 
List<String> sortedList = sort(lines);    

Files.write(Paths.get("<fill_the_path>/sorted.txt"),
            format(sortedList),
            StandardOpenOption.CREATE);



private List<String> sort(List<String> lines) {
    Comparator<String> comparator = Comparator.comparing((String s) -> Integer.valueOf(s.substring(0, 3)))
            .thenComparing(s -> Integer.valueOf(s.substring(3, 6)))
            .thenComparing(s -> Integer.valueOf(s.substring(6)));
    return lines.stream()
            .sorted(comparator)
            .collect(Collectors.toList());
}


private List<String> format(List<String> lines) {
    return lines.stream()
            .map(this::formatLine)
            .collect(Collectors.toList());
}

private String formatLine(String line) {
    return "+" +
            line.substring(0, 3) + " " +
            line.substring(3, 6) + " " +
            line.substring(6);
}

注意:您可以将每一行转换为Long,也可以使用Comparator.comparingLong(如果该值适合long)。

return lines.stream()
        .sorted(Comparator.comparingLong(Long::valueOf))
        .collect(Collectors.toList());

【讨论】:

  • 您好,可能我错了,但可以将数字排序为字符串,然后将它们格式化为三个子字符串?感谢您的关注。
  • @dariosicily 这就是它的完成方式,它给出了预期的结果stackoverflow.com/questions/67042184/…
  • @dariosicily 在这种情况下,当两个相同大小的文本可以作为文本排序时,但通常将数字作为字符串排序是错误的,因为行将逐个字符排序,因此 11 将被认为超过 101
【解决方案3】:

这是一个具有预期结果的工作示例

public static void main(String[] args) {
    final String regex = "(\\d{3})(\\d{3})(\\d*)";
    final String subst = "+$1 $2 $3";
    final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);

    File us = new File("unsorted.txt");
    File st = new File("sorted.txt");

    try (BufferedReader reader = new BufferedReader(new FileReader(us));
         BufferedWriter writer = new BufferedWriter(new FileWriter(st))) {
        reader.lines().sorted()
                .map(r -> pattern.matcher(r).replaceAll(subst))
                .forEach(res -> {
                    try {
                        writer.write(res);
                        writer.newLine();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                });
    } catch (IOException e) {
        e.printStackTrace();
    }
}

【讨论】:

    猜你喜欢
    • 2011-10-30
    • 2019-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-14
    • 1970-01-01
    • 1970-01-01
    • 2017-12-22
    相关资源
    最近更新 更多