【问题标题】:How do I use System.getProperty("line.separator").toString()?如何使用 System.getProperty("line.separator").toString()?
【发布时间】:2011-03-31 19:48:09
【问题描述】:

我有一个制表符分隔的字符串(代表一个表格),它传递给我的方法。当我将它打印到命令行时,它看起来像一个有行的表:

https://i.stack.imgur.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()?它已经是一个字符串,除非它为空,在这种情况下你会得到一个 NullPointerException。
  • 是的,我只是想确保将字符串而不是字符传递给 .split()。我应该阅读 .getProperty() 方法的文档,但是编写 .toString() 比打开浏览器更快,哈哈。

标签: java eol


【解决方案1】:

我认为您的问题是 String.split() 将其参数视为正则表达式,而正则表达式特别对待换行符。您可能需要显式创建一个正则表达式对象以传递给split()(它还有另一个重载),并通过在Pattern.compile() 的标志参数中传递MULTILINE 来配置该正则表达式以允许换行。 Docs

【讨论】:

  • MULTILINE 标志仅适用于您在正则表达式中使用开始/结束标志(^ 和 $)时。
  • MULTILINE 标志也会导致 "."将行分隔符识别为匹配的字符。
  • @James:不,根据规范(以及根据我的测试) MULTILINE "(?m) 不会导致 "." 字符匹配行分隔符。那将是 DOTALL 标志 " (?s)"
【解决方案2】:

在 Windows 上,line.separator 是 CR/LF 组合(参考 here)。

Java String.split() 方法采用regular expression。所以我认为这里有些混乱。

【讨论】:

    【解决方案3】:

    其他响应者认为 split() 将正则表达式作为参数是正确的,因此您必须先解决该问题。另一个问题是您假设换行符与系统默认值相同。根据数据的来源以及程序运行的位置,这种假设可能不正确。

    【讨论】:

    • 哇...“响应者”听起来很酷。从现在开始我将使用它。
    【解决方案4】:

    试试

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

    这应该可以解决 regex 问题。

    也不是那么重要,但返回类型为

    System.getProperty("line.separator")
    

    String所以不需要调用toString()。

    【讨论】:

    • 谢谢,这行得通。我想我只是阅读了 split() 方法的文档,发现它需要一个字符串,不理解正则表达式和字符串之间的区别。
    • 如果这是 Windows 并且换行符是 "\r\n",这实际上将在 \r\n 之间的 split 创建错误的空字符串。
    【解决方案5】:

    试试这个:

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

    无论输入中的行分隔符是什么,这都应该有效,并且会忽略空行。

    【讨论】:

    • 我原本希望这个 java 程序也能在 Mac/Linux 上运行。因此 System.getProperty() 方法。
    • 您仍然可能有包含非系统默认行分隔符的输入。无论平台和输入如何,此正则表达式都会捕获所有组合。
    【解决方案6】:

    问题

    您必须假定任意输入文本文件使用“正确”的平台特定newline 分隔符。这似乎是您问题的根源;它与正则表达式关系不大。

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

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

    当您生成一个文本文件作为输出时,您可能应该更喜欢特定于平台的换行符分隔符,但是当您使用一个文本文件作为输入时,它是假设它正确使用特定于平台的换行符可能不安全。


    解决办法

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

    你也可以组合2个Scanner,一个用来逐行扫描文件,另一个用来扫描每一行的token。这是一个简单的用法示例,它将每一行分成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 第 2 版,第 25 条:优先使用列表而不是数组

    相关问题

    【讨论】:

    • 感谢您抽出宝贵时间回答。我尝试了其他解决方案之一并且它起作用了(它比在正确的位置设置扫描仪要快)。由于这只是我的 java 程序的一小部分,而且我确切地知道输入将是什么(它不是任意输入文本文件),我可以假设默认的换行符。我查看了返回此输入字符串的另一种方法,它使用平台默认字符。不过,感谢您的所有帮助。
    • 我在 linux 中解析 Outlook pst 电子邮件标头,^M 注释帮助我理解了 cat -A 的输出。在我的情况下,绝对不想要 line.separator 属性。
    【解决方案7】:

    尝试BufferedReader.readLine(),而不是所有这些复杂的事情。它将识别所有可能的行终止符。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-16
      • 1970-01-01
      • 2012-11-05
      • 2020-05-16
      • 1970-01-01
      • 2013-01-07
      相关资源
      最近更新 更多