如何删除 Perl 6 中的变音符号

How to remove diacritics in Perl 6

两个相关的问题。 Perl 6 非常聪明,它可以将字素理解为一个字符,无论它是一个 Unicode 符号(如 äU+00E4)还是两个或多个组合符号(如 ḏ̣).这个小代码

my @symb;
@symb.push("ä");
@symb.push("p" ~ 0x304.chr); # "p̄" 
@symb.push("ḏ" ~ 0x323.chr); # "ḏ̣"
say "$_ has {$_.chars} character" for @symb;

给出以下输出:

ä has 1 character
p̄ has 1 character
ḏ̣ has 1 character

但有时我希望能够做到以下几点。 1) 从 ä 中删除变音符号。所以我需要一些方法,比如

"ä".mymethod → "a"

2) 将"combined"个符号拆分为多个部分,即将拆分为pCombining Macron U+0304。例如。 bash 中的类似以下内容:

$ echo p̄ | grep . -o | wc -l
2

这是我能从文档中想到的最好的方法——可能有更简单的方法,但我不确定。

my $in = "Él está un pingüino";
my $stripped = Uni.new($in.NFD.grep: { !uniprop($_, 'Grapheme_Extend') }).Str;
say $stripped; # El esta un pinguino

.NFD 方法将字符串转换为规范化形式 D(分解),将字素分离为基本代码点并尽可能组合代码点。然后 grep returns 只列出那些没有 "Grapheme_Extend" 属性 的代码点,即它删除了组合代码点。 Uni.new(...).Str 然后将这些代码点组装回一个字符串。

你也可以把这些拼凑起来回答你的第二个问题;例如:

$in.NFD.map: { Uni.new($_).Str }

将return 1 个字符的字符串列表,每个字符串都有一个分解的代码点,或者

$in.NFD.map(&uniname).join("\n")

将成为一个不错的小 unicode 调试器。

Perl 6 在 Str class 中具有强大的 Unicode 处理支持。要执行 (1) 中的要求,您可以使用 samemark method/routine.

根据文档:

multi sub samemark(Str:D $string, Str:D $pattern --> Str:D)
method    samemark(Str:D: Str:D $pattern --> Str:D)

Returns a copy of $string with the mark/accent information for each character changed such that it matches the mark/accent of the corresponding character in $pattern. If $string is longer than $pattern, the remaining characters in $string receive the same mark/accent as the last character in $pattern. If $pattern is empty no changes will be made.

Examples:

say 'åäö'.samemark('aäo');                        # OUTPUT: «aäo␤» 
say 'åäö'.samemark('a');                          # OUTPUT: «aao␤» 

say samemark('Pêrl', 'a');                        # OUTPUT: «Perl␤» 
say samemark('aöä', '');                          # OUTPUT: «aöä␤» 

这既可以用来从字母中删除 marks/diacritics,也可以用来添加它们。

对于 (2),有几种方法可以做到这一点 (TIMTOWTDI)。如果你想要一个字符串中所有代码点的列表,你可以使用 ords 方法来获取字符串中所有代码点的 List(技术上是 Positional)。

say "p̄".ords;                  # OUTPUT: «(112 772)␤»

您可以使用 uniname method/routine 获取代码点的 Unicode 名称:

.uniname.say for "p̄".ords;     # OUTPUT: «LATIN SMALL LETTER P␤COMBINING MACRON␤»

或者只使用 uninames method/routine:

.say for "p̄".uninames;         # OUTPUT: «LATIN SMALL LETTER P␤COMBINING MACRON␤»

如果你只是想要字符串中代码点的数量,你可以使用codes:

say "p̄".codes;                 # OUTPUT: «2␤»

这与chars不同,它只计算字符串中的字符数:

say "p̄".chars;                 # OUTPUT: «1␤»

另请参阅@hobbs 使用 NFD 的回答。

我不能说这更好或更快,但我以这种方式去除变音符号:

my $s = "åäö";
say $s.comb.map({.NFD[0].chr}).join; # output: "aao"