如何使用System.getProperty("line.separator").toString()?

21

我有一个包含表格的Tab分隔字符串,它作为参数传递给我的方法。当我在命令行上将其打印出来时,它呈现为一张带有行的表格:

https://istack.dev59.com/2fAyq.gif

命令窗口已正确缓冲。我认为每行前后肯定有一个换行符。

我的问题是,我想将传入的字符串拆分成表示表格行的单个字符串。到目前为止,我已经尝试了:

private static final String newLine = System.getProperty("line.separator").toString();
private static final String tab = "\t";
private static String[] rows;
...

rows = tabDelimitedTable.split(newLine);    //problem is here
    
System.out.println();
System.out.println("################### start debug ####################");

System.out.println((tabDelimitedTable.contains(newLine)) ? "True" : "False");
    
System.out.println("#################### end debug###################");
System.out.println();

输出:

################### start debug ####################
False
#################### end debug###################

很明显字符串中有些东西告诉操作系统开始新的一行,但它似乎不包含任何换行符。

在Windows XP SP3上运行最新版本的JDK。

有任何想法吗?


为什么要使用.toString()?它已经是一个字符串,除非它是null,在这种情况下你会得到一个NullPointerException。 - user207421
1
是的,我只是想确保我传递给 .split() 方法的是字符串而不是字符。我本应该阅读一下 .getProperty() 方法的文档,但写 .toString() 比打开浏览器快多了,哈哈。 - ejsuncy
7个回答

30

问题

不要假设任意输入文本文件使用“正确”的平台特定换行符。这似乎是你的问题的根源; 它与正则表达式关系不大。

举个例子,在Windows平台上,System.getProperty("line.separator")"\r\n"(CR + LF)。但是,在此平台上运行Java代码时,您可能必须处理一个仅使用"\n"(LF)作为行分隔符的输入文件。也许该文件最初是在Unix平台上创建的,然后以二进制(而不是文本)模式传输到Windows。可能会遇到许多这种情况,您必须解析一个不使用当前平台的换行符的文本文件作为输入。

(巧合的是,当将Windows文本文件以二进制模式传输到Unix时,许多编辑器都会显示^M,这使一些人感到困惑,不知道发生了什么)。

当您正在生成输出文本文件时,应该优先考虑特定于平台的换行符,但是当您正在使用文本文件作为输入时,假定它正确地使用平台特定的换行符可能是不安全的。


解决方案

解决问题的一种方法是使用例如java.util.Scanner。它有一个nextLine()方法,可以返回下一行(如果存在),正确处理平台的换行符和输入文本文件之间的任何不一致。

您还可以组合2个Scanner,一个逐行扫描文件,另一个扫描每行的标记。这是一个简单的用法示例,将每行分解为List<String>。因此,整个文件变成了一个List<List<String>>

这可能比将整个文件读入一个巨大的String,然后将其split成行(然后将其split成部分)更好。

    String text
        = "row1\tblah\tblah\tblah\n"
        + "row2\t1\t2\t3\t4\r\n"
        + "row3\tA\tB\tC\r"
        + "row4";

    System.out.println(text);
    //  row1    blah    blah    blah
    //  row2    1   2   3   4
    //  row3    A   B   C
    //  row4

    List<List<String>> input = new ArrayList<List<String>>();

    Scanner sc = new Scanner(text);
    while (sc.hasNextLine()) {
        Scanner lineSc = new Scanner(sc.nextLine()).useDelimiter("\t");
        List<String> line = new ArrayList<String>();
        while (lineSc.hasNext()) {
            line.add(lineSc.next());
        }
        input.add(line);
    }
    System.out.println(input);
    // [[row1, blah, blah, blah], [row2, 1, 2, 3, 4], [row3, A, B, C], [row4]]

参见

  • Effective Java 2nd Edition, Item 25: 偏爱列表而不是数组

相关问题


1
感谢您抽出时间回答。我尝试了其他解决方案之一,它有效了(比在正确位置设置扫描仪更快)。由于这只是我的Java程序的一小部分,并且我知道输入将是什么(不是任意输入文本文件),因此我可以假设默认换行符。我已经查看了返回此输入字符串的其他方法,它使用平台默认字符。再次感谢您的所有帮助。 - ejsuncy
我在Linux中解析Outlook PST邮件头,^M注释帮助我理解了cat -A命令的输出。在我的情况下绝对不想使用line.separator属性。 - user4256874

29

尝试一下

rows = tabDelimitedTable.split("[" + newLine + "]");

这应该可以解决正则表达式的问题。

还不是很重要,但是返回类型为

System.getProperty("line.separator")

字符串已经是String类型,不需要调用toString()方法。


谢谢,这很有效。我想我只是阅读了split()方法的文档并看到它需要一个字符串,但我不理解正则表达式和字符串之间的区别。 - ejsuncy
6
如果这是Windows,换行符为"\r\n",那么实际上会在\r\n之间进行split操作以创建虚假的空字符串。 - polygenelubricants

2
在Windows上,line.separator是CR/LF组合(参考这里)。
Java的String.split()方法需要一个正则表达式。因此我认为这里有些混淆。

2

尝试使用BufferedReader.readLine()代替所有这些复杂操作。它将识别所有可能的行终止符。


1

试试这个:

rows = tabDelimitedTable.split("[\\r\\n]+");

这应该可以在输入中无论使用什么行分隔符都能正常工作,并且会忽略空白行。


我最初希望这个Java程序也能在Mac/Linux上运行,因此使用了System.getProperty()方法。 - ejsuncy
您仍然可能有包含非系统默认行分隔符的输入。此正则表达式将捕获所有组合,无论平台和输入如何。 - James Van Huis

1

我认为你的问题在于String.split()将其参数视为正则表达式,而正则表达式会特殊处理换行符。你可能需要显式创建一个正则表达式对象传递给split()(它有另一个重载),并通过在Pattern.compile()的flags参数中传递MULTILINE来配置该正则表达式以允许换行符。文档


MULTILINE标志仅适用于在正则表达式中使用起始/结束标志(^和$)时。 - James Van Huis
MULTILINE标志还会导致“.”字符将行分隔符识别为匹配项。 - James Van Huis
@James:不对,根据规格说明(以及我的测试),MULTILINE "(?m)" 不会使 "." 字符匹配行分隔符。这应该使用 DOTALL 标志 "(?s)"。 - Maarten Bodewes

1
其他回答者说得没错,split()函数需要一个正则表达式作为参数,所以你首先需要修复这个问题。另一个问题是你假设换行符与系统默认值相同。根据数据来源和程序运行的位置,这种假设可能是不正确的。

1
哇...“Responders”听起来很酷。从现在开始我也要用这个词了。 - NullUserException

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接