正则表达式匹配单词的第一个实例,但仅当前面有来自另一个模式的匹配项时

regex to match first instance of a word but only when preceeded by match from another pattern

我找到了一些关于在字符串中查找某个单词的第一个实例的信息,但我试图仅当它是前面有一些非常具体的文本(用下划线分隔的 IP 地址),这些文本略有不同。此外,这些词由下划线分隔,因此出于某种原因 \b 对我不起作用。

这里有一些示例字符串可以针对一次一行进行测试。只应匹配粗体字词。

在第二次调用中,我想匹配这些字符串中的不同单词。

我的正则表达式风格是 POSIX 正则表达式(适用于 PostgreSQL 9.4)。到目前为止,我已经能够 运行 使用这里 http://regexpal.com/ 中的任何东西。

即使它不能一次解决所有 3 个示例,如果它能只解决前两个,那将非常有帮助。

编辑:明确地说,我的意图是用字符 'c' 替换第一个字符串 'card',然后用字母 [=] 替换第一个字符串 'port' 53=] 而不影响任何没有紧跟数字的 'card' 或 'port' 实例。这就是为什么我的比赛需要只包括那些没有相应数字的第一个单词。

如果可以使用负先行,则可以使用 card((?!port).)*port 将字符串与卡匹配,而不是后面没有端口的任意数量的字符,然后再次卡。

编辑:

如果输入始终采用相同的格式,那么您可以使用 card[0-9]{1,2}_port 更加具体。这将防止它匹配卡和端口的任何其他无关实例

编辑 2:

要仅匹配第一种情况下的单词,您可以使用正向先行:card(?=[0-9]{1,2}_port)。我不确定您的口味是否允许正面回顾(测试人员没有,但这是在 js 中),但请 (?<=card[0-9]{1,2}_)port 试一试。如果正面回顾不起作用,您可能需要研究替代方案。

\b 断言在这种情况下不起作用,因为 _ 被视为单词字符。

Demo

你可以用回头看看:

(?<=_)(card).*?(?<=_)(port)

Demo

更具体地说,使用 IP 地址模式:

(^(?:\d+_){4})(card\d+)_(port\d+)

Demo

我不得不分两步解决这个问题。首先,我只匹配开头带有 IP 字符串的行(这不包括像我的第 3 个示例那样的行)。在第二步中,我使用 regexp_replace 来替换每个单词的第一个匹配项。

不幸的是,我完全错过了 regexp_replace 仅替换第一个匹配项的事实,除非用 'g' 标志另有说明:

WHEN (SELECT regexp_matches(mystring, '^1(?:[0-9]{1,3}_){4}card[0-9]{1,2}_port[0-9]{1,2}')) IS NOT NULL
  THEN regexp_replace(regexp_replace(mystring, 'card', 'c'), 'port', 'p')

虽然我仍然希望我能弄清楚如何在单个表达式中匹配其中一个单词,但我会接受任何可以实现这一点的答案。