将带有unicode字符的字符串转换为小写字母

vir*_*rus 0 regex unicode perl

问题陈述 -我正在处理一些数据文件.在该数据转储中,我有一些包含字符的unicode值的字符串.字符可以是大写和小写.现在我需要对此字符串进行以下处理.

1-如果有任何 - ,_)(} {] ['"然后删除它们.所有这些字符都以Unicode形式出现在字符串中($ 4-hexa-digits)

2-所有大写字符都需要转换为小写字母(包括所有不同的unicode字符'Φ' - >'φ','Ω' - >'ω','Ž' - >'ž')

3-稍后我将使用此最终字符串来匹配不同的用户输入.

问题详细说明 -我有一些字符串Buna$002C_Texas , Zamboanga_$0028province$0029和更多.

这里$002C, $0028$0029是Unicode值,我用下面把它们转换成自己的字符表示.

$str =~s/\$(....)/chr(hex($1))/eg;
Run Code Online (Sandbox Code Playgroud)

要么

$str =~s/\$(....)/pack 'U4', $1/eg;
Run Code Online (Sandbox Code Playgroud)

现在我按照我的要求替换所有角色.然后我将字符串解码为utf-8以获得所有字符的小写,包括unicode,如下所示,lc直接不支持unicode字符.

$str =~ s/(^\-|\-$|^\_|\_$)//g;                        
$str =~ s/[\-\_,]/ /g;                                                                         
$str =~ s/[\(\)\"\'\.]|?|’|‘//g;                                                                                       
$str =~ s/^\s+|\s+$//g;
$str =~ s/\s+/ /g;
$str = decode('utf-8',$str);
$str = lc($str);
$str = encode('utf-8',$str);
Run Code Online (Sandbox Code Playgroud)

但是当Perl尝试解码字符串时,我遇到了错误.

Cannot decode string with wide characters at /usr/lib64/perl5/5.8.8/x86_64-linux-thread-multi/Encode.pm line 173

如此处所述,此错误也很明显.@ http://www.perlmonks.org/?node_id=569402

现在我按照上面的url改变了我的逻辑.我使用下面的方法将unicode转换为字符表示.

$str =~s/\$(..)(..)/chr(hex($1)).chr(hex($2))/eg;

但现在我没有得到字符表示.我得到了一些不可打印的字符.那么当我不知道有多少不同的unicode表示时,如何处理这个问题.

amo*_*mon 5

您希望在进行转换之前解码字符串,最好使用类似的PerlIO层:utf8.因为您在解码之前插入了转义的代码点,所以您的字符串可能已经包含多字节字符.请记住,Perl(貌似)在代码点上运行,而不是字节.

那么我们要做的是以下内容:解码,unescape,规范化,删除,案例折叠:

 use strict; use warnings;
 use utf8;  # This source file holds Unicode chars, should be properly encoded
 use feature 'unicode_strings'; # we want Unicode semantics everywhere
 use Unicode::CaseFold; # or: use feature 'fc'
 use Unicode::Normalize;

 # implicit decode via PerlIO-layer
 open my $fh, "<:utf8", $file or die ...;
 while (<$fh>) {
   chomp;

   # interpolate the escaped code points
   s/\$(\p{AHex}{4})/chr hex $1/eg;

   # normalize the representation
   $_ = NFD $_;  # or NFC or whatever you like

   # remove unwanted characters. prefer transliterations where possible,
   # as they are more efficient:
   tr/.?//d;
   s/[\p{Quotation_Mark}\p{Open_Punctuation}\p{Close_Punctuation}]//g;  # I suppose you want to remove *all* quotation marks?
   tr/-_,/   /;
   s/\A\s+//;
   s/\s+\z//;
   s/\s+/ /g;

   # finally normalize case
   $_ = fc $_

   # store $_ somewhere.
 }
Run Code Online (Sandbox Code Playgroud)

您可能对perluniprops感兴趣,这是所有可用的Unicode字符属性的列表,例如Quotation_Mark,Punct(标点符号),Dash(像 - - - 这样的破折号),Open_Punctuation(像parens ({[?和引号一样„“)等.

为什么我们执行unicode规范化?一些字形(视觉字符)可以具有多个不同的表示.例如,á可以表示为" a具有急性"或"a"+"结合急性".的NFC尝试的信息组合成一个码点,而NFD分解这样的信息到多个码点.请注意,这些操作会更改字符串的长度,因为长度是在代码点中测量的.

在输出您分解的数据之前,最好再次重新组合它.

为什么我们使用case折叠fc而不是lowercasing?两个小写字符可能是等价的,但不会相同,例如希腊小写sigma:??.表壳折叠使其正常化.德语ß是大写的双字符序列SS.因此,"ß" ne (lc uc "ß").大小写折叠将其标准化,并将其转换ßss:fc("ß") eq fc(uc "ß").(但无论你做什么,你仍然可以享受土耳其数据).