分类: PERL
2014-01-12 21:38:51
1.8.1 问题描述
你有一个Unicode字符串,它包含有组合字符,但是你希望把这个字符串当做一个单独的逻辑字符处理。
1.8.2 解决方案
在正则表达式中用\X来处理此类字符
$string = "fac\x{0327}ade"; # "fa?ade"
$string =~ /fa.ade/; # fails
$string =~ /fa\Xade/; # succeeds
@chars = split(//, $string); # 7 letters in @chars
@chars = $string =~ /(.)/g; # same thing
@chars = $string =~ /(\X)/g; # 6 "letters" in @chars
1.8.3 讨论
一个基本字符可以和一个非空的Unicode字符结合,一般情况下这些Unicode字符是一些附加字符,例如重音符号,变音符号和波浪线等.对容纳遗留字符系统来说,同一个字符结构可以有两个或者更多的表现方式。例如,单词 "fa?ade" 可以写成两个“a”中间插入一个字符的形式,"\x{E7}"是一个拉丁字符,这类字符采用UTF-8双字节编码的形式,这和perl内部采取的编码形式是一致的,但是这种双字节在perl中会被当做一个字符处理。
另外一种方式显得复杂,表达U+00E7的方式是使用两种不同的编码:字母c后面加上“\x{327}. 代码U+0327是一个无空格间隔的组合字符,它要求把一个变音符号加到前边一个基本字符的下边。
我们经常会遇到需要让perl把组合字符作为一个逻辑字符来处理,但是组合字符里边是不同的代码格式。Perl里边相关处理字符的操作符对中间不含空格的组合字符作为独立的字符处理,它们包括substr,length,和正则表达式的元字符,像/./ 或[^abc].
在正则表达式中, 元字符\X匹配的是包含Unicode的组合字符,它相当于(?:PM\pM*)
(?x: # begin non-capturing group
\PM # one character without the M (mark) property,
# such as a letter
\pM # one character that does have the M (mark) property,
# such as an accent mark
* # and you can have as many marks as you want
)
然而,如果在字符串中包含了这些符号会使得简单的做作显得复杂,按照上一节介绍的字符逆序排列单词的方法,"année" 和"ni?o"可以写成"anne\x{301}e" and "nin\x{303}o"
for $word ("anne\x{301}e", "nin\x{303}o") {
printf "%s simple reversed to %s\n", $word,
scalar reverse $word;
printf "%s better reversed to %s\n", $word,
join("", reverse $word =~ /\X/g);
}
=> année simple reversed to éenna
année better reversed to eénna
ni?o simple reversed to ?nin
ni?o better reversed to o?in
上面例子中的输出结果中标示simple reversed的,变音符从一个基本字符换为了另一个基本字符,因为组合字符总是跟随其基本字符的,而逆转的是整个字符串。避免这种问题的方法是抓取包含所有字符的序列,其中包括基本字符后边的组合字符,然后逆序这个序列。