问题描述
我正在尝试将单词 wall 转换为其ascii代码列表(119,97,108,108)
,如下所示:
my @ascii="abcdefghijklmnopqrstuvwxyz";
my @tmp;
map { push @tmp,$_.ord if $_.ord == @ascii.comb.any.ord },"wall".comb;
say @tmp;
请注意,我必须使用@ascii
变量,即我不能使用连续增加的ascii序列(97,98,99 ... 122)
,因为我也打算将这种代码用于非ascii语言。
解决方法
我们可以在这里做一些事情来使其正常工作。
首先,让我们解决@ascii
变量。 @
标记表示位置变量,但是您为其分配了单个字符串。这将创建一个由1个元素组成的数组['abc...']
,这将在以后引起问题。根据您需要的通用程度,我建议直接创建一个数组:
my @ascii = <a b c d e f g h i j k l m n o p q r s t u v x y z>;
my @ascii = 'a' .. 'z';
my @ascii = 'abcdefghijklmnopqrstuvwxyz'.comb;
或继续处理any
部分:
my $ascii-char = any <a b c d e f g h i j k l m n o p q r s t u v x y z>;
my $ascii-char = any 'a' .. 'z';
my $ascii-char = 'abcdefghijklmnopqrstuvwxyz'.comb.any;
在这里,我使用了$
标记,因为any
确实指定了任何 single 值,因此也可以正常工作(这也使我们的生活更加轻松)。我本人会使用$ascii
,但我使用了一个单独的名称,以使以后的示例更具区分性。
现在我们可以处理地图功能了。根据{{1}}的以上两个版本,我们可以将您的map函数重写为以下任意一个
ascii
请注意,如果您更喜欢使用{ push @tmp,$_.ord if $_ eq @ascii.any }
{ push @tmp,$_.ord if $_ eq $ascii-char }
,则可以继续在最初的==
创建中创建数值,然后使用ascii
。同样,就个人而言,我喜欢命名映射变量,例如:
$_.ord
其中{ push @tmp,$^char.ord if $^char eq @ascii.any }
{ push @tmp,$^char.ord if $^char eq $ascii-char }
替换$^foo
(如果您使用多个,它们将按字母顺序映射到$_
,@_[0]
等)。
但是,让我们在这里提出更有趣的问题。我们如何无需预先声明@_[1]
就能完成所有这些工作?显然,这仅需要在map循环中创建数组。您可能会认为,当我们没有ASCII值时,这可能会很棘手,但是如果@tmp
语句未运行,则会返回if
(或Empty
),这确实使生活变得更加艰难。简单:
()
如果我们使用“wáll”,则my @tmp = map { $^char.ord if $^char eq $ascii-char },"wall".comb;
my @tmp = map { $^char.ord if $^char eq @ascii.any },"wall".comb;
收集的列表 将是map
,它自动返回为{{1} }。因此,119,Empty,108,108
被设置为119,108
。
是的,有一种更简单的方法。
"wall".ords.grep('az'.ords.minmax);
当然,这取决于a
至z
是不间断的序列。这是因为minmax
根据列表中的最小值和最大值创建一个Range对象。
如果它们的序列不间断,则可以使用结点。
"wall".ords.grep( 'az'.ords.minmax | 'AZ'.ords.minmax );
但是您说过要匹配其他语言。让我尖叫的是正则表达式。
"wall".comb.grep( /^ <:Ll> & <:ascii> $/ ).map( *.ord )
这与同样也是ASCII的小写字母匹配。
实际上,我们可以使其更简单。 comb
可以使用正则表达式来确定从输入中获取哪些字符。
"wall".comb( / <:Ll> & <:ascii> / ).map( *.ord )
# (119,97,108)
"ΓΔαβγδε".comb( / <:Ll> & <:Greek> / ).map( *.ord )
# (945,946,947,948,949)
# Does not include Γ or Δ,as they are not lowercase
请注意,如果您没有重音符号,则以上内容仅适用于ASCII。
"de\c[COMBINING ACUTE ACCENT]f".comb( / <:Ll> & <:ascii> / )
# ("d","f")
组合式重音符号与e
组合而成,"f\c[COMBINING ACUTE ACCENT]".comb( / <:Ll> & <:ascii> / )
# ("f́",)
构成带小写字母的拉丁小写字母E。
该组成字符不是ASCII,因此会被跳过。
如果字符没有组合值,它将变得更加奇怪。
f
这是因为$buf.grep: {
.uniprop() eq 'Ll' #
&& .uniprop('Block') eq 'Basic Latin' # ASCII
}
是小写的ASCII码。组成的代码点可随身携带。
基本上,如果您的数据具有重音符号,或者可能具有重音符号,并且如果它可能会破坏东西,那么最好还是以二进制形式处理它。
.uniprop
上面的方法也适用于单个字符串,因为"wall".comb.grep: {
.uniprop() eq 'Ll' #
&& .uniprop('Block') eq 'Basic Latin' # ASCII
}
适用于代表代码点的整数或实际字符。
.uniprop('Script')
再次注意,由于它可以与字符串一起使用,因此在编写代码点时也会遇到相同的问题。
根据您想做什么,您可能还想使用.uniprop('Block')
而不是https
。
这是使用Raku的trans
方法(在Raku REPL中执行的代码段)的一种可行方法:
> my @a = "wall".comb;
[w a l l]
> @a.trans('abcdefghijklmnopqrstuvwxyz' => ords('abcdefghijklmnopqrstuvwxyz') ).put;
119 97 108 108
上面,我们处理一个ascii字符串。在下面添加“é”字符,并显示一个两步解决方案:
> my @a = "wallé".comb;
[w a l l é]
> my @b = @a.trans('abcdefghijklmnopqrstuvwxyz' => ords('abcdefghijklmnopqrstuvwxyz') );
[119 97 108 108 é]
> @b.trans("é" => ords("é")).put
119 97 108 108 233
注解#1:尽管上面的所有代码都能正常工作,但是当我尝试将字母缩短为'a'..'z'
时,我最终看到了错误的返回值...因此使用了完整的'abcdefghijklmnopqrstuvwxyz'
。
Nota bene#2:我脑海中的一个问题是,当trans
无法识别字符时,我试图抑制输出(例如,如何禁止将“é”分配为@b
的最后一个元素)上面的第二个示例代码)。我尝试将:delete
参数添加到trans
,但是没有运气。
已编辑:要删除不需要的字符,以下代码使用grep
(@ Brad Gilbert),然后使用trans
:
> my @a = "wallé".comb;
[w a l l é]
> @a.grep('a'..'z'.comb.any).trans('abcdefghijklmnopqrstuvwxyz' => ords('abcdefghijklmnopqrstuvwxyz') ).put
119 97 108 108