w 是不是匹配 Unicode 标准中定义的所有字母数字字符?

Posted

技术标签:

【中文标题】\w 是不是匹配 Unicode 标准中定义的所有字母数字字符?【英文标题】:Does \w match all alphanumeric characters defined in the Unicode standard?\w 是否匹配 Unicode 标准中定义的所有字母数字字符? 【发布时间】:2011-07-30 03:53:54 【问题描述】:

Perl 的 \w 是否匹配 Unicode 标准中定义的所有字母数字字符?

例如,\w 会匹配所有(比如)中文和俄文字母数字字符吗?

我编写了一个简单的测试脚本(见下文),它表明 \w 确实与我测试的非 ASCII 字母数字字符“按预期”匹配。但测试显然远非详尽。

#!/usr/bin/perl                                                                                                                                                                                                  

use utf8;

binmode(STDOUT, ':utf8');

my @ok;
$ok[0] = "abcdefghijklmnopqrstuvwxyz";
$ok[1] = "éèëáàåäöčśžłíżńęøáýąóæšćôı";
$ok[2] = "şźüęłâi̇ółńśłŕíáυσνχατςęςη";
$ok[3] = "τσιαιγολοχβςανنيرحبالтераб";
$ok[4] = "иневоаслкłјиневоцедањеволс";
$ok[5] = "рглсывызтоμςόκιναςόγο";

foreach my $ok (@ok) 
    die unless ($ok =~ /^\w+$/);

【问题讨论】:

【参考方案1】:

perldoc perlunicode 说

正则表达式中的字符类匹配字符而不是字节,并匹配 Unicode 属性数据库中指定的字符属性。例如,\w 可用于匹配日语表意文字。

所以看起来你的问题的答案是“是”。

但是,您可能希望使用\p 构造直接访问特定的Unicode character properties。您可能可以使用\pL(或更短的\pL)来表示字母,使用\pN 来表示数字,这样您就会更有信心得到您想要的。

【讨论】:

请注意,这取决于字符语义;如果您的字符串来自使用字节语义的源,\w 将仅匹配 ASCII 单词字符。 有关 Unicode 字符语义的更多详细信息,请参阅The Unicode Bug in perlunicode。与\w 等效的保险箱是使用\pAlnum @cjm, \w 实际上是\pWord\pAlnum 缺少下划线。 @Anomie:还有语言环境问题。 @CanSpice:“字母”!=“字母”。您绝不能使用\pL 来表示\pAlphabetic。他们真的很不一样。从 Unicode 6 开始,有 1006 个代码点具有 Alphabetic 属性但缺少 GC=Letter 属性。【参考方案2】:

是和不是。

如果你想要所有字母数字,你想要[\pAlphabetic\pGC=Number]\w 包含更多和更少。它特别排除了任何\pN 既不是\pNd 也不是\pNl,如上标、下标和分数。这些是\pGC=Other_Number,不包含在\w 中。

因为与大多数正则表达式系统不同,Perl 遵守 Requirement 1.2a, “Compatibility Properties” 来自 UTS #18 on Unicode Regular Expressions,然后 假设您有 Unicode 字符串, 正则表达式中的 \w 匹配任何单个代码点以下四个属性:

    \pGC=Alphabetic \pGC=Mark \pGC=Connector_Punctuation \pGC=Decimal_Number

上面的数字 4 可以用以下任何一种方式表示,它们都被认为是等价的:

\pDigit \pGeneral_Category=Decimal_Number \pGC=Decimal_Number \pDecimal_Number \pNd \pNumeric_Type=Decimal \pNt=De

请注意,\pDigit\pNumeric_Type=Digit 不同。例如,代码点 B2,SUPERSCRIPT TWO,只有 \pNumeric_Type=Digit 属性,而不是普通的 \pDigit。那是因为它被认为是\pOther_Number\pNo。但是,它确实具有您想象的 \pNumeric_Value=2 属性。

确实是上面的第 1 点,\pAlphabetic,这给人们带来了最大的麻烦。那是因为他们经常错误地认为它与\pLetter (\pL) 相同,但事实并非如此。

Alphabetics 包括的远不止这些,都是因为 \pOther_Alphabetic 属性,因为这反过来 包括一些但不是所有\pGC=Mark、所有\pLowercase(与\pGC=Ll不同,因为它添加了\pOther_Lowercase)和所有\pUppercase(不同为\pGC=Lu,因为它添加了\pOther_Uppercase)。

这就是它如何像罗马数字一样引入\pGC=Letter_Number 所有带圆圈的字母,类型为\pOther_Symbol\pBlock=Enclosed_Alphanumerics

您不高兴我们使用\w 吗? :)

【讨论】:

“其他字母”包含 GC=Mark 有什么意义? “小写”与 GC=Ll 不一样,这有什么意义?莫名其妙。【参考方案3】:

特别是\w 也匹配下划线字符。

#!/usr/bin/perl -w
$name = 'Arun_Kumar';
($name =~ /\w+/)? print "Underscore is a word character\n": print "No underscores\n";
$ underscore.pl 

下划线是单词字符。

【讨论】:

以上是关于w 是不是匹配 Unicode 标准中定义的所有字母数字字符?的主要内容,如果未能解决你的问题,请参考以下文章

Python 标准库模块 - re

计算机中的编码和字符集:理解二进制字节流和常见编码方案

如何判断一个字符串是不是是unicode编码?

unicode编码详解,一看就懂

正则表达式如何匹配汉字?

Unicode ASCII UTF-8 GBK关系