w.k*_*w.k 8 regex unicode perl locale utf-8
从我之前的问题为什么在locale-pragma字符下不匹配?以及如何更改嵌套引号我了解到,在处理UTF-8数据时,您不能信任\wword-char,必须使用Unicode字符属性\p{Word}.现在,我发现零宽度字边界\b也不适用于UTF-8(启用了区域设置),但我没有在Unicode字符属性中找到任何等效字符.我以为我可以自己构建它:(?<=\P{Word})(\p{Word}+)(?=\P{Word})它应该等同于\b(\w+)\b.
在下面的测试脚本中,我有两个数组来测试两个不同的正则表达式.\b当未启用语言环境时,第一个基于工作正常.为了使它也能与locales一起工作,我编写了另一个带有模拟边界的版本,(?=\P{Word})但是它没有按照我的预期工作(我也在脚本中显示了预期的结果).
你是否看到了什么错误以及如何使用ASCII(或没有语言环境)来模拟正则表达式的工作?
#!/usr/bin/perl
use 5.010;
use utf8::all;
use locale; # et_EE.UTF-8 in my case
$| = 1;
my @test_boundary = ( # EXPECTED RESULT:
'"abc def"', # '«abc def»'
'"abc "d e f" ghi"', # '«abc «d e f» ghi»'
'"abc "d e f""', # '«abc «d e f»»'
'"abc "d e f"', # '«abc "d e f»'
'"abc "d" "e" f"', # '«abc «d» «e» f»'
# below won't work with \b when locale enabled
'"100 ?????iï"', # '«100 ?????iï»'
'"äöõ "ä õ ü" ï"', # '«äöõ «ä õ ü» ï»'
'"äöõ "ä õ ü""', # '«äöõ «ä õ ü»»'
'"äöõ "ä õ ü"', # '«äöõ «ä õ ü»'
'"äöõ "ä" "õ" ï"', # '«äöõ «ä» «õ» ï»'
);
my @test_emulate = ( # EXPECTED RESULT:
'"100 ?????iï"', # '«100 ?????iï»'
'"äöõ "ä õ ü" ï"', # '«äöõ «ä õ ü» ï»'
'"äöõ "ä õ ü""', # '«äöõ «ä õ ü»»'
'"äöõ "ä õ ü"', # '«äöõ "ä õ ü»'
'"äöõ "ä" "õ" ï"', # '«äöõ «ä» «õ» ï»'
);
say "BOUNDARY";
for my $sentence ( @test_boundary ) {
my $quote_count = ( $sentence =~ tr/"/"/ );
for ( my $i = 0 ; $i <= $quote_count ; $i += 2 ) {
$sentence =~ s/
"( # first qoute, start capture
[\p{Word}\.]+? # suva word-char
.*?\b[\.,?!»]*? # any char followed boundary + opt. punctuation
)" # stop capture, ending quote
/«$1»/xg; # change to fancy
}
say $sentence;
}
say "EMULATE";
for my $sentence ( @test_emulate ) {
my $quote_count = ( $sentence =~ tr/"/"/ );
for ( my $i = 0 ; $i <= $quote_count ; $i += 2 ) {
$sentence =~ s/
"( # first qoute, start capture
[\p{Word}\.]+? # at least one word-char or point
.*?(?=\P{Word}) # any char followed boundary
[\.,?!»]*? # optional punctuation
)" # stop capture, ending quote
/«$1»/gx; # change to fancy
}
say $sentence;
}
Run Code Online (Sandbox Code Playgroud)
因为位置之后的字符\b要么是一些标点符号,或者"(为了安全,请仔细检查它们\p{Word}中的任何一个都不匹配),它就属于这种情况\b\W.因此,我们可以效仿\b:
(?<=\p{Word})
Run Code Online (Sandbox Code Playgroud)
我不熟悉Perl,但是根据我在这里测试的内容,当编码设置为UTF-8时,似乎\w(和\b)也很好用.
$sentence =~ s/
"(
[\w\.]+?
.*?\b[\.,?!»]*?
)"
/«$1»/xg;
Run Code Online (Sandbox Code Playgroud)
如果向上移动到Perl 5.14及更高版本,则可以将字符集设置为带有u标志的Unicode .
您可以使用此一般策略来构造与字符类对应的边界.(就像\b字边界定义基于定义一样\w).
让我们C成为角色类.我们想要定义一个基于字符类C的边界.
当您知道当前字符属于C字符类(相当于(\b\w))时,下面的构造将模拟前面的边界:
(?<!C)C
Run Code Online (Sandbox Code Playgroud)
或落后(相当于\w\b):
C(?!C)
Run Code Online (Sandbox Code Playgroud)
为什么负面的环顾?因为正向环视(带有互补字符类)也会断言前面/后面必须有一个字符(断言前后宽度至少为1).负面的环顾将允许字符串开头/结尾的情况,而无需编写繁琐的正则表达式.
用于\B\w仿真:
(?<=C)C
Run Code Online (Sandbox Code Playgroud)
同样地\w\B:
C(?=C)
Run Code Online (Sandbox Code Playgroud)
\B是的正好相反\b,因此,我们就可以翻转正/负环视模拟效果.这也是有道理的 - 只有在前后有更多角色时才能形成非边界.
其他仿真(让我们c的补充字符类C):
\b\W: (?<=C)c\W\b: c(?=C)\B\W: (?<!C)c\W\B: c(?!C)对于独立边界的仿真(相当于\b):
(?:(?<!C)(?=C)|(?<=C)(?!C))
Run Code Online (Sandbox Code Playgroud)
独立的非边界(相当于\B):
(?:(?<!C)(?!C)|(?<=C)(?=C))
Run Code Online (Sandbox Code Playgroud)
你应该使用负面的外观:
(?<!\p{Word})(\p{Word}+)(?!\p{Word})
Run Code Online (Sandbox Code Playgroud)
积极的外观在字符串的开头或结尾处失败,因为它们需要存在非单词字符.在两种情况下,负面的外观都有效.