【问题标题】:perl6 Negating multiple words and permutations of their chars inside a regexperl6 在正则表达式中否定多个单词及其字符的排列
【发布时间】:2017-03-01 17:46:05
【问题描述】:

在正则表达式中,执行多个单词的否定以及构成这些单词的字符排列的最佳方法是什么?

例如:我不想

"zero dollar"
"roze dollar"
"eroz dollar"
"one dollar"
"noe dollar"
"oen dollar"

但我确实想要

"thousand dollar"
"million dollar"
"trillion dollar"

如果我写

not m/ [one | zero] \s dollar /

它不会匹配字符的排列,并且外部的“not”函数将使正则表达式匹配其他所有内容,例如“big bang”,而正则表达式中没有“dollar”。

m/ <- [one] | [zero] > \s dollar/ # this is syntax error.

非常感谢!

lisprog

【问题讨论】:

  • FWIW,避免语法错误的方法是将其写为/ &lt;!after one | zero&gt; \s dollar/
  • 应该有一个新的tag类别perl6 regexen,这样人们就可以区分PCRE 5种类型了。
  • @sln regex 标签的描述说“所有带有这个标签的问题还应该包括一个指定适用的编程语言或工具的标签。” Aiui 这解决了您提出的问题(不仅针对 PCRE 正则表达式与非 PCRE 正则表达式,而且还针对一种 PCRE 风味与另一种),前提是提问者遵循警告添加语言/工具标签(或编辑为他们做)。我相信所有 Perl 6 正则表达式问题都是如此。也许tag intersection searching 需要改进?
  • @raiph - 我认为 Perl6 正则表达式有一些兼容模式可以启用 Perl5。但是,Perl5 风格的正则表达式结构渗透到其他引擎的 %90 语法中。这就是为什么 regex 标记主要是 Perl5 样式的默认值。让正则表达式符合 perl6 的要求实在是太大了,因为它在正则表达式领域大多是独立的。
  • 谢谢你的罪和raiph!我更喜欢 perl6 正则表达式。

标签: regex permutation raku negation


【解决方案1】:

使用代码断言:

您可以匹配任何单词,然后使用&lt;!{ }&gt; 断言来拒绝“一”或“零”排列的单词:

say "two dollar" ~~ / :s ^ (\w+) <!{ $0.comb.sort.join eq "eno" | "eorz" }> dollar $ /;

使用before/after:

或者,您可以预先生成不允许的单词的所有排列,然后在正则表达式中使用&lt;!before &gt;&lt;!after &gt; 断言来拒绝它们:

my @disallowed = <one zero>.map(|*.comb.permutations)».join.unique;

say "two dollar" ~~ / :s ^ <!before @disallowed>\w+ dollar $ /;
say "two dollar" ~~ / :s ^ \w+<!after @disallowed> dollar $ /;

【讨论】:

    【解决方案2】:

    这是一个行之有效的解决方案。它使用一个 helper-sub is-bad-word$needle(即它在目标字符串中找到的内容)与 @badwords 进行比较,如果 any 匹配,它将返回 True。

    在正则表达式本身内部,我使用了一个否定代码断言,它将匹配到辅助 sub 的 (\w+) 传递。

    需要指出的重要一点:如果您没有正确地将(\w+) 锚定到单词的开头(这次我选择了字符串的开头),它会在发现坏词时跳过一个字符无论如何都要接受(除非坏词只有一个字符开头,比如a dollar)。毕竟,你的@badwords 是零,但ero 不是。

    希望有帮助!

    my @badwords = <one zero yellow>;
    
    my @parsefails = q:to/EOF/.lines;
        zero dollar
        roze dollar
        erzo dollar
        one dollar
        noe dollar
        oen dollar
        yellow dollar
        wolley dollar
        EOF
    
    my @parsepasses = q:to/EOF/.lines;
        thousand dollar
        million dollar
        dog dollar
        top dollar
        meme dollar
        EOF
    
    sub is-bad-word($needle) {
        return $needle.comb.sort eq any(@badwords).comb.sort
    }
    
    use Test;
    plan @parsefails + @parsepasses;
    
    for flat (@parsefails X False), (@parsepasses X True) -> $line, $should-pass {
        my $succ = so $line ~~ / ^ (\w+) \s <!{ is-bad-word($0.Str) }> 'dollar' /;
        ok $succ eqv $should-pass, "$line -> $should-pass";
    }
    
    done-testing;
    

    【讨论】:

    • 当然,如果您有兴趣也不允许使用一美元,您可能希望在 is-bad-word 中将 eq 的两侧折叠起来 (.fc)。
    • 谢谢提莫蒂莫!!你已经打包了许多我需要做更多学习的概念。我会学习 Perl6;与你同在!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-05
    • 2018-12-16
    • 1970-01-01
    • 2016-04-28
    • 2021-11-16
    • 2016-09-06
    • 2021-04-20
    相关资源
    最近更新 更多