21

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

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。

有任何想法吗?

4

7 回答 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 第 2 版,第 25 条:优先使用列表而不是数组

相关问题

于 2010-08-19T08:15:17.853 回答
29

尝试

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

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

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

System.getProperty("line.separator")

字符串,所以不需要调用 toString()。

于 2010-08-18T22:06:28.650 回答
2

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

JavaString.split()方法采用正则表达式。所以我认为这里有些混乱。

于 2010-08-18T21:55:48.397 回答
2

尝试BufferedReader.readLine()而不是所有这些并发症。它将识别所有可能的线路终止符。

于 2010-08-19T09:08:56.847 回答
1

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

于 2010-08-18T21:52:19.743 回答
1

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

于 2010-08-18T22:00:24.987 回答
1

试试这个:

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

无论输入中的行分隔符如何,这都应该有效,并且将忽略空行。

于 2010-08-18T22:21:12.020 回答