Perl6正则表达式: 匹配除了.和"之外的所有标点符号

8

我读了一些有关匹配“除Y外X”的帖子,但没有针对perl6的具体解释。 我正在尝试匹配和替换所有标点符号,除了.和


> my $a = ';# -+$12,678,93.45 "foo" *&';
;# -+$12,678,93.45 "foo" *&

> my $b = $a.subst(/<punct - [\.\"]>/, " ", :g);
===SORRY!===
Unrecognized regex metacharacter - (must be quoted to match literally)
------> my $b = $a.subst(/<punct⏏ - [\.\"]>/, " ", :g);
Unrecognized regex metacharacter   (must be quoted to match literally)
------> my $b = $a.subst(/<punct -⏏ [\.\"]>/, " ", :g);
Unable to parse expression in metachar:sym<assert>; couldn't find final '>' (corresponding starter was at line 1)
------> my $b = $a.subst(/<punct - ⏏[\.\"]>/, " ", :g);

> my $b = $a.subst(/<punct-[\.\"]>/, " ", :g);
===SORRY!=== Error while compiling:
Unable to parse expression in metachar:sym<assert>; couldn't find final '>' (corresponding starter was at line 1)
------> my $b = $a.subst(/<punct⏏-[\.\"]>/, " ", :g);
    expecting any of:
        argument list
        term

> my $b = $a.subst(/<punct>-<[\.\"]>/, " ", :g);
===SORRY!===
Unrecognized regex metacharacter - (must be quoted to match literally)
------> my $b = $a.subst(/<punct>⏏-<[\.\"]>/, " ", :g);
Unable to parse regex; couldn't find final '/'
------> my $b = $a.subst(/<punct>-⏏<[\.\"]>/, " ", :g);

> my $b = $a.subst(/<- [\.\"] + punct>/, " ", :g); # $b is blank space, not want I want
                       
> my $b = $a.subst(/<[\W] - [\.\"]>/, " ", :g);
      12 678 93.45 "foo"   
# this works, but clumsy; I want to 
# elegantly say: punctuations except \, and \" 
# using predefined class <punct>;

什么是最佳方法?

1个回答

10

我认为最自然的解决方案是使用“字符类算术表达式”。这涉及在任意数量的Unicode属性[...]字符类上使用+-前缀:

                            #;# -+$12,678,93.45 "foo" *&
<+:punct -[."]>             #    +$12 678 93.45 "foo"

这可以理解为“具有Unicode属性punct的字符类减去."字符”。


你的输入字符串包含+$。它们不被认为是“标点符号”字符。您可以明确将它们添加到要替换为空格的字符集中:

<:punct +[+$] -[."] >       #      12 678 93.45 "foo"   

(在:punct前面,我已经去掉了初始的+。如果你在字符类算术表达式的第一项中不写+-,则默认为+。)

有一个Unicode属性涵盖所有“符号”,包括+$,所以你可以使用它代替:

<:punct +:symbol -[."] >    #      12 678 93.45 "foo"

总而言之,您可以组合任意数量的:

  • Unicode 属性,例如以 : 开头并对应于由 Unicode 指定的某些字符属性的 :punct; 或者

  • [...] 字符类,列出特定字符、反斜杠字符类(如 \d)或字符范围(例如 a..z)。


如果整体的 <...> 断言是一个字符类算术表达式,则在开头的 < 后面的第一个字符必须是以下四个字符之一:

  • : 引入 Unicode 属性 (例如 <:punct ...>);

  • [ 引入 [...] 字符类 (例如 <[abc ...>);

  • +-。这可能后跟空格。然后必须跟随一个 Unicode 属性 (:foo) 或一个 [...] 字符类 (例如 <+ :punct ...>).

此后,在同一整体字符类算术表达式中的每个其他属性或字符类之前必须带有一个 +-,可以带有额外的空格 (例如 <:punct - [."] ...>).


您可以用括号将子表达式分组。


我不确定 +- 的精确语义。我注意到这个令人惊讶的结果:

say $a.subst(/<-[."] +:punct>/, " ", :g); # substitutes ALL characters!?! 

在字符类算术表达式中,形如<...>的内置符号不被接受

即使在文档中称其为"字符类",这也是真实的。这包括那些根本不像字符类的符号(例如,在文档中,<ident> 被称为字符类,尽管它匹配多个字符的字符串,该字符串匹配特定的模式!),但也包括那些看起来字符类的符号,例如 <punct><digit>。(后者中的许多直接对应于 Unicode 属性,因此您只需使用这些属性即可。)


要在字符类算术表达式中使用反斜杠 "字符类",例如 \d,您必须将其列在 [...] 字符类内部

组合断言

虽然<punct>不能使用字符类算术与其他断言组合,但可以使用&正则表达式连接运算符与其他正则表达式结构组合:

<punct> & <-[."]>           #    +$12 678 93.45 "foo"

根据编译器优化的状态(截至2019年,正则表达式引擎几乎没有进行过任何优化),通常情况下,这比使用真正的字符类要慢。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接