【问题标题】:perl6 How to match a character only under some conditions?perl6 如何仅在某些条件下匹配字符?
【发布时间】:2017-01-22 05:17:43
【问题描述】:

我有一个格式为:

- foo bar - baz
  one two three - or four
  and another line

- next job
  do this - and that

我的语法是

grammar tasks {
    regex TOP        { \n* <oneTask>+ \n* }
    regex oneTask    { ^^ \- (<oneSection> <endSection>)+ }
    regex oneSection { \N+ } # this is not quite working
    regex endSection { \n+ }

}

在正则表达式 oneSection 中,我如何编写“我想匹配 '-' 仅当它不在行首时”这一事实?

我把文件放到一个字符串中,然后解析这个字符串:

my $content = slurp("taskFile");
my $result = tasks.parse($content);

这不太行。

<[\N] - [\-]> does not make the match conditional.

谢谢!!

【问题讨论】:

    标签: regex match conditional-statements raku


    【解决方案1】:

    放下你想要匹配的东西比试图排除一些东西更容易。

    您要查找的是行首的一个字符,不是换行符或破折号,后跟任意数量的非换行符。或者您正在寻找至少一个不是换行符且不在换行符之后的字符。

    regex oneSection {
    
        || ^^            # beginning of line
           <-[\n-]>      # not newline or dash
           \N*           # any number of not newlines
    
        || <!before ^^>  # check the position before this is not the start of a line
           \N+
    
    }
    

    (这很复杂,因为您试图将复杂性放在语法中的错误位置)


    您也可以像当前一样匹配并添加一个以- 开头的测试失败。

    regex oneSection {
        \N+
    
        <!{ # fail if the following is True
            $/.starts-with('-')
        }>
    }
    

    语法是一种类,而正则表达式/令牌/规则是一种方法。因此,您可能应该通过添加换行符和 cmets 来编写它们。

    如果您学习如何使用 %%% 正则表达式运算符,编写语法会变得更好。
    (区别在于%%可以匹配尾随分隔符)

    有效地使用% 可能需要一些时间来适应,所以我将向您展示我将如何使用它来匹配您的文件。

    我还将部分的分隔符从一个换行符更改为一个换行符和两个空格。这将从 section 匹配的内容中删除空格,这将简化任何进一步的处理。

    在您学习期间,我建议您使用 Grammar::Debugger 和 Grammar::Tracer。

    grammar Tasks {
        # use token for its :ratchet behaviour
        # ( more performant than regex because it doesn't backtrack )
        token TOP {
            \n*       # ignore any preceding empty lines
    
            <task>+   # at least one task
            %         # separated by
            \n+       # at least one newline
    
            \n*       # ignore trailing empty lines
        }
    
        token task {
          ^^ '- '     # a task starts with 「- 」 at the beginning of a line
    
          <section>+  # has at least one section
          %           # separated by
          "\n  "      # a newline and two spaces
        }
    
        token section { \N+ }
    }
    
    my $test = q:to/END/;
    - foo bar - baz
      one two three - or four
      and another line
    
    - next job
      do this - and that
    END
    
    put Tasks.parse( $test, :actions(class {
      method TOP     ($/) { make @<task>».made.List }
      method task    ($/) { make @<section>».made.List }
      method section ($/) {
        make ~$/  # don't do any processing, just make it a Str
      }
    })).made.perl;
    
    # (("foo bar - baz", "one two three - or four", "and another line"),
    #  ("next job", "do this - and that"))
    

    如果我将use Grammar::Tracer; 放在顶部,它将输出如下内容:

    TOP
    |  task
    |  |  section
    |  |  * MATCH "foo bar - baz"
    |  |  section
    |  |  * MATCH "one two three - or four"
    |  |  section
    |  |  * MATCH "and another line"
    |  * MATCH "- foo bar - baz\n  one two three - or four\n  and another l"
    |  task
    |  |  section
    |  |  * MATCH "next job"
    |  |  section
    |  |  * MATCH "do this - and that"
    |  * MATCH "- next job\n  do this - and that"
    |  task
    |  * FAIL
    * MATCH "- foo bar - baz\n  one two three - or four\n  and another line"
    

    FAIL 是预期的,因为有一个尾随换行符,就语法所知,它后面可能跟着一个任务。

    【讨论】:

    • 非常好!!!非常感谢你,布拉德吉尔伯特!!!我希望其他读者能真正从您的回答中受益;我当然从你那里学到了很多。谢谢教授:-)
    【解决方案2】:

    匹配不是字符串开头的任何内容,后跟破折号

    [^$]-
    

    【讨论】:

    • 谢谢安迪·雷!但是如何推广到一个普遍的匹配条件呢?例如,仅在第n行且仅当“-”的总数未超过k时才匹配“-”?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-09
    • 2011-09-14
    • 1970-01-01
    • 2020-10-26
    • 1970-01-01
    • 1970-01-01
    • 2010-12-20
    相关资源
    最近更新 更多