regex - perl6 如何只在某些条件下匹配一个字符?

标签 regex match conditional-statements raku

我有一个格式的文件:

- 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 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('-')
    }>
}

语法是一种类,正则表达式/标记/规则是一种方法。因此,您可能应该通过添加换行符和注释以这种方式编写它们。

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

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

我还将各部分的分隔符从一个换行符更改为一个换行符和两个空格。这将从 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 是预料之中的,因为有一个尾随换行符,并且就语法所知,它后面可以跟一个任务。

关于regex - perl6 如何只在某些条件下匹配一个字符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41787612/

相关文章:

Java 正则表达式 特殊字符和 & 符号

python - 非贪婪 XML 中的多个匹配(Python 正则表达式)

python - 如何使用正则表达式搜索字母对匹配?

excel - 索引匹配具有多个条件的唯一值?

if-statement - awk 打印标题上带有条件的列

c# - 仅当包含至少 1 个指定字符时,正则表达式匹配任何 2 个字符组合

.NET 正则表达式保留字符

haskell - 请帮助我理解 haskell 中的模式匹配。我有点困惑

mysql - 在 MySQL 中,我可以在 INSERT 上下文中使用 IF 吗?

r - 基于行和列总和的 0 和 1 条件随机矩阵