【问题标题】:Regex to capture everything after optional token正则表达式捕获可选令牌之后的所有内容
【发布时间】:2020-07-10 00:17:32
【问题描述】:

我的字段包含以下可能格式的数据(每行都有不同的可能性):

AAA - Something Here  
AAA - Something Here - D  
Something Here 

请注意,第一组字母 (AAA) 可以有不同的长度。

我试图捕捉的是使用 PCRE 的“这里的东西”或“这里的东西 - D”(如果存在),但我无法让正则表达式在所有三种情况下都正常工作。我试过了:

- (.*) 适用于案例 1 和 2,但显然不适用于案例 3;

(?<= - )(.*) 也适用于案例 1 和 2;

(?! - )(.+)| - (.+) 适用于案例 2 和 3,但不适用于案例 1。

我觉得我快要完成了,但我似乎无法破解它。

提前感谢您的帮助。

编辑:我意识到我的要求不清楚。如果后面有“-D”(数据中的字母是任意的,但应该只是单个字符),也需要捕获。

【问题讨论】:

  • “Something Here”可以包含“-”吗?
  • @Sweeper - 是的,我意识到这是要求的一部分。基本上无论第二个连字符是否存在,它都必须捕获第一个连字符(如果存在)的所有内容。我已经编辑了我的问题。

标签: regex pcre


【解决方案1】:

关于您尝试过的模式:

  • - (.*)此模式将匹配第一次出现的 - ,然后匹配该行的其余部分。它将与第二个示例匹配太多,因为 .* 也将匹配 - 的第二次出现
  • (?<= - )(.*)此模式将与没有 - 的第一个示例匹配,因为它断言应该直接出现在左侧
  • (?! - )(.+)| - (.+) 此模式使用负前瞻,它断言直接在右侧的不是(?! - )。由于没有一个示例以 - 开头,因此整行将直接在由于.+ 而导致的负前瞻之后匹配,并且不会评估替换| 之后的第二部分

如果第一组字母可以有不同的长度,您可以使匹配特定匹配 1 个或多个大写字符 [A-Z]+ 或 1+ 个单词字符 \w+

要获得更广泛的匹配,您可以使用 \S+ 匹配 1 个或多个非空白字符

^(?:\S+\h-\h)?\K\S+(?:\h(?!-\h)\S+)*

说明

  • ^ 字符串开始
  • (?:\S+\h-\h)? 可以选择匹配第一组非空白字符,然后在水平空白字符之间匹配-
  • \K清除匹配缓冲区(忘记当前匹配的内容)
  • \S+ 匹配 1+ 个非空白字符
  • (?:非捕获组
    • \h(?!-\h) 匹配一个水平空白字符并断言右边不是- 后跟另一个水平空白字符
    • \S+ 匹配 1+ 个非空白字符
  • )*关闭非捕获组并重复1+次以匹配更多以空格分隔的“单词”

Regex demo

编辑

要匹配可选的连字符和尾随单个字符,您可以添加可选的非捕获组(?:-\h\S\h*)?$,如果模式应该匹配整个字符串,则断言字符串的结尾:

^(?:\S+\h-\h)?\K\S+(?:\h(?!-\h)\S+)*\h*(?:-\h\S\h*)?$
                                       

Regex demo

【讨论】:

  • 这是一个了不起的答案,我很欣赏我使用的那些不起作用的原因;特别是第三个,因为我无法弄清楚为什么引擎似乎没有评估负前瞻(查看 regex101.com 的调试功能)。不幸的是,我意识到我错过了一个要求 - 如果有一个尾随连字符和字母(第二种情况),那么尾随连字符和字母也必须被捕获。我已经编辑了我的问题。
  • @RyanJ 我添加了一个更新来说明尾随的连字符和字母。如果它应该是一封信,你也可以使用[A-Z]而不是\S
【解决方案2】:

你可以使用

^(?:.*? - )?\K.*?(?= - | *$)
^(?:.*?\h-\h)?\K.*?(?=\h-\h|\h*$)

regex demo

详情

  • ^ - 字符串开头 -(?:.*? - )? - 一个可选的非捕获组,匹配除换行符之外的任何 0+ 字符,直到第一个 space-space
  • \K - 匹配重置运算符
  • .*? - 除换行符以外的任何 0+ 字符尽可能少
  • (?= - | *$) - space-space 或 0+ 个空格直到字符串末尾应紧跟在右侧。

请注意,\h 匹配任何水平空白字符。

【讨论】:

  • 这是一个漂亮的答案和一个很好的解释,但是,我意识到我错过了一个要求。它还必须匹配“Something Here - D”,例如如果尾随连字符 + 字母,则也必须捕获。我已经编辑了我的问题以反映这一点。
  • @RyanJ ^(?:.*? - )?\K.*?(?= - \p{L}$| *$) (demo) / ^(?:.*?\h-\h)?\K.*?(?=\h-\h\p{L}$|\h*$) (demo)?
  • @RyanJ 如果不是您所期望的,请发表评论。
【解决方案3】:
^(?:[A-Z]+ - \K)?.*\S

demo

由于“Something Here” 可以是任何东西,因此没有理由专门描述模式中最终的最后一个字母。你不需要更复杂的东西。

对于这种模式,我假设您对尾随空格不感兴趣,这就是我以\S 结束它的原因。如果要保留它们,请删除 \S 并将之前的量词更改为 +

【讨论】:

  • 这是一个更简单的答案。漂亮。
猜你喜欢
  • 1970-01-01
  • 2011-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-03
  • 2018-12-11
相关资源
最近更新 更多