如何删除 Perl 6 中的变音符号
How to remove diacritics in Perl 6
两个相关的问题。
Perl 6 非常聪明,它可以将字素理解为一个字符,无论它是一个 Unicode 符号(如 ä
、U+00E4
)还是两个或多个组合符号(如 p̄
和 ḏ̣
).这个小代码
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"个符号拆分为多个部分,即将p̄
拆分为p
和Combining 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 PCOMBINING MACRON»
或者只使用 uninames
method/routine:
.say for "p̄".uninames; # OUTPUT: «LATIN SMALL LETTER PCOMBINING 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"
两个相关的问题。
Perl 6 非常聪明,它可以将字素理解为一个字符,无论它是一个 Unicode 符号(如 ä
、U+00E4
)还是两个或多个组合符号(如 p̄
和 ḏ̣
).这个小代码
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"个符号拆分为多个部分,即将p̄
拆分为p
和Combining 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 PCOMBINING MACRON»
或者只使用 uninames
method/routine:
.say for "p̄".uninames; # OUTPUT: «LATIN SMALL LETTER PCOMBINING 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"