我该如何将Perl5/PCRE翻译成Perl 6正则表达式?

8

为了先说明一下,我会使用indexsubstr或类似的方法,因为它们是我特定情况下的明显解决方案,但我正在制作一个grammar,所以我只能使用regex。 :(

话虽如此,关于将Perl5 / PCRE正则表达式翻译为Perl6正则表达式的建议仍然是很好的SO内容,因为Perl 6越来越流行,它的正则表达式引擎非常不同。


这里有一个正则表达式,只匹配不包含给定字符列表中任何字符的字符串。
(在这里试一试.)

^(?:(?!\/).)*$
^            # assert position at start of string
(?:          # begin a noncapturing group 
   (?!       # negative lookahead: following regex must not match the string
      \/     # literal forward slash
    )        # end negative lookahead
    .        # any character, once
 )*          # the previous noncapturing group, 0..Inf times
 $           # assert position at end of string

显然,由于多种原因,在Perl 6中无法使用。

基于在perl6正则表达式文档中查找非捕获组负向先行断言,我尝试将其翻译为以下内容:

[ \/ <!before .*> \/ <!after .*> || .? ]*

还有一个细节(我想是这个):

[       # begin a noncapturing group which apparently look like a charclass in p6
\/      # a literal forward slash  
<!before .*> # negative lookahead for the immediately preceding regex (literal /)
\/      # a literal /
<!after .*>  # negative lookbehind for the immediately preceding regex
|| .?   # force this to be a noncapturing group, not a charclass
]*      # end noncapturing group and allow it to match 0..Inf times

我像这样实现:my regex not-in { ... },然后像这样使用:/^<not-in>$/。但是它对于每个字符串都返回Nil,这意味着它无法正常工作。
我找不到Perl 6的http://regex101.com等效工具,因此与Perl 5一样轻松地玩耍并不容易。
如何将此转换为Perl 6?

@CIAvash 当然应该!我太累了,抱歉。 - cat
1
如果你还没有安装,可以通过安装Grammar::Debugger来使用Grammar::TracerGrammar::Debugger。在我调试语法时,它们非常有帮助。 - Christopher Bottoms
2
我认为即使在Perl 5中,如果您只是反转检查"a" !~ m{/},在Perl 6中则为"a" !~~ m{'/'},效果会更好。虽然我可以想象出一些情况,您需要知道如何编写像您所拥有的那样的内容。但在这种特定情况下,m{^ [^\/]* $}x会更好。 - Brad Gilbert
1
m{^ [^\/]* $}x仍然更好 - Brad Gilbert
1
@BradGilbert 请将您的 "a" !~~ m{'/'} 添加为答案。@cat 如果Brad Gilbert将其作为答案添加,那么它应该是被接受的答案。 - Christopher Bottoms
显示剩余5条评论
3个回答

8

简短回答

匹配不包含正斜杠的字符串的正则表达式:/^ <-[ / ]>* $/

/ 开始正则表达式
^ 字符串开头

<-[ 打开负字符类(如果没有 -,那么这将是一个普通字符类)
/ 类不匹配的字符
]> 关闭字符类

* 零个或多个此类的“副本”
$ 字符串结束
/ 正则表达式结束

Perl 6 正则表达式中默认忽略空格。


详细回答

如果我理解正确,您只是想匹配不包含正斜杠的字符串。在这种情况下,只需使用负字符类即可。

包含 ab 的字符类应写为:<[ab]>

ab 以外的任何字符类应写为:<-[ab]>

包含除 / 以外的任何字符类应写为:<-[ / ]>,确保字符串中没有任何字符包含正斜杠的正则表达式为 /^ <-[ / ]>* $/

此代码在字符串不含正斜杠时匹配,在包含正斜杠时不匹配:

say "Match" if "abc/" ~~ /^ <-[ / ]>* $/; # Doesn't match
say "Match" if "abcd" ~~ /^ <-[ / ]>* $/; # Matches

使用index函数是检查除一个字符外是否存在的首选方法。但是,如果您想要排除多个字符,只需使用带有不想在字符串中查找的所有字符的负字符类即可。

是的,你对我的问题的理解是正确的,抱歉。我没有在文档中看到定义负向先行断言的这种方式,但还是谢谢! - cat

7

你原始正则表达式 ^(?:(?!\/).)*$ 的字面翻译到Perl 6语法的形式是:

^ [ <!before \/> . ]* $

这个很容易直接翻译。

  • (?:...)替换为[...]
  • (?!...)替换为<!before...>
  • 默认情况下假设使用x修改器

在这个例子中,其他内容保持不变。

我已经用一个简单的例子进行了测试:

say "Match" if "ab/c" ~~ /^ [ <!before \/> . ]* $/; # doesn't match
say "Match" if "abc"  ~~ /^ [ <!before \/> . ]* $/; # Match

3
更易读,避免“斜着的牙签症候群”:^ [ <!before '/'> . ]* $ - mscha

2

先说一下

你的问题开头是这样的:

为了先解决这个问题,我会使用 index、substr 或类似的方法,因为它们是我特定情况下的显而易见的解决方案,但我正在编写语法,所以只能使用正则表达式。 :(

严格来说,你可以做到这一点。实际上,你可以在 Perl 正则表达式中嵌入任意代码。


以下是 Perl 6 的一个典型示例:

/ (\d**1..3) <?{ $/ < 256 }> / # match an octet
\d**1..3位匹配1到3个十进制数字。括号(...)告诉Perl 6将匹配存储在特殊变量$/中。 <?{ ... }>是一个代码断言。如果代码返回true,正则表达式继续运行。否则,它会回溯或失败。
使用index等函数(在这种情况下,我选择了substr-eq)在正则表达式中很麻烦,可能是疯狂的。但是,它是可行的:
say "a/c" ~~ / a <?{ $/.orig.substr-eq: '/', $/.to }> . c /;
say "abc" ~~ / a <?{ $/.orig.substr-eq: '/', $/.to }> . c /

显示:

「a/c」
Nil

在Match对象上调用.orig会返回与之匹配的原始字符串。调用.to会返回该原始字符串中匹配到的位置,或者到目前为止已经匹配到的位置;"abc" ~~ / a { say $/.orig, $/.to } bc /会显示abc1


1
谢谢你教我东西!当我在通知中看到这个回答时,我本来以为会因为我的问题起步方式而被批评呢 :) - cat
1
我不想让Audrey失望,也不想让Jackson Galaxy追捕我。 :) - raiph
1
我正在回顾我的一些旧问题,我想我从来没有点击过你的评论中的链接,但那些链接非常有趣,特别是巧合的是,也是一个跨性别女性自由软件开发者,现在奥黛丽是我的偶像 :) - cat
你听说过-Ofun编译器标志吗? - raiph
我在一月的评论中提到了奥德丽,是因为每当我给陌生人在线回答问题时,我都会想到她“拥抱巨魔”理念下的爱与智慧。(并不是说你有巨魔般的行为啊,但无论怎样)我提到采纳 -Ofun 作为指导原则是因为这可能是她对 Perl 6 最重要的影响。如果您还没有访问过 #perl6#perl6-dev,并亲身体验过 -Ofun,那么您将错过很多......;) - raiph

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