【问题标题】:why is String.split("£", 2) not working?为什么 String.split("£", 2) 不起作用?
【发布时间】:2012-12-20 10:11:24
【问题描述】:

我有一个包含 1000 行的文本文件,格式如下:

19 x 75 Bullnose Architrave/Skirting £1.02 

我正在编写一个逐行读取文件的方法 - 这工作正常。

然后我想使用“£”作为分隔符拆分每个字符串并将其写入 一个ArrayList<String>,格式如下:

19 x 75 Bullnose Architrave/Skirting, Metre, 1.02

这就是我的处理方式(productListArrayList,在 try 块之外声明/实例化):

try{
    br = new BufferedReader(new FileReader(aFile));
    String inputLine = br.readLine();
    String delim = "£";

    while (inputLine != null){
        String[]halved = inputLine.split(delim, 2);
        String lineOut = halved[0] + ", Metre, " + halved[1];//Array out of bounds
        productList.add(lineOut);

        inputLine = br.readLine();
    }
}

字符串没有拆分,我不断收到ArrayIndexOutOfBoundsException。我对正则表达式不是很熟悉。我也尝试过使用旧的StringTokenizer,但得到了相同的结果。

£ 作为分隔符有问题还是其他原因?我确实想知道这是否与第二个令牌没有被读取为 String 有关?

任何想法都会有所帮助。

【问题讨论】:

  • System.out.println(inputLine.indexOf(delim)); 打印什么,当您将其作为循环的第一个操作时?
  • 有一些可能的原因:1)源文件的编码和编译命令中使用的编码不匹配2)阅读器的编码没有指定正确。最有可能 2) 来自您的代码。
  • 在拆分前打印 inputLine 并检查内容。
  • 如果是 (1),您可以使用 String delim = "\u00A3" 来确保它是正确的字符串,无论 .java 文件的编码如何。
  • 你能确定每一行都包含£吗?另外,作为建议,您可以使用一个只有一行的小测试文件,然后打印所有内容以查看问题所在。

标签: java regex string split


【解决方案1】:

以下是一些可能的原因:

  • 文件的编码与您用来读取它的编码不匹配,并且文件中的“磅”字符被“破坏”成其他内容。

  • 文件和您的源代码使用不同的类似井号的字符。例如,Unicode 有两个看起来像“磅符号”的代码点 - 英镑字符 (00A3) 和里拉字符 (2084)……然后是罗马字符 (10192)。

  • 您试图编译一个 UTF-8 编码的源文件,却没有告诉编译器它是 UTF-8 编码的。


从你的cmets来看,这是一个编码不匹配的问题;即 Java 使用的“默认”编码与文件的实际编码不匹配。有两种方法可以解决这个问题:

  • 更改文件的编码以匹配 Java 的默认编码。您似乎已经尝试过但失败了。 (而且我不会这样做......)

  • 更改程序以使用特定(非默认)编码打开文件;例如改变

    new FileReader(aFile)
    

    new FileReader(aFile, encoding)
    

    其中encoding 是文件实际字符编码的名称。 Java 可以理解的编码名称在here 中列出,但我猜它是“ISO-8859-1”(又名 Latin-1)。

【讨论】:

  • @jlordo System.out.println(inputLine.indexOf(delim));返回 -1。
  • @nhahtdh - 使用记事本++,我尝试将文件格式保存为 UTF 8 endof/endon 等...无济于事!
  • 19 x 50 Bullnose Architrave ð.69
【解决方案2】:

这可能是编码不匹配的情况。要检查这一点,

  • 打印delim.length 并确保它是1
  • 打印 inputLine.length 并确保它是正确的值 (42)。

如果其中之一不是预期值,那么您必须确保您在所有地方都使用 UTF-8。

你说delim.length 是 1,所以这很好。另一方面,如果inputLine.length 是 34,这是 非常 错误的。对于"19 x 75 Bullnose Architrave/Skirting £1.02",如果一切都符合预期,您应该得到 42。如果您的文件是 UTF-8 编码但读取为 ISO-8859-1 或类似文件,您将得到 43。

现在我有点不知所措。要调试它,您可以单独打印字符串的每个字符并检查它们有什么问题。

for (int i = 0; i < inputLine.length; i++)
    System.err.println("debug: " + i + ": " + inputLine.charAt(i) + " (" + inputLine.codePointAt(i) + ")");

【讨论】:

  • delim.length 将始终为 1。
  • @assylias 如果源文件以 UTF-8 编码并且编译器认为它是 ISO-8859-1(或另一个单字节字符集),则不会。
  • @assylias 这就是看到的。我的意思是检查 compiler 看到了什么。
  • @Kmkaplan index of delim ..-1 delim 长度 1 inputline 34 长度
  • @SimonPage “输入行 34 的长度”?这是非常错误的。请参阅我的编辑以了解一些调试轨道。
【解决方案3】:

非常感谢您的所有回复。

在读取中指定编码并将原始文本文件保存为 UTF -8 有效。

但是,经验告诉我,使用“£”或其他可能在不同编码中具有多种表示形式的字符来分隔文本是一种糟糕的策略。

我决定采取不同的方法:

1) 查找输入字符串中的最后一个空格并将其替换为“xxx”或类似内容。

2) 使用分隔符“xxx”拆分它。这应该拆分字符串并撕掉“£”。

3) 继续..

【讨论】:

  • 而不是用标记替换空格来分割的可怕黑客,为什么不使用一些变体:int split_idx = inputLine.lastIndexOf(" "); if (split_idx &gt;= 0) lineOut = inputLine.substring(0, split_idx) + ", Metre," + inputLine.substring(split_idx);
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-16
相关资源
最近更新 更多