使用 UNICODE_CHARACTER_CLASS 标志时不同的 Java 正则表达式匹配行为
Different Java Regex matching behavior when using UNICODE_CHARACTER_CLASS flag
我正在针对不同的标点符号测试 Pattern.UNICODE_CHARACTER_CLASS
标志的行为,并注意到重音字符 (U+0060) `
的匹配会根据是否 Pattern.UNICODE_CHARACTER_CLASS
被使用。
例如,看下面的代码:
public class GraceAccentTest {
public static void main(String args[]) {
Pattern p = Pattern.compile("\p{Punct}");
Matcher m = p.matcher("`");
System.out.println(m.matches()); // returns true
Pattern p1 = Pattern.compile("\p{Punct}", Pattern.UNICODE_CHARACTER_CLASS);
Matcher m1 = p1.matcher("`");
System.out.println(m1.matches()); // returns false
}
}
当我不使用 Pattern.UNICODE_CHARACTER_CLASS
标记重音字符与 \p{Punct}
字符匹配时 class 但是当我使用该标记时它不匹配。有人可以解释一下这样做的原因吗?
正在阅读 UNICODE_CHARACTER_CLASS
的文档
When this flag is specified then the (US-ASCII only) Predefined
character classes and POSIX character classes are in conformance with
Unicode Technical Standard #18: Unicode Regular Expression Annex C:
Compatibility Properties.
所以这就是说只使用 US-ASCII。因此,如果您检查字符 标点符号 的 table,您将检查是否有很多缺失的字符。
表格:
https://www.fileformat.info/info/unicode/category/Po/list.htm
https://www.gaijin.at/en/infos/unicode-character-table-punctuation
当你使用Pattern p = Pattern.compile("\p{Punct}");
时,那么\p{Punct}
指的是下面的32个字符:
!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
这32个字符对应ASCII字符集字符0x21
到0x7e
,不包括字母和数字。它们也恰好代表了我的标准 U.S 上的所有 non-letter 和 non-digit 符号。键盘(当然,您的键盘可能不同)。
重音符(也称为反引号)在该列表和我的键盘上。
这是一个“预定义字符 class”的简单示例 - 并解释了为什么您的 m.matches()
returns true
.
当您添加 Pattern.UNICODE_CHARACTER_CLASS
标志时,事情会变得更加复杂。
正如该标志的 documentation 所解释的,它:
Enables the Unicode version of Predefined character classes and POSIX character classes.
和:
When this flag is specified then the (US-ASCII only) Predefined character classes and POSIX character classes are in conformance with Unicode Technical Standard #18: Unicode Regular Expressions Annex C: Compatibility Properties.
查看上面提到的 Annex C,我们发现 table 显示“为兼容性推荐的分配 属性 名称”。
对于我们的 属性 名称 (punct
),标准建议是使用这样定义的字符:
\p{gc=Punctuation}
这里,“gc”代表“一般类别”。 Unicode 字符被分配了一个 "general category" 值。在这种情况下,即 Punctuation
- 也缩写为 P
并进一步分解为各种 sub-categories,例如 Pc
用于连接器,Pd
用于破折号,以及很快。 “其他标点符号”还有一个catch-all Po
。
坟墓字符分配给 Unicode 中的 Symbol
通用类别 - 以及 Modifier
子类别。您可以看到分配给 Sk
here.
将它与诸如 ASCII 感叹号之类的字符(也是我们原始 \p{Punct}
列表的一部分,如上所示)进行对比。对于那个we can see,一般类别分配是Po
。
这解释了为什么当我们将 Pattern.UNICODE_CHARACTER_CLASS
标志添加到我们的原始模式时坟墓不再匹配。
它被分配到与我们在正则表达式中使用的标点符号类别不同的一般类别。
下一个明显的问题是 为什么坟墓字符没有包含在 Unicode Po
通用类别中? 为什么它在 Sk
中?
对此我没有很好的答案 - 我敢肯定有“历史原因”。但是,值得注意的是,Sk
类别包括诸如尖音符、变音符、分音符等字符,以及(如前所述)我们的重音符。
所有这些都是变音符号 - 通常与基本字母结合使用以改变发音。所以也许这就是根本原因。
坟墓有点奇怪,也许是因为它除了用作变音符号外还有历史用途。
首先问坟墓如何成为原始 ASCII 字符集的一部分可能更相关。 backtick.
的维基百科页面提供了一些关于此的背景信息
我正在针对不同的标点符号测试 Pattern.UNICODE_CHARACTER_CLASS
标志的行为,并注意到重音字符 (U+0060) `
的匹配会根据是否 Pattern.UNICODE_CHARACTER_CLASS
被使用。
例如,看下面的代码:
public class GraceAccentTest {
public static void main(String args[]) {
Pattern p = Pattern.compile("\p{Punct}");
Matcher m = p.matcher("`");
System.out.println(m.matches()); // returns true
Pattern p1 = Pattern.compile("\p{Punct}", Pattern.UNICODE_CHARACTER_CLASS);
Matcher m1 = p1.matcher("`");
System.out.println(m1.matches()); // returns false
}
}
当我不使用 Pattern.UNICODE_CHARACTER_CLASS
标记重音字符与 \p{Punct}
字符匹配时 class 但是当我使用该标记时它不匹配。有人可以解释一下这样做的原因吗?
正在阅读 UNICODE_CHARACTER_CLASS
When this flag is specified then the (US-ASCII only) Predefined character classes and POSIX character classes are in conformance with Unicode Technical Standard #18: Unicode Regular Expression Annex C: Compatibility Properties.
所以这就是说只使用 US-ASCII。因此,如果您检查字符 标点符号 的 table,您将检查是否有很多缺失的字符。
表格:
https://www.fileformat.info/info/unicode/category/Po/list.htm
https://www.gaijin.at/en/infos/unicode-character-table-punctuation
当你使用Pattern p = Pattern.compile("\p{Punct}");
时,那么\p{Punct}
指的是下面的32个字符:
!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
这32个字符对应ASCII字符集字符0x21
到0x7e
,不包括字母和数字。它们也恰好代表了我的标准 U.S 上的所有 non-letter 和 non-digit 符号。键盘(当然,您的键盘可能不同)。
重音符(也称为反引号)在该列表和我的键盘上。
这是一个“预定义字符 class”的简单示例 - 并解释了为什么您的 m.matches()
returns true
.
当您添加 Pattern.UNICODE_CHARACTER_CLASS
标志时,事情会变得更加复杂。
正如该标志的 documentation 所解释的,它:
Enables the Unicode version of Predefined character classes and POSIX character classes.
和:
When this flag is specified then the (US-ASCII only) Predefined character classes and POSIX character classes are in conformance with Unicode Technical Standard #18: Unicode Regular Expressions Annex C: Compatibility Properties.
查看上面提到的 Annex C,我们发现 table 显示“为兼容性推荐的分配 属性 名称”。
对于我们的 属性 名称 (punct
),标准建议是使用这样定义的字符:
\p{gc=Punctuation}
这里,“gc”代表“一般类别”。 Unicode 字符被分配了一个 "general category" 值。在这种情况下,即 Punctuation
- 也缩写为 P
并进一步分解为各种 sub-categories,例如 Pc
用于连接器,Pd
用于破折号,以及很快。 “其他标点符号”还有一个catch-all Po
。
坟墓字符分配给 Unicode 中的 Symbol
通用类别 - 以及 Modifier
子类别。您可以看到分配给 Sk
here.
将它与诸如 ASCII 感叹号之类的字符(也是我们原始 \p{Punct}
列表的一部分,如上所示)进行对比。对于那个we can see,一般类别分配是Po
。
这解释了为什么当我们将 Pattern.UNICODE_CHARACTER_CLASS
标志添加到我们的原始模式时坟墓不再匹配。
它被分配到与我们在正则表达式中使用的标点符号类别不同的一般类别。
下一个明显的问题是 为什么坟墓字符没有包含在 Unicode Po
通用类别中? 为什么它在 Sk
中?
对此我没有很好的答案 - 我敢肯定有“历史原因”。但是,值得注意的是,Sk
类别包括诸如尖音符、变音符、分音符等字符,以及(如前所述)我们的重音符。
所有这些都是变音符号 - 通常与基本字母结合使用以改变发音。所以也许这就是根本原因。
坟墓有点奇怪,也许是因为它除了用作变音符号外还有历史用途。
首先问坟墓如何成为原始 ASCII 字符集的一部分可能更相关。 backtick.
的维基百科页面提供了一些关于此的背景信息