【问题标题】:Regex to get the last match of a pattern正则表达式获取模式的最后一个匹配项
【发布时间】:2020-10-27 15:53:12
【问题描述】:

这是一个类似于我要匹配的字符串(为了简单起见,除了几个特定的​​模式)。 Hello, tonight I'm in the town of Trenton in New Jersey and I will be staying in Hotel HomeStay [123] and I have no money.

我正在尝试仅匹配最后一个 in Hotel HomeStay [123]。

我现在对前瞻和后瞻等正则表达式概念不太熟悉。这里的类似问题似乎无法解决我的问题。我尝试了一堆正则表达式(据我所知),这就是我想出的(?= (?:in|\d+))([\w \[]*\s*\d*\]*)(?!.*in)。数字和特殊字符可能是我实际尝试匹配的部分。

lookahead 和lookbehind 模式不限于仅包含in。它们也可以有更多常用词,例如and 和is。我只是在寻找其中任何一个的最后一次出现,然后是非常独特的主要模式 - edit 假设匹配必须包含HomeStay 或LuxuryInn,为了这个例子。

但是,这匹配整个in the town of Trenton in New Jersey and I will be staying in Hotel HomeStay [123]。 我哪里错了?另外,有人可以解释为什么 in 尽管被置于非捕获组中,但仍被捕获?

非常感谢任何帮助。

【问题讨论】:

  • 正则表达式无法实现您想要实现的目标。对不起!
  • @Ava 哦,那真是太糟糕了。如果有帮助,我编辑了我的原始帖子以添加更多细节。是否有任何其他工具可以用于此目的?

标签: regex regex-lookarounds regex-group


【解决方案1】:

如果您想检索包含HomeStay 并以某些单词为前缀但不包含这些单词的文本,您可以使用内部使用否定前瞻的捕获组。下面的正则表达式捕获所有出现 (working fiddle)。

\b(?:in|and|is)\s+((?:.(?!\b(?:in|and|is)\b))*HomeStay(?:.(?!\b(?:in|and|is)\b))*)

这里,正则表达式查找:

  • 给定前缀(in、and 或 is 作为一个整个单词,被分词符包围\b)
  • ...后跟至少一个空白字符,
  • ...然后是0个或多个字符的序列每个字符后面都没有前缀,
  • ...后跟HomeStay,
  • ... 后面跟着另一个 0 或多个字符的序列,每个字符后面都没有前缀

如果您只想要最后一次出现,您可以在 (fiddle) 之后添加另一个负前瞻。

\b(?:in|and|is)\s+((?:.(?!\b(?:in|and|is)\b))*HomeStay(?:.(?!\b(?:in|and|is)\b))*)(?!.*HomeStay.*)

同上,除了匹配的文本后面不能有包含HomeStay的文本。

最后,如果匹配文本必须至少包含列表中的一个单词,只需将两个出现的HomeStay 替换为替代列表即可。寄宿家庭和豪华住宿示例:(?:HomeStay|Luxury) (fiddle)。

【讨论】:

  • 基本上,我想要这些条件匹配的最小子字符串。立即以“in”为前缀,并包含“HomeStay”。所以我想我想要前者:最后一次出现以“in”为前缀的文本,它必须包含 HomeStay。
  • 这是我一直在寻找的答案。非常感谢!
【解决方案2】:

在java中:

String s = "Hello, tonight I'm in the town of Trenton in New Jersey and I will be "
           + "staying in Hotel HomeStay [123] and I have no money.";
// Garbage: final String SUBP = "\\bin\\s+(\\S+)";
Pattern p = Pattern.compile("^.*\\sin\\s+(\\S+).*$", Pattern.DOTALL);
String last = p.matcher(s).replaceFirst("$1"); // If found

这将找到last“... in ...”,因为.*(而不是急切的.*?)会寻找最长的序列。

上面的结果将是Hotel(in 之后的非空格)但它可能是任何东西。


  • Dot-All 将使. 也匹配换行符。
  • 该模式将从^ 开始到$ 结束。
  • 任何字符.*(最长)后跟一个空格字符\s。
  • 然后是“in”,然后是组 1 中的一个单词(非空格 \S+)(...)
  • 然后是直到结尾的任何字符.*。为了纯度,最短序列应该是.*?。
  • 结局$.

【讨论】:

  • 你能详细解释一下吗?特别是字符串SUBP的用途?
  • 我的第一个想法是使用(.*" + SUBP + ").**(" + SUBP + ")" 创建一个重复模式,因此 $2 是所需的正则表达式组。现在它是我应该删除的垃圾。
  • 我明白了。我试过了,虽然它适用于匹配“Hotel”的特殊情况,但只要我包含一个空格来捕获多个单词,它还会包含“and ...”直到句子的结尾,这我试图避免。有没有办法做到这一点?
  • 如果你有一个这样的词列表,可以使用否定前瞻/后瞻。您还可以使用 ``(\\S+(\\s+\\S){0-3})` 限制单词的数量。由于这样的正则表达式很容易变得不可读,因此也应该考虑对其进行编码 - 可能更快。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-01
  • 1970-01-01
  • 2017-03-31
  • 1970-01-01
  • 2016-08-30
  • 1970-01-01
相关资源
最近更新 更多