首页 > 解决方案 > perl6 正则表达式:匹配除 . 和 ”

问题描述

我读了一些关于匹配“X 除了 Y”的线程,但没有特定于 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>-⏏&lt;[\.\"]>/, " ", :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>;

最好的方法是什么?

标签: regexcharacterraku

解决方案


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

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

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


您的输入字符串包括+$。这些不被视为“标点”字符。您可以将它们显式添加到被空格替换的字符集中:

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

(我之前已经放弃了首字母+:punct如果您没有为字符类算术表达式中的第一项写 a +or ,则假定为。)-+

有一个涵盖所有“符号”的 Unicode 属性,+因此$您可以使用它来代替:

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

回顾一下,您可以组合任意数量的:

  • 像这样的 Unicode 属性:punct以 a 开头:并对应于 Unicode 指定的某些字符属性;或者

  • [...]枚举特定字符的字符类、反斜杠字符类(如\d)或字符范围(如a..z)。


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

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

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

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

此后,同一整体字符类算术表达式中的每个附加属性或字符类必须以带有或不带有附加空格的 or 开头(例如+)。-<:punct - [."] ...>


您可以在括号中对子表达式进行分组。


我不确定+and的确切语义是什么-。我注意到这个令人惊讶的结果:

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

字符类算术表达式不接受表单<...>的内置函数。

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


\d要像在字符类算术表达式中使用+和算术一样使用反斜杠“字符类” ,-您必须字符类中列出它[...]

组合断言

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

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

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


推荐阅读