rakulang, dartlang, nimlang, golang, rustlang, lang lang no see

Raku 中的梳子

焉知非鱼

Comb in Raku

Raku 中的梳子!

在 Perl 5 中, 我很感激有这样两个便利的结构:

my @things = $text =~ /thing/g;
my %things = $text =~ /(key)...(value)/g;

你拿出一小段可以预见的文本, 并给它一个正则表达式, 吼吼, 你得到了一个列表和散列, 像变魔术一般!我们也可以在 Raku 中使用正则表达式, 但是 comb 更适合做这个工作。

img

朴素的字符 #

你可以把 comb 用作子例程或方法。在它的最基本的形式中, comb 会把字符串分解为字符:

'foobar moobar 駱駝道bar'.comb.join('|').say;
'foobar moobar 駱駝道bar'.comb(6).join('|').say;

# OUTPUT:
# f|o|o|b|a|r| |m|o|o|b|a|r| |駱|駝|道|b|a|r
# foobar| mooba|r 駱駝道b|ar

不适用任何参数的 comb 你会得到各个单独的字符。给 comb 提供一个整数 $n, 那么你会得到长度至多为 $n 个字符的一个列表, 并且如果没有剩下的字符不够的话, 这个列表会接收较短的这个字符串。这个方法比使用正则表快了 30 倍。

Limits #

你也可以为 comb 提供第二个整数参数, 即 limit, 来标示每个列表中最多含有 limit 个元素:

'foobar moobar 駱駝道bar'.comb(1, 5).join('|').say;
'foobar moobar 駱駝道bar'.comb(6, 2).join('|').say;

# OUTPUT:
# f|o|o|b|a
# foobar| mooba

这适用于使用 comb 方法/函数的所有形式, 而不仅仅是上面展示的那样。

计数 #

comb 也接收普通的 Str 作为参数, 返回一个包含那个字符串的匹配的列表。所以这在计算子字符串在字符串中出现的次数时很有用。

'The 🐈 ran after a 🐁, but the 🐁 ran away'.comb('🐈').Int.say;
'The 🐈 ran after a 🐁, but the 🐁 ran away'.comb('ran').Int.say;

# OUTPUT:
# 1
# 2

简单的匹配 #

comb 的参数也可以是一个正则表达式, 整个匹配会作为一个标量被返回:

foobar moobar 駱駝道bar'.comb(/<[a..z]>+ 'bar'/).join('|').say;

# OUTPUT:
# foobar|moobar

限制所匹配的东西 #

你可以使用环视断言或者更简单的 <()> 正则表达式捕获记号:

'moo=meow ping=pong'.comb(/\w+    '=' <( \w**4/).join('|').say; # values
'moo=meow ping=pong'.comb(/\w+ )> '='    \w**4/).join('|').say; # keys

# OUTPUT:
# meow|pong
# moo|ping

你可以使用 <()> 两者之一或两者都使用。<( 从匹配中排除任何它之前的东西, 而 )> 会排除之后的任何东西。即 /'foo' <('bar')> 'ber'/ 会匹配包含 foobarber 的东西, 但是从 comb 中返回的东西只会有 bar

多个捕获 #

怎么样得出 Perl 5 那样的键/值对儿呢?

my %things = 'moo=meow ping=pong'.comb(/(\w+) '=' (\w+)/, :match)».Slip».Str;
say %things;

# OUTPUT:
# moo => meow, ping => pong

圆括号用于捕获。:match 参数使 comb 返回一个 Match 对象的列表, 而非返回一个字符串列表。下一步, 我们使用两个 hyper 运算符把 Matches 转换为 Slips, 这会给我们一个捕获的列表, 但是它们仍旧是 Match 对象, 这就是为什么我们还要把它们转换为 Str 的原因。

我们还可以使用具名捕获使代码更清晰:

my %things = 'moo=meow ping=pong'
    .comb(/$<key>=\w+ '=' $<value>=\w+/, :match)
    .map({ .<key> => .<value>.Str });
say %things;

# OUTPUT:
# moo => meow, ping => pong

你还可以把上面的代码写成这样:

my %things = ('moo=meow ping=pong' ~~ m:g/(\w+) '=' (\w+)/)».Slip».Str;
say %things;

# OUTPUT:
# moo => meow, ping => pong

结论 #

combrotor 结合起来用会很强大。

评论 #

代替使用带有 :match 参数的 .comb, 你最好就使用 .match 方法好了:

'moo=meow ping=pong'.match(/(\w+) '=' (\w+)/, :g)