如何在没有 Java 7 的情况下匹配正则表达式字符串中大于 \uFFFF 的 Unicode 代码点?
How to match Unicode code points greater then \uFFFF in regex string without Java 7?
这是我的正则表达式:
(?x)(?:[A-Za-z:_] | [\xC0-\xD6]| [\xD8-\xF6] | [\xF8-\x{2FF}] | [\x{370}-\x{37D}] | [\x{37F}-\x{1FFF}] | [\x{200C}-\x{200D}] | [\x{2070}-\x{218F}] | [\x{2C00}-\x{2FEF}] | [\x{3001}-\x{D7FF}] | [\x{F900}-\x{FDCF}] | [\x{FDF0}-\x{FFFD}] | [\x{10000}-\x{EFFFF}])
Java 拒绝编译它。它引发了这个异常:
java.util.regex.PatternSyntaxException: Illegal hexadecimal escape sequence near index 68
^/((?:(?x)(?:(?x)(?:[A-Za-z:_] | [\xC0-\xD6]| [\xD8-\xF6] | [\xF8-\x{2FF}]...
^
怎么了?
Java 6
BNF 图仅适用于 Java 7 及以上。对于 Java 6,Java RegExp,\x
期望后面正好有两个十六进制数字,不多也不少。如果需要匹配 Unicode,请使用 \u
后跟四个十六进制数字。
在你的情况下,那将是 ... [\xF8-\u02FF] ...
,等等
原因是 Java RegExp 不使用模式作为字符的占位符。相反,Java 编译器创建 Unicode 代码点并将它们收集在 Unicode 字符串中,然后将其传递给 RegExp 工具。因此,RegExp 工具永远不会看到 \x
或 \u
(这也是您收到此注释的编译错误的原因:// See c:\User\...
)
对于 Unicode 代码点 > 0xFFFF
,您需要使用 surrogate pairs。您可以使用 Character.toChars()
创建它们。 Character.toChars(0x10000)
创建两个 char
代表 \x{10000}
.
\x{<i>h...h</i>}
表示法,带有大括号和非固定数目的十六进制数字,直到 Java 才添加到 java.util.regex.Pattern
7:
(在页面中搜索\x{
。只有后者link有。)
相反,您需要使用 \u<i>hhhh</i>
表示法:[\xF8-\u02FF]
.
然而,\u<i>hhhh</i>
表示一个UTF-16编码单元,即Javachar
,而不是完整的 Unicode 代码点,因此正则表达式的最后一部分 — [\x{10000}-\x{EFFFF}]
— 翻译起来比较棘手。我认为 Java 6 正则表达式完全在代码单元上运行,因此您实际上需要将其视为两个代码单元:[\uD800-\uDB7F][\uDC00-\uDFFF]
(其中 [\uD800-\uDB7F]
是 "high" 代理项,而 [\uDC00-\uDFFF]
是 "low" 代理项的整个范围;幸运的是 U+EFFFF 恰好位于具有相同高代理项的代码点范围的末尾,否则你会需要做一些更复杂的事情)。 (免责声明: 未经测试。)
以下是我解决问题的方法:
String regex = "(?x)" +
"(?:" +
"[A-Za-z:_] |" +
"[\xC0-\xD6] |" +
"[\xD8-\xF6] |" +
"[\xF8-\u02FF] |" +
"[\u0370-\u037D] |" +
"[\u037F-\u1FFF] |" +
"[\u200C-\u200D] |" +
"[\u2070-\u218F] |" +
"[\u2C00-\u2FEF] |" +
"[\u3001-\uD7FF] |" +
"[\uF900-\uFDCF] |" +
"[\uFDF0-\uFFFD] |" +
"[\ud800\udc00-\udb7f\udfff]" +
)";
感谢大家的帮助。
参考:
这是我的正则表达式:
(?x)(?:[A-Za-z:_] | [\xC0-\xD6]| [\xD8-\xF6] | [\xF8-\x{2FF}] | [\x{370}-\x{37D}] | [\x{37F}-\x{1FFF}] | [\x{200C}-\x{200D}] | [\x{2070}-\x{218F}] | [\x{2C00}-\x{2FEF}] | [\x{3001}-\x{D7FF}] | [\x{F900}-\x{FDCF}] | [\x{FDF0}-\x{FFFD}] | [\x{10000}-\x{EFFFF}])
Java 拒绝编译它。它引发了这个异常:
java.util.regex.PatternSyntaxException: Illegal hexadecimal escape sequence near index 68
^/((?:(?x)(?:(?x)(?:[A-Za-z:_] | [\xC0-\xD6]| [\xD8-\xF6] | [\xF8-\x{2FF}]...
^
怎么了?
Java 6
BNF 图仅适用于 Java 7 及以上。对于 Java 6,Java RegExp,\x
期望后面正好有两个十六进制数字,不多也不少。如果需要匹配 Unicode,请使用 \u
后跟四个十六进制数字。
在你的情况下,那将是 ... [\xF8-\u02FF] ...
,等等
原因是 Java RegExp 不使用模式作为字符的占位符。相反,Java 编译器创建 Unicode 代码点并将它们收集在 Unicode 字符串中,然后将其传递给 RegExp 工具。因此,RegExp 工具永远不会看到 \x
或 \u
(这也是您收到此注释的编译错误的原因:// See c:\User\...
)
对于 Unicode 代码点 > 0xFFFF
,您需要使用 surrogate pairs。您可以使用 Character.toChars()
创建它们。 Character.toChars(0x10000)
创建两个 char
代表 \x{10000}
.
\x{<i>h...h</i>}
表示法,带有大括号和非固定数目的十六进制数字,直到 Java 才添加到 java.util.regex.Pattern
7:
(在页面中搜索\x{
。只有后者link有。)
相反,您需要使用 \u<i>hhhh</i>
表示法:[\xF8-\u02FF]
.
然而,\u<i>hhhh</i>
表示一个UTF-16编码单元,即Javachar
,而不是完整的 Unicode 代码点,因此正则表达式的最后一部分 — [\x{10000}-\x{EFFFF}]
— 翻译起来比较棘手。我认为 Java 6 正则表达式完全在代码单元上运行,因此您实际上需要将其视为两个代码单元:[\uD800-\uDB7F][\uDC00-\uDFFF]
(其中 [\uD800-\uDB7F]
是 "high" 代理项,而 [\uDC00-\uDFFF]
是 "low" 代理项的整个范围;幸运的是 U+EFFFF 恰好位于具有相同高代理项的代码点范围的末尾,否则你会需要做一些更复杂的事情)。 (免责声明: 未经测试。)
以下是我解决问题的方法:
String regex = "(?x)" +
"(?:" +
"[A-Za-z:_] |" +
"[\xC0-\xD6] |" +
"[\xD8-\xF6] |" +
"[\xF8-\u02FF] |" +
"[\u0370-\u037D] |" +
"[\u037F-\u1FFF] |" +
"[\u200C-\u200D] |" +
"[\u2070-\u218F] |" +
"[\u2C00-\u2FEF] |" +
"[\u3001-\uD7FF] |" +
"[\uF900-\uFDCF] |" +
"[\uFDF0-\uFFFD] |" +
"[\ud800\udc00-\udb7f\udfff]" +
)";
感谢大家的帮助。
参考: