【问题标题】:Continue scanning a string until it has found the first/last occurrence of a string继续扫描字符串,直到找到第一次/最后一次出现的字符串
【发布时间】:2016-03-21 09:49:25
【问题描述】:

我想使用正则表达式扫描这行文本。

axhaweacb

我想将文本从“a”转换为“b”。这是我目前的模式:

pattern = "a.*?b";

当前输出是:axhaweacb(它包含 a 和 b 之间的所有内容),但我想要返回的是“acb”。

为什么你会问?我试图应用的逻辑/正则表达式是: 当您找到第一次出现“from”正则表达式(“a”)时,开始扫描。如果您发现另一个“发件人”字母出现而没有找到字母的“最后一个”出现 - 在本例中为“b”,请删除前一个字符串 - 这是axh,以便字符串变为:aweacb。如果您发现另一个出现的“来自” - 在这种情况下是 a,而没有找到“到” - b。删除之前的字符串,使其变为acb。然后重新开始扫描。在这种情况下,我们找到了我们的模式 - a 到 b,没有另一个“a”挡住我们的路。

我知道我可以从字符串开始,并删除所有内容,直到最后一次出现“a” - 但我也想将它重用于不同的字符串。在这种情况下,它总是会在最后一次出现之前对所有内容进行子串化 - 这会导致删除大量数据。

我希望我把我的问题/问题说清楚了。如果没有,请告诉我,我会尽力澄清我的问题。

谢谢。

【问题讨论】:

  • 你知道你的字符串总是3个字符长吗?在这种情况下,您似乎可以使用模式"a.b"。我不知道它是否可以推广到你的其他字符串,但你可以考虑一下。

标签: java regex string computer-science


【解决方案1】:

正则表达式引擎从左到右搜索匹配项。当它找到aa.*?b 时,它是字符串中的第一个a。然后,找到并匹配的第一个 baxhaweacb 字符串中的最后一个字符。

惰性量词匹配到与后续子模式匹配的最接近的最右侧字符,而不是可能的最短子字符串。

因此,您需要一种方法来排除(如果找到则=失败)所有出现在它们之间的前导子模式。

这可以在tempered greedy token的帮助下完成:

pattern = "a(?:(?!a|b).)*b";
            ^^^^^^^^^^^^^

这是demo

【讨论】:

  • 仅供参考,如果您的输入中有换行符,您还需要指定 DOTALL 修饰符,以便 . 可以匹配换行符。
【解决方案2】:

您可以使用这个基于负前瞻的正则表达式:

a(?:(?![ab]).)*b
  • (?![ab]) 是匹配除 a 和 b 之外的任何内容的负正则表达式`
  • (?:(?![ab]).)* 匹配 0 个或多个不是 a 和 b, thus giving us shortest match betweenaandb`的任何字符。

RegEx Demo

【讨论】:

  • 谢谢。它正在工作。但是,如果我想为不同的字符串重用这个正则表达式而不必每次都更改正则表达式,我该怎么办。例如,尝试用这个正则表达式匹配“我的名字是杰克”: name(?:(?![namejack]).)*jack 。这将返回“名字是杰克”。但是当我尝试: my(?:(?![myjack]).)*jack 匹配整个字符串时 - 它什么也不返回。知道为什么吗?
  • [...] 内不能使用多字符串。您可以使用:\bname\b(?:(?!\b(name|jack)\b).)*\bjack\b
猜你喜欢
  • 2020-10-25
  • 2021-06-11
  • 1970-01-01
  • 2022-01-13
  • 1970-01-01
  • 2018-02-05
  • 1970-01-01
  • 1970-01-01
  • 2014-12-12
相关资源
最近更新 更多