奇怪的Java Unicode正则表达式StringIndexOutOfBoundsException

bin*_*nit 14 java regex unicode

我的问题很简单但令人费解.可能有一个简单的开关可以解决这个问题,但我对Java正则表达不太熟悉......

String line = "";
line.replaceAll("(?i)(.)\\1{2,}", "$1");
Run Code Online (Sandbox Code Playgroud)

这崩溃了.如果我取下(?i)开关,它就可以了.三个unicode字符不是随机的,它们是在韩文大文中发现的,但我不知道它们是否有效.

奇怪的是,正则表达式适用于所有其他文本,但这一点.为什么我会收到错误?

这是我得到的例外

Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 6
    at java.lang.String.charAt(String.java:658)
    at java.lang.Character.codePointAt(Character.java:4668)
    at java.util.regex.Pattern$CIBackRef.match(Pattern.java:4846)
    at java.util.regex.Pattern$Curly.match(Pattern.java:4125)
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4615)
    at java.util.regex.Pattern$CharProperty.match(Pattern.java:3694)
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4556)
    at java.util.regex.Pattern$Start.match(Pattern.java:3408)
    at java.util.regex.Matcher.search(Matcher.java:1199)
    at java.util.regex.Matcher.find(Matcher.java:592)
    at java.util.regex.Matcher.replaceAll(Matcher.java:902)
    at java.lang.String.replaceAll(String.java:2162)
    at tokenizer.Test.main(Test.java:51)
Run Code Online (Sandbox Code Playgroud)

eis*_*eis 1

桑托什在此答案中的解释是不正确的。这可以通过运行来证明

\n\n
String str = "";\nSystem.out.println("code point: " + .codePointAt(0));\n
Run Code Online (Sandbox Code Playgroud)\n\n

这将输出(至少对我来说)值 128149,该页面确认该值是正确的。所以Java不会以错误的方式解释字符串。使用 getBytes() 方法时它确实解释错误。

\n\n

然而,正如OP所解释的,正则表达式似乎崩溃了。我对此没有其他解释,因为它是 java 中的一个错误。要么是这样,要么它在设计上不完全支持 UTF-16。

\n\n

编辑:

\n\n

基于这个答案

\n\n
\n

正则表达式编译器搞砸了 UTF-16。同样,这永远无法修复,否则会改变旧程序。您甚至无法通过使用 java -encoding UTF-8 编译来解决 Java\xe2\x80\x99s Unicode-in-source-code\n 问题的正常解决方法来解决这个错误,因为愚蠢的\n 东西存储了字符串作为令人讨厌的 UTF-16,这必然会在字符类中破坏它们。哎呀!

\n
\n\n

看来这是java中正则表达式的限制。

\n\n
\n\n

既然你这么评论了

\n\n
\n

如果我可以简单地忽略 UTF-16 字符并应用正则表达式而不是抛出异常,那就最好了。

\n
\n\n

这当然可以做到。一种简单的方法是仅将正则表达式应用于特定范围。过滤 unicode 字符范围已在此答案中进行了解释。基于这个答案,这个例子似乎并没有令人窒息,只是留下了问题字符:

\n\n
line.replaceAll("(?Ui)([\\\\u0000-\\\\uffff])\\\\1{2,}", "$1")    \n\n// "" -> ""\n// "foo  foo" -> "foo  foo"\n// "foo aAa foo" -> "foo a foo"\n
Run Code Online (Sandbox Code Playgroud)\n