2013-10-16 32 views
6

我正在嘗試在perl webapp(使用perl v5.10.1)中查找名稱大寫的解決方案。我原本以爲要使用Lingua :: EN :: NameCase,但是我看到一些重音字符的問題。大寫包含重音字符的字符串

我需要能夠處理來自各種歐洲語言(愛爾蘭語,法語,德語)的重音字符。

我在網上看到一些跡象表明Lingua :: EN :: NameCase應該適用於我的用例。例如,在此頁perlmonks:http://www.perlmonks.org/?node_id=889135

這裏是上面的鏈接根據我的測試代碼:

#!/usr/bin/perl 

use strict; 
use warnings; 
use Lingua::EN::NameCase; 
use locale; 
use POSIX qw(locale_h); 

my $locale = 'en_FR.utf8'; 

setlocale(LC_CTYPE, $locale); 

binmode DATA, ':encoding(UTF-8)'; 
binmode STDOUT, ':encoding(UTF-8)'; 

while (my $original_name = <DATA>) { 
    chomp $original_name; 
    my $normalized_name = nc($original_name); 
    printf "%30s L::EN::NC %30s UCFIRST %30s\n", $original_name, $normalized_name, xlc($original_name); 
} 

sub xlc { 
    my $str = shift; 
    $_ = lc($str); 
    return join q{} => (map { ucfirst(lc($_)) } ($str =~ m/(\W+|\w+)/g)); 
}; 

__DATA__ 
ÉTIENNE DE LA BOÉTIE 
ÉMILIE DU CHÂTELET 
HÉLÈNE CIXOUS 
Seán Ó Hannracháín 
Máire Ó hÓgartaigh 

主要生產以下輸出。 L :: EN :: NC和自定義ucfirst(lc())解決方案都會產生不正確的結果(請注意每個重音字符後面的大寫字母)。這似乎是因爲perl正則表達式匹配每個重音字符之前/之後的「單詞邊界」。我希望字邊界只能匹配空格字符和非空格字符。

有人可以提出一個解決方案嗎?

謝謝,

Brian。

ÉTIENNE DE LA BOÉTIE L::EN::NC   éTienne de la BoéTie UCFIRST   ÉTienne De La BoÉTie 
    ÉMILIE DU CHÂTELET L::EN::NC    éMilie du ChâTelet UCFIRST    ÉMilie Du ChÂTelet 
     HÉLÈNE CIXOUS L::EN::NC     HéLèNe Cixous UCFIRST     HÉLÈNe Cixous 
    Seán Ó Hannracháín L::EN::NC    SeáN ó HannracháíN UCFIRST    SeÁN ó HannrachÁíN 
    Máire Ó hÓgartaigh L::EN::NC    MáIre ó HóGartaigh UCFIRST    MÁIre ó HÓGartaigh 
+3

參見[大寫重音字符在Perl(http://stackoverflow.com/questions/13261522/uppercase-accented-characters-in-perl) – hwnd

+0

該鏈接發佈的hwnd很有趣,但是'$ original_name'上的utf8標誌*被設置爲*:所有內容都被正確解碼。 – amon

+0

確實。我沒有大寫字母的問題。 uc()和lc()似乎對我發送給它們的任何字符串都很好。問題在於L :: EN :: NC似乎無法正確識別單詞的開頭,以便將該單詞的首字母大寫。來自L :: EN :: NC的相關正則表達式是使用'\ b'標識字邊界的'{\ b(\ w)} {\ u $ 1} gox;'。對我來說'\ b'似乎可以識別重音字符和非重音字符之間的任何變化作爲字邊界,這對我來說似乎是錯誤的。 –

回答

0

如果你的數據是UTF8,你應該把它解碼Perl的內部編碼:

utf8::decode($original_name); 
    my $normalized_name = nc($original_name); 
    printf "%30s L::EN::NC %30s UCFIRST %30s\n", $original_name, $normalized_name, xlc($original_name); 
+0

謝謝博格丹。我的數據確實是UTF8 - utf8 :: is_utf8($ original_name)返回true。但是utf8 :: decode()不會給我所需的輸出。它確實改變了輸出。因此,在我的原始示例中,不是L :: EN :: NC給出「éTiennede laBoéTie」,它現在給出了「ÉTiennede laBoÉTie」。所以大寫字母已經改變了,但我仍然有一些虛假的資本。 –

1

Perl 5.10的是舊的;如果可以的話,你應該更新它。

接下來,您會發現我用於類似情況的版本。 (在perl 5.14.2中測試)

#!/usr/bin/perl 

use strict; 
use warnings; 
use utf8::all; 

while (<DATA>) { chomp; 
    printf "%30s ==> %30s\n", $_, xlc($_); 
} 

sub xlc { my $str = shift; 
    $str =~ s/(\w+)/ucfirst(lc($1))/ge; 
    $str =~ s/(L[ea]s? 
       | Von 
       | D[aeou]s? 
       )\b 
       /lc($1)/xge; 
    return $str; 
}; 

__DATA__ 
ÉTIENNE DE LA BOÉTIE 
ÉMILIE DU CHÂTELET 
HÉLÈNE CIXOUS 
Seán Ó Hannracháín 
Máire Ó hÓgartaigh 
+0

剛注意到我們幾乎給出了相同的答案。但你是第一位的。所以這裏是我的upvote :) – Pierre

0

好吧,我剛剛得到你的腳本工作。下面是我得到的輸出:

 ÉTIENNE DE LA BOÉTIE L::EN::NC   Étienne de la Boétie UCFIRST   Étienne De La Boétie 
     ÉMILIE DU CHÂTELET L::EN::NC    Émilie du Châtelet UCFIRST    Émilie Du Châtelet 
      HÉLÈNE CIXOUS L::EN::NC     Hélène Cixous UCFIRST     Hélène Cixous 
     Seán Ó Hannracháín L::EN::NC    Seán Ó Hannracháín UCFIRST    Seán Ó Hannracháín 
     Máire Ó hÓgartaigh L::EN::NC    Máire Ó Hógartaigh UCFIRST    Máire Ó Hógartaigh 

我不得不改變兩兩件事:

  1. 我註釋掉binmode調用,因爲他們沒有與任何編碼我的系統上使用emacs的我的需要。你的旅費可能會改變。如果您弄錯了,您會看到有關未映射到Unicode或寬字符的字符的警告。

  2. 我改變了本地。你告訴它在法國使用講英語的語言環境。我不確定這是一個有效的區域設置。我選擇了一個實際使用重音字符的地方。

不幸的是,區域名稱不規範,但下面的區域設置爲我工作:

my $locale = 'fr_FR.utf-8'; 

特別是,它並沒有不帶連字符的工作。

0

其實你只需要utf8編譯指示。

use utf8; 
binmode STDOUT, ':utf8'; 

while (my $name = <DATA>) { 
    $name =~ s/(\w+)/ucfirst lc $1/eg; 
    print $name; 
} 

__DATA__ 
ÉTIENNE DE LA BOÉTIE 
ÉMILIE DU CHÂTELET 
HÉLÈNE CIXOUS 
Seán Ó Hannracháín 
Máire Ó hÓgartaigh 

我得到:

Étienne De La Boétie 
Émilie Du Châtelet 
Hélène Cixous 
Seán Ó Hannracháín 
Máire Ó Hógartaigh