【问题标题】:How to exclude occurrences after a positive lookbehind?如何在积极的回顾后排除事件?
【发布时间】:2022-01-10 01:29:42
【问题描述】:

假设我有以下markdown 列表项:

- [x] Example of a completed task.
- [x] ! Example of a completed task.
- [x] ? Example of a completed task.

我有兴趣使用 regex 解析该项目并提取以下组捕获:

  • $1:当符号 x 介于两者之间时,左边的 [ 和右边的 ] 括号
  • $2:括号 [] 之间的符号 x
  • $3! 之后的修饰符 [x]
  • $4:在[x] 之后的修饰符?
  • $5[x] 后面没有修饰符的文本,例如 [x] This is targeted.
  • $6[x] ! 后面的文字
  • $7[x] ? 后面的文字

在使用在线解析器进行大量试验和错误之后,我想出了以下内容:

((?<=x)\]|\[(?=x]))|((?<=\[)x(?=\]))|((?<=\[x\]\s)!(?=\s))|((?<=\[x\]\s)\?(?=\s))|((?<=\[x\]\s)[^!?].*)|((?<=\[x\]\s!\s).*)|((?<=\[x\]\s\?\s).*)

为了使上面的regex 更具可读性,这些捕获组一一列出:

  • $1((?&lt;=x)\]|\[(?=x]))
  • $2: ((?&lt;=\[)x(?=\]))
  • $3: ((?&lt;=\[x\]\s)!(?=\s))
  • $4: ((?&lt;=\[x\]\s)\?(?=\s))
  • $5: ((?&lt;=\[x\]\s)[^!?].*)
  • $6: ((?&lt;=\[x\]\s!\s).*)
  • $7: ((?&lt;=\[x\]\s\?\s).*)

这很可能不是最好的方法,但至少它似乎捕捉到了我想要的:

我想扩展 regex 以捕获 markdown 表中的行 看起来像这样:

|       | Task name                               |    Plan     |   Actual    |      File      |
| :---- | :-------------------------------------- | :---------: | :---------: | :------------: |
| [x]   | Task one with a reasonably long name.   | 08:00-08:45 | 08:00-09:00 |  [[task-one]]  |
| [x] ! | Task two with a reasonably long name.   | 09:00-09:30 |             |  [[task-two]]  |
| [x] ? | Task three with a reasonably long name. | 11:00-13:00 |             | [[task-three]] |

更具体地说,我有兴趣拥有与上述相同的组捕获,但我想排除表格网格(即|)。因此,$1$4 组应该保持不变,但 $5$7 组应该捕获文本,不包括 |,例如,如下面的选择:

您对我如何调整有任何想法,例如,组$5 的正则表达式以排除|。我无休止地尝试了各种否定(例如,[^\|])。我正在使用Oniguruma regular expressions

【问题讨论】:

  • 要获取列值,您可以:regex101.com/r/kRIonQ/1(正则表达式:((?&lt;=\|)[^|]*)
  • "但是 $5$7 的组应该捕获文本,不包括 |" - 我认为捕获组不可能由以下序列组成不连续的字符。最好将这些捕获为额外的单独组或捕获后的后处理。
  • @DeanTaylor,我想你已经非常清楚地表达了我想要做的事情,即从一系列不连续的字符中创建一个捕获组。不幸的是,我无法进行任何后期处理,因为上面的 regex 是 VSCode 中语法注入的一部分。
  • @Luuk,这看起来很有趣。如果我理解正确,您可以在排除| 的同时创建一个组。我会玩弄它的。
  • 如果您使用的是打开文档搜索和替换功能中使用的正则表达式引擎,请尝试((?&lt;=x)\]|\[(?=x]))|((?&lt;=\[)x(?=\]))|((?&lt;=\[x\]\s)!(?=\s))|(?&lt;=\[x\]\s)(\?)(?=\s)|(?&lt;=x].*?\|)(.*?)(?=\|)。见regex101.com/r/XBFkp2/2

标签: regex visual-studio-code syntax-highlighting regex-group


【解决方案1】:

Wiktor 的回答启发,检查下面的正则表达式,它很短

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

上面的解释

1.\G(?!\A)\|

\G 在前一个匹配的结尾或第一个匹配的字符串的开头断言位置。负向回溯 (?!\A)

  1. \A 断言字符串开头的位置
  2. |匹配字符 |
  1. (?:\[x]\s[?!]?\s*\|?)

非捕获组。匹配 [x]、\s(空格)、[?|!](零或 1)后跟 \s*(零或更多)和 | (零或一)

  1. \K

\K 重置报告匹配的起点。

  1. ([^|\n]*)

所有字符除了 |或 \n(换行符)匹配前一个标记零次或无限次。

【讨论】:

  • 感谢您的建议!使用您指定的表达式,第一个 | 被省略,但后续的不是。例如,在| [x] | Task one with a reasonably long name. | 08:00-08:45 | 08:00-09:00 | [[task-one]] | 这种形式的构造中,我希望将除[x]| 之外的所有其他组匹配为一个组,同时保留我在上述问题中指出的其他组。
  • 对不起,这不是我要找的。我有兴趣维护所有七个组捕获。使用您提到的regex,我只得到一个incorrect 组捕获,如下所示:regex101.com/r/NOuTOb/1
  • 也许我弄错了你的要求。最后澄清一下
  • 更新答案,可在regex101.com/r/5OaZc0/1查看
  • 感谢您提出的好问题以及@Wiktor。有很多东西要学习
【解决方案2】:

你可以使用

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

查看regex101 PCRERuby (Onigmo/Oniguruma) demos

添加了什么?(?:\G(?!\A)\||(?&lt;=\[x]\s[?!\s]\s\|))\K([^|\n]*)(?=\|)部分:

  • (?: - 非捕获组的开始(此处为自定义边界,我们将匹配...)
    • \G(?!\A)\| - 上一场比赛的结束和一个| 字符(即| 必须紧跟上一场比赛),
    • |(?&lt;=\[x]\s[?!\s]\s\|) - 或紧跟在 [x] 前面的位置 + 空格 + ?! 或空格 + 空格和 | 字符
  • ) - 小组结束
  • \K - 匹配重置运算符,用于从整体匹配内存缓冲区中删除到目前为止匹配的文本
  • ([^|\n]*) - 除了| 和换行符之外的零个或多个字符
  • (?=\|) - | 字符必须立即出现在当前位置的右侧。

【讨论】:

  • 我正在彻底研究您的解决方案,并将报告!
  • 我花了一段时间才了解\G\A\K,但我可以确认这非常有效。唯一的问题是,当我尝试创建我的捕获组时,\K 似乎被忽略了。例如,尝试匹配b 并将其捕获为组@98​​7654346@(即,不是$0)在字符串ab 中使用regex (a\Kb) 将匹配ab
  • @Mihai \K 只影响“整体匹配内存缓冲区”,不影响捕获的文本。
  • 我对此感到非常困惑,最后在这里提出了一个后续问题(即stackoverflow.com/q/70237510/5252007)。我的想法是我想在捕获组中使用您的解决方案,事情变得有点难以理解……您帮了很多忙,我可以强调我是多么感激它。
猜你喜欢
  • 2020-06-11
  • 1970-01-01
  • 2021-01-25
  • 1970-01-01
  • 1970-01-01
  • 2021-07-24
  • 2021-01-12
  • 2016-07-10
  • 1970-01-01
相关资源
最近更新 更多