我在测试不同标点符号的Pattern.UNICODE_CHARACTER_CLASS标志的行为,注意到根据是否使用Pattern.UNICODE_CHARACTER_CLASS,严重重音字符(U+0060)`的匹配情况会有所不同.

例如,请参见以下代码:


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}个字符的类匹配时,但当我使用该标志时,它不匹配.有人能解释一下原因吗?

推荐答案

使用Pattern p = Pattern.compile("\\p{Punct}");时,\p{Punct}表示以下32个字符:

!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

参考:the Pattern class.

这32个字符对应于ASCII字符集字符0x210x7e,不包括字母和数字.它们还碰巧代表了我的标准美国键盘上的所有非字母和非数字符号(当然,您的键盘可能不同).

严重的口音(也被称为倒勾音)就在那个列表和我的键盘上.

这是一个"预定义字符类"的简单示例,并解释了m.matches()返回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个,我们发现一个表格显示了"兼容性属性名称的推荐分配".

对于我们的房产名称(punct),标准建议使用以下定义的字符:

\p{gc=Punctuation}

这里,"gc"代表"一般类别".Unicode字符被分配一个"general category"的值.在本例中,即Punctuation——也缩写为P,并进一步细分为各种子类别,例如Pc表示连接器,Pd表示破折号,等等.还有一个"其他标点符号"的总括Po.

在Unicode中,grave字符被分配到Symbol个一般类别,以及Modifier个子类别.你可以看到分配给Skhere的任务.

将其与ASCII感叹号等字符进行对比(这也是我们最初的\p{Punct}列表的一部分,如上所示).对于we can see,一般类别分配为Po.

这就解释了为什么当我们把Pattern.UNICODE_CHARACTER_CLASS面旗帜添加到原始图案中时,坟墓不再匹配.

它被分配到与我们在正则表达式中使用的标点符号类别不同的一般类别.


显而易见的下一个问题是why did the grave character not get included in the Unicode 100 general category?为什么改为Sk

对此,我没有一个好的答案——我肯定有"历史原因".然而,值得注意的是,这Sk个系列包括尖锐口音、塞迪利亚口音、迪亚瑞斯口音等等——以及(如前所述)我们的严肃口音.

所有这些都是变音符号——通常与基本字母结合使用来改变发音.所以这可能就是根本原因.

坟墓可能有点奇怪,因为它除了用作变音符号外,还有一个历史用法.

首先,询问坟墓如何成为原始ASCII字符集的一部分可能更为相关.维基百科backtick年版提供了一些相关背景信息.

Java相关问答推荐

SpringBootreact 式Web应用程序的Spring Cloud Configer服务器中的资源控制器损坏

如何修复PDF重建过程中的文本定位

Spring Data JPA慢慢地创建了太多非活动会话

如何让JavaFx应用程序识别依赖项?

使SLF4J在Android中登录到Logcat,在测试中登录到控制台(Gradle依赖问题)

在VS代码中,如何启用Java Main函数的&Q;Run|DEBUG&Q;代码?

使用正则表达式从字符串中提取多个值

Spring Boot&;Docker:无法执行目标org.springframework.boot:spring-boot-maven-plugin:3.2.0:build-image

在Spring Boot应用程序中,server.port=0的默认端口范围是多少?

Spring Framework6.1中引入的新RestClient是否有适合于测试的变体,就像RestTemplate和TestRestTemplate一样?

Android Studio模拟器没有互联网

在Oracle db中,当我们提供字符串而不是数字时,比较是如何工作的?

除0错误/抱歉我的句子是PT

组合连接以从两个表返回数据

泛型与泛型问题的完美解决方案?

在不使用instanceof或强制转换的情况下从父类变量调用子类方法

如何使用jooq更新记录?

获取所有可以处理Invent.ACTION_MEDIA_BUTTON Android 13 API33的Android包

Cucumber java-maven-示例表-未定义一步

SonarQube在合并升级到java17后对旧代码提出错误