如何将捕获组与“\K”重置匹配一起使用?

How to use capture groups with the `\K` reset match?

我发现 this question 关于使用带有 \K 重置匹配的捕获组(即,不确定这是否是正确的名称),但它没有回答我的查询。

假设我有以下字符串:

ab

使用以下 regex a\Kb 输出如预期的那样 b:

但是,当使用 regex (a\Kb) 添加捕获组(即 </code>)时,组 <code> returns ab而不是 a:

给定以下字符串:

ab
cd

使用 regex (a\Kb)|(c\Kd) 我希望组 </code> 包含 <code>b,组 </code> 包含 <code>d,但是情况并非如此,如下所示:

我试过了Wiktor Stribiżew's answer that points to using a branch reset group:

(?|a\Kb)|(?|c\Kd)

产生:

但是,现在比赛都是组 [=33=] 的一部分,而我要求它们分别属于组 </code> 和 <code>。您对如何实现这一目标有任何想法吗?我正在使用 Oniguruma regular expressions and the PCRE 口味。


根据以下评论更新。

上面的示例旨在易于理解和重现。 @Booboo 指出 非捕获组 可以解决问题,即:

(?:a\K(b))|(?:c\K(d))

产生输出:

然而,当应用于另一个例子时它失败了。因此,为了清楚起见,我将这个问题扩展到涵盖评论中讨论的更复杂的场景。

假设我在 markdown 文件中有以下文本:

- [x] Example task. | Task ends. [x] Another task.
- [x] ! Example task. | This ends. [x] ! Another task.

This is a sentence. [x] Task is here.
Other text. Another [x] ! Task is here.

|       | Task name     |    Plan     |   Actual    |      File      |
| :---- | :-------------| :---------: | :---------: | :------------: |
| [x]   | Task example. | 08:00-08:45 | 08:00-09:00 |  [[task-one]]  |
| [x] ! | Task example. | 08:00-08:45 | 08:00-09:00 |  [[task-one]]  |

我对带有 两个捕获组 的单个 regex 表达式感兴趣,如下所示:

  • </code>(即,见下面的选择):</p> <ul> <li><p>在table之外:捕获<code>[x] !之后的所有内容,直到|

  • 在 table 内:捕获 [x] ! 之后的所有内容,不包括 | 符号

  • 我有以下 regex(即 see demo here)在单独评估时有效,但在捕获组内使用时无效:

  • </code>: <ul> <li>table外:<code>[^\|\s]\s*\[x\]\s*\!\s*\K[^|\n]*
  • 在table里面:(?:\G(?!\A)\||(?<=\[x]\s)\s*\!\s*\|)\K[^|\n]*(?=\|)
  • 我遇到的问题是在组合上面的表达式时。

    regex:

    ([x] outside|[x] inside)|([x] ! outside|[x] ! inside)
    

    实际regex:

    ([^\|\s]\s*\[x\]\s*\K[^!|\n]*|(?:\G(?!\A)\||(?<=\[x]\s)\s*\|)\K[^|\n]*(?=\|))|([^\|\s]\s*\[x\]\s*\!\s*\K[^|\n]*|(?:\G(?!\A)\||(?<=\[x]\s)\s*\!\s*\|)\K[^|\n]*(?=\|))
    

    产生(即,如 demo linked above):

    table 内匹配的 regex 基于 Wiktor Stribiżew's answer and

    如果我了解您要匹配的内容,请用作正则表达式:

    (?:[^|\s]\s*\[x\](?!\s*!)\s*\K([^!|\n]*))|(?:[^|\s]\s*\[x\]\s*!\s*\K([^|\n]*))
    

    Regex Demo

    我删除了一些不必要的转义。但此外:

    对于 | 之前的第 1 组匹配(第一个备选方案),请注意,在我们匹配“[x]”之后,我有以下否定先行断言:

    (?!\s*!)
    

    这可确保 [x] 后不跟 0 个或多个空格后跟感叹号。只有这样,您才希望将下一个感叹号或换行符之前的所有内容都匹配为第 1 组。

    而不是\K,尝试使用控制动词(*SKIP)(*F):

    (a(*SKIP)(*F)|b)|(c(*SKIP)(*F)|d)
    

    检查test case

    以您在 regex101 上提供的示例为例,可以尝试使用以下表达式,但需要注意的是,文本不应包含除“[x]”以外的任何第三个括号

    (?<!\|\s)(((?:\[x]\s[!]?))\K[^[\n]+)
    

    解释以上内容

    1. (?<!\|\s)
    • 如您所述
    • ,这种否定前瞻将丢弃 table
    1. (?:[x]\s[!]?)
    • 这是一个非捕获组,将匹配“[x]”或“[x]!”
    1. \K (Optional)
    • \K 重置报告匹配的起点。任何先前消耗的字符不再包含在最终匹配中
    1. [^[\n]+
    • 在一次和无限次之间否定匹配前一个标记。

    Regex101 sample

    你可以使用

    (?|(?:\G(?!\A)(?<=\|)|^\|\h*\[x\]\h*\|)\h*\K([^|\n]+)(?<=\S)\h*\||\[x]\h*\K([^|\s!]+(?:\h*[^|\s]+)*))|(?|(?:\G(?!\A)\||^\|\h*\[x]\h*!\h*\|)\h*\K([^|\n]+)(?<=\S)\h*|\[x]\h*!\h*\K([^|\s]+(?:\h*[^|\s]+)*))
    

    regex demo详情:

    • (?|(?:\G(?!\A)(?<=\|)|^\|\h*\[x\]\h*\|)\h*\K([^|\n]+)(?<=\S)\h*\||\[x]\h*\K([^|\s!]+(?:\h*[^|\s]+)*)) - 分支重置组匹配:

      • (?:\G(?!\A)(?<=\|)|^\|\h*\[x\]\h*\|) - 非捕获组匹配
        • \G(?!\A)(?<=\|) - 前一个成功匹配的结尾紧接 | char
      • | - 或者
        • ^\|\h*\[x\]\h*\| - line/string、| 的开始,零个或多个水平空格,[x],零个或多个水平空格,|
      • \h*\K - 匹配后立即从匹配值中丢弃的零个或多个水平空格
      • ([^|\n]+)(?<=\S) - 第 1 组:除 LF 和 | 之外的一个或多个字符,尽可能多,但块应与非空白字符匹配
      • \h*\| - 零个或多个水平空格和一个 | 字符
    • | - 或

      • \[x]\h*\K - [x],零个或多个水平空格,此文本从匹配值中丢弃
      • ([^|\s!]+(?:\h*[^|\s]+)*) - 第 1 组(注意它是一个分支重置组):除 !| 和空格之外的一个或多个字符,然后出现零次或多次零个或多个水平空格,然后是 | 和空格
      • 以外的一个或多个字符
    • | - 或

    • (?|(?:\G(?!\A)\||^\|\h*\[x]\h*!\h*\|)\h*\K([^|\n]+)(?<=\S)\h*|\[x]\h*!\h*\K([^|\s]+(?:\h*[^|\s]+)*)) - 分支重置组:

      • (?:\G(?!\A)\||^\|\h*\[x]\h*!\h*\|) - 上一个成功匹配的结尾和后面的 | 个字符,或字符串的开头,|,零个或多个水平空格,[x]! 包含零个或多个水平空格,一个 | 字符
      • \h*\K - 零个或多个水平空格和到目前为止匹配的整个文本从匹配值中丢弃
      • ([^|\n]+)(?<=\S) - 第 2 组:除 LF 和 | 以非空白字符结尾的任何一个或多个字符
      • \h* - 零个或多个水平空格
    • | - 或

      • \[x] - [x] 字符串
      • \h*!\h*\K - ! 包含零个或多个水平空格,并且到目前为止匹配的整个文本将从匹配值中丢弃
      • ([^|\s]+(?:\h*[^|\s]+)*) - 第 2 组(请注意它是一个分支重置组):除 | 和空格之外的一个或多个字符,然后零个或多个出现零个或多个水平空格和然后是 | 和空格以外的一个或多个字符。