【问题标题】:Regex - Get string between two words that doesn't contain word正则表达式 - 获取两个不包含单词的单词之间的字符串
【发布时间】:2011-09-07 11:33:26
【问题描述】:

我一直在环顾四周,但无法做到这一点。我不完全是菜鸟。

我需要获取由(包括)START 和 END 分隔但不包含 START 的文本。基本上我找不到不使用高级东西来否定整个单词的方法。

示例字符串:

abcSTARTabcSTARTabcENDabc

预期结果:

STARTabcEND

不好:

STARTabcSTARTabcEND

我不能使用向后搜索的东西。我在这里测试我的正则表达式:www.regextester.com

感谢您的建议。

【问题讨论】:

  • 如果文本是abcSTARTabcENDabcSTARTabcENDabc怎么办?你想要两场比赛吗?
  • 没想到……反正如果需要我可以找到第二场比赛。
  • 最好在单个正则表达式中执行此操作。我已经添加了答案。
  • 你可以在rubular.com测试你的正则表达式

标签: regex search word jmeter


【解决方案1】:

试试这个

START(?!.*START).*?END

here online on Regexr

(?!.*START) 是负前瞻。它确保单词“START”没有跟随

.*? 是所有字符的非贪婪匹配,直到下一个“END”。它是必需的,因为负前瞻只是向前看而不捕获任何东西(零长度断言)

更新:

我想多了,上面的解决方案匹配到第一个“END”。如果不需要(因为您从内容中排除了 START),请使用贪婪版本

START(?!.*START).*END

这将匹配到最后一个“END”。

【讨论】:

  • +1 得到很好的答案,所有运算符的简单解释
  • 如果字符串中有多个START...END 对,这将失败。 (或者更准确地说,它只会在字符串中找到最后一个 START...END 对。)
  • 澄清蒂姆的评论:如果有 ANY 第二次出现START,则您的正则表达式将与您期望的不匹配,无论是 之前之后 END(例如abcSTARTabcENDxyzSTART 将不匹配)
  • 是的,它只是询问将来是否有任何 start 出现,如果有,则不匹配。这不是想要的(描述的)行为。
【解决方案2】:
START(?:(?!START).)*END

适用于任意数量的START...END 对。用 Python 演示:

>>> import re
>>> a = "abcSTARTdefENDghiSTARTjlkENDopqSTARTrstSTARTuvwENDxyz"
>>> re.findall(r"START(?:(?!START).)*END", a)
['STARTdefEND', 'STARTjlkEND', 'STARTuvwEND']

如果您只关心STARTEND 之间的内容,请使用:

(?<=START)(?:(?!START).)*(?=END)

看这里:

>>> re.findall(r"(?<=START)(?:(?!START).)*(?=END)", a)
['def', 'jlk', 'uvw']

【讨论】:

  • 是的,这样就可以了。 +1(尽管您可能想提及/使用s dot-matches-all 标志。)
【解决方案3】:

真正简单的解决方案是START(([^S]|S*S[^ST]|ST[^A]|STA[^R]|STAR[^T])*(S(T(AR?)?)?)?)END。现代正则表达式风格有负面断言,可以更优雅地执行此操作,但我将您关于“向后搜索”的评论解释为可能意味着您不能或不想使用此功能。

更新:为了完整起见,请注意,上述内容对于结束分隔符是贪婪的。要仅捕获可能的最短字符串,请将否定扩展到也覆盖结束分隔符 -- START(([^ES]|E*E[^ENS]|EN[^DS]|S*S[^STE]|ST[^AE]|STA[^RE]|STAR[^TE])*(S(T(AR?)?)?|EN?)?)END。不过,这有可能超过大多数文化中的酷刑门槛。

错误修复:此答案的先前版本存在错误,因为 SSTART 可能是匹配的一部分(第二个 S 将匹配 [^T] 等)。我解决了这个问题,但通过在[^ST] 中添加S 并在非可选S 之前添加S* 以允许S 的任意重复,否则。

【讨论】:

  • 不错的解决方案(如果没有前瞻可能)+1
  • 这就是我想要的,谢谢。确实......行人:)但它有效。我希望可能有一种我想念的更简单的方法。很抱歉没有早点回帖。
  • 最后一部分是干什么用的?为什么需要(S(T(AR?)?)?)?
  • 好的!我明白了......你需要...(S(T(AR?)?)?)?...,否则你必须在SSTSTASTAR之后使用字符......这真是个天才。
  • 不确定你的意思。在 END 分隔符之前允许 START 的子字符串,并且我们一直在阻止这些子字符串匹配。
【解决方案4】:

我可以建议对 Tim Pietzcker 的解决方案进行改进吗? 在我看来,START(?:(?!START).)*?END 更好,以便只捕获 START 紧随其后的 END 而没有任何 STARTEND 。我正在使用.NET,Tim 的解决方案也可以匹配START END END。至少在我个人的情况下,这是不想要的。

【讨论】:

    【解决方案5】:

    [编辑:我留下这篇文章是为了获取有关捕获组的信息,但我给出的主要解决方案不正确。 (?:START)((?:[^S]|S[^T]|ST[^A]|STA[^R]|STAR[^T])*)(?:END) 正如 cmets 中指出的那样,它不起作用;我忘记了不能删除被忽略的字符,因此您需要诸如 ...|STA(?![^R])| 之类的东西来仍然允许该字符成为 END 的一部分,从而在诸如 STARTSTAEND 之类的东西上失败;所以这显然是一个更好的选择;以下应该显示使用捕获组的正确方法...]

    使用带有捕获组的“零宽度负前瞻”运算符“?!”给出的答案是:(?:START)((?!.*START).*)(?:END),它使用 $1 捕获内部文本进行替换。如果您想捕获 START 和 END 标签,您可以执行 (START)((?!.*START).*)(END),它通过添加/删除 ()s 或 ?:s 给出 $1=START $2=text 和 $3=END 或各种其他排列。

    这样,如果您使用它进行搜索和替换,您可以执行类似 BEGIN$1FINISH 的操作。所以,如果你开始:

    abcSTARTdefSTARTghiENDjkl

    您将获得 ghi 作为捕获组 1,替换为 BEGIN$1FINISH 将为您提供以下信息:

    abcSTARTdefBEGINghiFINISHjkl

    这将允许您仅在正确配对时更改您的 START/END 令牌。

    每个(x) 都是一个组,但我已经为每个组添加了(?:x),除了中间标记为非捕获组;我留下的唯一一个没有?: 的是中间;但是,如果您想移动它们或您有什么,您也可以捕获 BEGIN/END 令牌。

    有关 Java 正则表达式的完整详细信息,请参阅 Java regex documentation

    【讨论】:

    • 你在 STARTSTAEND 模式上失败了。
    • @tripleee 叹息,是的,确实,我需要用 ?!这有点违背了整个目的。谢谢你指出。
    猜你喜欢
    • 1970-01-01
    • 2020-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多