大写包含重音字符的字符串

时间:2013-10-16 06:43:21

标签: regex perl unicode capitalization

我正在尝试找到一个在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正则表达式在每个重音字符之前/之后匹配“单词边界”。我希望单词边界只能匹配空格字符和非空格字符。

有人可以建议解决方案吗?

谢谢,

布赖恩。

  É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

4 个答案:

答案 0 :(得分: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

答案 1 :(得分: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);

答案 2 :(得分: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. 我改变了本地。你告诉它在法国使用说英语的语言环境。我不确定这是一个有效的语言环境。我选了一个实际上使用重音字符的本地。

  3. 不幸的是,语言环境名称没有标准化,但以下语言环境对我有用:

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

    特别是,如果没有连字符,它就无效。

答案 3 :(得分:0)

其实你只需要utf8 pragma。

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