首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >否定命名Regex,或Raku中的字符类插值

否定命名Regex,或Raku中的字符类插值
EN

Stack Overflow用户
提问于 2020-12-05 23:20:25
回答 2查看 223关注 0票数 16

我正试图解析一个引用的字符串。就像这样:

代码语言:javascript
复制
say '"in quotes"' ~~ / '"' <-[ " ]> * '"'/;

(来自https://docs.raku.org/language/regexes“枚举字符类和范围”)但是..。我想要更多的那一种报价。这样的东西构成了不起作用的语法:

代码语言:javascript
复制
  token attribute_value { <quote> ($<-quote>) $<quote> };
  token quote           { <["']> };

我发现这种讨论是另一种方法,但它似乎没有任何进展:https://github.com/Raku/problem-solving/issues/97。有办法做这种事吗?谢谢!

更新1

我无法获得@user0721090601的“多令牌”解决方案。我的第一次尝试成功了:

代码语言:javascript
复制
$ ./multi-token.raku 
No such method 'quoted_string' for invocant of type 'QuotedString'
  in block <unit> at ./multi-token.raku line 16

在做了一些研究之后,我加入了proto token quoted_string {*}

代码语言:javascript
复制
#!/usr/bin/env raku

use Grammar::Tracer;

grammar QuotedString {
  proto token quoted_string {*}
  multi token quoted_string:sym<'> { <sym> ~ <sym> <-[']> }
  multi token quoted_string:sym<"> { <sym> ~ <sym> <-["]> }
  token quote         { <["']> }
}

my $string = '"foo"';

my $quoted-string = QuotedString.parse($string, :rule<quoted_string>);
say $quoted-string;
代码语言:javascript
复制
$ ./multi-token.raku 
quoted_string
* FAIL
(Any)

我还在学习Raku所以我可能做错了什么。

更新2

哦哦!感谢@raiph指出这一点。我忘了在<-[']><-["]>上加一个量词。这就是我在没有思想的情况下复制/粘贴的结果!工作发现当你做得对的时候:

代码语言:javascript
复制
#!/usr/bin/env raku

use Grammar::Tracer;

grammar QuotedString {
  proto token quoted_string (|) {*}
  multi token quoted_string:sym<'> { <sym> ~ <sym> <-[']>+ }
  multi token quoted_string:sym<"> { <sym> ~ <sym> <-["]>+ }
  token quote         { <["']> }
}

my $string = '"foo"';

my $quoted-string = QuotedString.parse($string, :rule<quoted_string>);
say $quoted-string;

更新3

只是为了在这上面鞠躬..。

代码语言:javascript
复制
#!/usr/bin/env raku

grammar NegativeLookahead {
  token quoted_string { <quote> $<string>=([<!quote> .]+) $<quote> }
  token quote         { <["']> }
}

grammar MultiToken {
  proto token quoted_string (|) {*}
  multi token quoted_string:sym<'> { <sym> ~ <sym> $<string>=(<-[']>+) }
  multi token quoted_string:sym<"> { <sym> ~ <sym> $<string>=(<-["]>+) }
}

use Bench;

my $string = "'foo'";

my $bench = Bench.new;
$bench.cmpthese(10000, {
  negative-lookahead =>
    sub { NegativeLookahead.parse($string, :rule<quoted_string>); },
  multi-token        =>
    sub { MultiToken.parse($string, :rule<quoted_string>); },
});
代码语言:javascript
复制
$ ./bench.raku
Benchmark: 
Timing 10000 iterations of multi-token, negative-lookahead...
multi-token: 0.779 wallclock secs (0.759 usr 0.033 sys 0.792 cpu) @ 12838.058/s (n=10000)
negative-lookahead: 0.912 wallclock secs (0.861 usr 0.048 sys 0.909 cpu) @ 10967.522/s (n=10000)
O--------------------O---------O-------------O--------------------O
|                    | Rate    | multi-token | negative-lookahead |
O====================O=========O=============O====================O
| multi-token        | 12838/s | --          | -20%               |
| negative-lookahead | 10968/s | 25%         | --                 |
O--------------------O---------O-------------O--------------------O

我将使用“多令牌”解决方案。谢谢大家!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-12-06 05:57:15

有几种不同的方法可以采用- which,最好的方法可能取决于您所使用的结构的其余部分。

但是,首先,观察一下你目前的解决方案,以及为什么向其他人开放它并不是这样的。考虑一下字符串'value"。应该解析一下吗?你布置的结构实际上是匹配的!这是因为每个<quote>令牌将匹配单引号或双引号。

处理内心

最简单的解决方法是让你的内心成为一个非贪婪的通配符:

代码语言:javascript
复制
<quote> (.*?) <quote>

这将停止比赛,一旦你到达报价再次。还请注意使用可以使两个终端位更接近的倾斜的替代语法:

代码语言:javascript
复制
<quote> ~ <quote> (.*?)

你最初的尝试是想用一种不匹配的方法。这确实以断言的形式存在,如果找到一个<!quote> (通过任意复杂的事情,它不需要仅仅是一个字符),<quote>就会失败。但是它不消耗,所以您需要单独提供。例如

代码语言:javascript
复制
[<!quote> .]*

将检查某些内容不是引号,然后使用下一个字符。

最后,您可以使用这两种方法之一,并使用内部处理的<content>令牌。这实际上是一个很好的方法,如果你打算以后做更复杂的事情(例如转义字符)。

避免错配

正如我所指出的,您的解决方案将解析不匹配的引号。因此,我们需要有一种方法,以确保我们是(而不是)匹配的报价是相同的开始一个。其中一种方法是使用multi token

代码语言:javascript
复制
proto token attribute_value (|) { * }
multi token attribute_value:sym<'> { <sym> ~ <sym> <-[']> }
multi token attribute_value:sym<"> { <sym> ~ <sym> <-["]> }

(不需要使用实际的令牌<sym>,如果需要,可以将其编写为{ \' <-[']> \'} )。

另一种可以这样做的方法是传递一个参数(不管是字面意义上的,还是通过动态变量)。例如,您可以将attribute_value编写为

代码语言:javascript
复制
token attribute_value {
    $<start-quote>=<quote>      # your actual start quote
    :my $*end-quote;            # define the variable in the regex scope
    { $*end-quote = ... }       # determine the requisite end quote (e.g. ” for “)
    <attribute_value_contents>  # handle actual content
    $*end-quote                 # fancy end quote
}

token attribute_value_contents {
    # We have access to $*end-quote here, so we can use
    # either of the techniques we've described before
    # (a) using a look ahead
    [<!before $*end-quote> .]*
    # (b) being lazy (the easier)
    .*?
    # (c) using another token (described below)
    <attr_value_content_char>+
}

我提到最后一个原因是,如果最终决定允许转义字符,您甚至可以进一步委托。例如,您可以这样做

代码语言:javascript
复制
proto token attr_value_content_char (|) { * }
multi token attr_value_content_char:sym<escaped> { \\ $*end-quote }
multi token attr_value_content_char:sym<literal> { . <?{ $/ ne $*end-quote }> }

但如果你的所作所为太过分了,啊,好吧:-)

不管怎么说,也许有其他的方法没有跳进我的脑海,其他人可以想到,但希望这会让你走上正确的道路。(此外,有些代码未经测试,因此可能会出现轻微的错误,对此表示歉意)

票数 12
EN

Stack Overflow用户

发布于 2020-12-06 16:19:10

假设您只想再次匹配相同的引号字符。

代码语言:javascript
复制
token attribute-value { <string> }

token string {
  # match <quote> and expect to end with "$<quote>"
  <quote> ~ "$<quote>"

  [
    # update match structure in $/ otherwise "$<quote>" won't work
    {}

    <!before "$<quote>"> # next character isn't the same as $<quote>

    .    # any character

  ]*     # any number of times
}

token quote { <["']> }

对于任何更复杂的内容,请使用类似于前面答案中的$*end-quote动态变量的内容。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65163014

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档