为什么String.split("£", 2)无法工作?

4
我有一个文本文件,包含1000行,格式如下:
19 x 75 Bullnose Architrave/Skirting £1.02 

我正在编写一个方法,逐行读取文件 - 这个方法可以正常工作。
然后我想使用"£"作为分隔符来分割每个字符串,并将其按以下格式写入一个ArrayList<String>
19 x 75 Bullnose Architrave/Skirting, Metre, 1.02

这是我的处理方式(productList 是在 try 块外声明/实例化的 ArrayList):
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”。
任何建议都将很有帮助。

1
当您将System.out.println(inputLine.indexOf(delim));作为循环的第一个操作时,它会打印什么? - jlordo
3
可能的原因有:1)源文件的编码和编译命令使用的编码不匹配;2)阅读器的编码没有正确指定。最有可能是由于您代码中的第2个原因。 - nhahtdh
1
在分割输入行之前打印inputLine并检查内容。 - assylias
如果是(1),您可以使用String delim = "\u00A3"来确保它是正确的字符串,无论.java文件的编码如何。 - Ian Roberts
你能确保每一行都包含 £ 吗?另外,作为建议,你可以使用一个只有一行的小测试文件,并打印出所有内容,以查看问题所在。 - sleepsort
@assylias输入行打印输出结果如预期。 - Simon Page
3个回答

6
以下是一些可能的原因:
  • 文件的编码与您用来读取它的编码不匹配,文件中的"pound"字符被"破坏"成其他字符。

  • 文件和您的源代码使用不同的类似"pound"的字符。例如,Unicode有两个代码点看起来像一个"英镑符号"——英镑字符(00A3)和里拉字符(2084)、罗马semuncia字符(10192)。

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


根据您的评论,这是一个编码不匹配的问题;即Java使用的"默认"编码与文件的实际编码不匹配。解决此问题有两种方法:
  • Change the encoding of the file to match Java's default encoding. You seem to have tried that and failed. (And it wouldn't be the way I'd do this ...)

  • Change the program to open the file with a specific (non default) encoding; e.g. change

    new FileReader(aFile)
    

    to

    new FileReader(aFile, encoding)
    

    where encoding is the name of the file's actual character encoding. The names of the encodings understood by Java are listed here, but my guess is that it is "ISO-8859-1" (aka Latin-1).


@jlordo System.out.println(inputLine.indexOf(delim)); 返回-1。 - Simon Page
@nhahtdh - 我使用Notepad ++,尝试将文件保存为UTF 8 endof/endon等格式,但无济于事! - Simon Page
19 x 50牛鼻线门套板 ð.69 - Simon Page

0

这可能是编码不匹配的情况。为了检查这个问题,

  • 打印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) + ")");

1
delim.length 的值始终为1。 - assylias
@assylias 如果源文件编码为UTF-8,而编译器认为它是ISO-8859-1(或其他单字节字符集),那么就不行。 - kmkaplan
2
@assylias 这是看到的。我的观点是要检查编译器看到了什么。 - kmkaplan
@Kmkaplan delim的索引..-1 delim的长度1 inputline的长度34 - Simon Page
1
@SimonPage "inputline 34的长度"?这是非常错误的。请查看我的编辑以获取一些调试轨迹。 - kmkaplan

-1

非常感谢您的回复。

在读取和保存原始文本文件为UTF-8时指定编码已经起作用。

然而,这次经历告诉我,使用“£”或其他可能在不同编码中具有多个表示的字符来分隔文本是一种不好的策略。

我决定采取不同的方法:

1)找到输入字符串中的最后一个空格,并用“xxx”或类似字符替换它。

2)使用分隔符“xxx”拆分此字符串。这应该会拆分字符串并去除“£”。

3)继续进行...


不要使用将空格替换为标记的可怕方法进行分割,为什么不尝试以下变体:int split_idx = inputLine.lastIndexOf(" "); if (split_idx >= 0) lineOut = inputLine.substring(0, split_idx) + ", Metre," + inputLine.substring(split_idx); - Michael Burr

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