Java中使用"."(点号)进行字符串分割

479

为什么这段代码的第二行会抛出 ArrayIndexOutOfBoundsException 异常?

String filename = "D:/some folder/001.docx";
String extensionRemoved = filename.split(".")[0];

虽然这个可以工作:

String driveLetter = filename.split("/")[0];

我使用Java 7。


7
分割函数使用正则表达式字符串吗?如果是的话,"."代表任意字符。 - Felix Glas
4
“//”是用来分隔的,需要输入两个斜杠。 - Ben
4个回答

950

如果想要按字面意义分割点,你需要转义这个点:

String extensionRemoved = filename.split("\\.")[0];
否则,你正在使用正则表达式 . 进行切割,它表示“任何字符”。请注意,需要双反斜杠才能在正则表达式中创建单个反斜杠。

当输入字符串只是一个点,即"."时,您会收到ArrayIndexOutOfBoundsException异常,这是一种边缘情况,因为在点上进行分割会产生一个空数组;split(regex)会从结果中删除所有尾随空白,但由于在点上进行分割只留下两个空白,因此在删除尾随空白后,您将得到一个空数组。
为了避免在这种边缘情况下出现ArrayIndexOutOfBoundsException,请使用重载版本的split(regex,limit),它具有第二个参数,即生成数组的大小限制。当limit为负数时,禁用从结果数组中删除尾随空白的行为:
".".split("\\.", -1) // returns an array of two blanks, ie ["", ""]

例如,当filename只是一个点"."时,调用filename.split("\\.", -1)[0]会返回一个空白,但调用filename.split("\\.")[0]会抛出一个ArrayIndexOutOfBoundsException异常。


1
请注意,文件名可能包含多个点。必须使用最后一个 "." 的索引,并使用它来查找文件名的子字符串。 - saurabheights
2
@saurabheights 这个问题不是关于正确的正则表达式,而是为什么会出现 ArrayIndexOutOfBoundsException。话虽如此,你的回答是错误的:你不需要知道最后一个点在哪里;你只需要正确的正则表达式:filename.split("\\.(?=[^.]*$)")。这个正则表达式使用了 前瞻 来断言在匹配点之后的输入中没有任何点。 - Bohemian
1
@emma,你可以通过问题下方的“删除”链接自行删除它们。 - Bohemian
1
更简洁的解决方案:str.split(Pattern.quote("."))[0] - A. Hafid
@TomRutchik 你其实不需要四个反斜杠:请参考实时演示 - Bohemian
显示剩余4条评论

139

在Java正则表达式引擎中,“.”是一个特殊字符,因此你需要使用“\\.”来转义这个字符:

final String extensionRemoved = filename.split("\\.")[0];

29
在Java中,它不是一个特殊字符,而是在Java的正则表达式引擎中是一个特殊字符。 - anon
1
我在回答中并不是很准确,但我同意你的观点。谢谢你的精确指出 ;) - aimhaj
1
这是一个值得区分的差别。另外,我刚意识到我自己有点搞砸了;虽然在Java中它是一个特殊字符,但这并不是导致问题的原因。无论如何。 - anon

35
这是因为在正则表达式中.是一个保留字符,代表任何字符。因此,我们应该使用以下语句:
String extensionRemoved = filename.split("\\.")[0];

21

我认为你应该转义这个点。尝试:

String filename = "D:/some folder/001.docx";
String extensionRemoved = filename.split("\\.")[0];
否则点在正则表达式中被解释为任何字符。

1
更简洁的解决方案:str.split(Pattern.quote("."))[0] - A. Hafid

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