2013-02-18 31 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

相關問題