2013-02-18 71 views
7

从我以前的问题Why under locale-pragma word characters do not match?How to change nested quotes我了解到,在处理UTF-8数据时,您不能信任\w作为word-char,并且您必须使用Unicode字符属性\p{Word}。现在我处于一种情况,我发现零宽度的文字边界\b也不支持UTF-8(启用区域设置),但我在Unicode字符属性中找不到任何等效字符。我想我可以自己构建它,如:(?<=\P{Word})(\p{Word}+)(?=\P{Word}),它应该相当于\b(\w+)\b如何在使用unicode字符属性时模拟字边界?

在下面的测试脚本中,我有两个数组来测试两个不同的正则表达式。当区域设置未启用时,基于\b的第一项工作正常。为了使它也适用于语言环境,我编写了另一个模拟边界(?=\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; 
} 
+4

首先,是错误的:'\ w'和'\ p {word}'在定义上是相同的。但第二,***请请,请不要使用'use locale'杂注。它是破碎的,不可靠的,不可预知的,并且在对接中发生了皇家的痛苦 - 正如你似乎已经发现的那样。你应该使用'Unicode :: Collat​​e :: Locale'模块。你可能不应该使用'use utf8:all',而是做你想要的具体事情。 – tchrist 2013-02-23 01:40:15

+0

@tchrist:'\ w'和'\ p {Word}'可能被定义为相同的,但它们在'use locale'下的行为不同。当然,当我有其他方式时,我不会使用区域设置。 '使用utf8 :: all'可以很好地满足我的需求,而且它是显示我的意图的干净方式。如果utf8 :: all中有一些缺失,也许你可以将它指向作者? – 2013-02-23 12:05:38

+0

你不知道'utf8:all'做了什么或不做什么,这正是问题所在 - 我注意到一个问题,不能通过添加东西来解决。你得到了什么级别的'utf8'警告?没有或警告或致命?那么这三种亚型,nonchar和替代品以及non_unicode呢?这些东西应该在代码中明确,以便人们可以看到它们是什么。然后在输入和NFC上输出到NFD的问题;它是这样做的吗? – tchrist 2013-02-23 14:59:57

回答

7

由于后\b的位置或者是一些标点符号或"字符(为了安全起见,请仔细检查\p{Word}不符合任何人的),它落入的情况下\b\W。因此,我们可以效仿\b有:

(?<=\p{Word}) 

我不熟悉Perl,但是从what I tested here,似乎当编码设置为UTF-8 \w(和\b)也很好地工作。

$sentence =~ s/ 
    "(
    [\w\.]+? 
    .*?\b[\.,?!»]*? 
)" 
    /«$1»/xg; 

如果移动学习Perl 5.14及以上的,可以设置的字符集与u标志为Unicode。


你可以使用这个总体战略,构建对应于字符类的边界。 (如\b字边界定义基于\w的定义)。

C成为角色等级。我们想定义一个基于字符类C.边界

下建设将效仿边界在面前的时候,你知道当前字符属于C字符类(相当于(\b\w)):

(?<!C)C 

或后方(相当于\w\b):

C(?!C) 

为什么负环视?因为积极的环视(与互补角色类别)也会断言前后必须有一个角色(在前/后至少1处声明宽度)。消极的环视将允许字符串的开始/结束,而不用写繁琐的正则表达式。


对于\B\w仿真:

(?<=C)C 

,同样\w\B

C(?=C) 

\B\b正好相反,因此,我们就可以翻转正/负环视模拟效果。这也是有道理的 - 只有当前后角色更多时才能形成非边界。


其他仿真(让c是补体字符类的C):

  • \b\W(?<=C)c
  • \W\bc(?=C)
  • \B\W(?<!C)c
  • \W\Bc(?!C)

对于独立边界的仿真(相当于\b):

(?:(?<!C)(?=C)|(?<=C)(?!C)) 

和独立非边界(相当于\B):

(?:(?<!C)(?!C)|(?<=C)(?=C)) 
+0

将'\ b'改成'(?!\ p {Word})'并没有改变结果。有了测试用例''“äöõ”äõüü“'''我被抓住了,而不是'äöõ'äõü'仍然'äöõ',就像我的正面看法一样。你能指出什么出错? – 2013-02-18 21:13:40

+0

@wk:我不确定你想要做什么(括号匹配?)。问题不在于字边界(及其仿真),而在于你正在使用的正则表达式。 – nhahtdh 2013-02-18 23:04:21

+0

我的目标是改变双引号“ “äöõ”'变成花哨的语录'«äöõ»'。在嵌套引号中,它应该替换不匹配的对,但是第一个和第三个引号,然后是第二个和第四个。我的第一个正则表达式的工作原理和我预期的一样,当我不启用语言环境。因此,在第二个正则表达式中,只有改变我将''b'改成'(?= \ P {Word})'并且在你的建议变为负向前瞻'(?!\ p {Word})' 。这些lookaheads不会像'\ b'那样工作,我也不明白为什么? – 2013-02-19 08:38:23

5

您应该使用负lookarounds:

(?<!\p{Word})(\p{Word}+)(?!\p{Word}) 

正lookarounds在开始或结束的字符串失败,因为他们需要一个非单词字符存在。在这两种情况下,负面看法都起作用。

+0

是不是就像写作'\ b(\ w +)\ b'? – tchrist 2013-02-23 01:39:12

+0

他把事情搞糟了/破坏了'use locale';请参阅[本答案](http://stackoverflow.com/a/15036072/471272)了解如何以正确的方式在Perl中执行区域设置。这样,你也可以使用普通的正则表达式。 – tchrist 2013-02-23 05:27:18

相关问题