在Raku

问题描述

我正在尝试将单词 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;
  1. 是否可以使用@tmp而不用单独的行声明它?

  2. 是否可以在一行而不是三行中生成ASCII代码列表?如果是这样,该怎么做?

请注意,我必须使用@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);

当然,这取决于az是不间断的序列。这是因为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