正则表达式获取模式的最后一个匹配项

Regex to get the last match of a pattern

这是一个类似于我要匹配的字符串(为简单起见,除了几个特定模式外)。 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)。数字和特殊字符可能是我实际尝试匹配的部分内容。

前瞻和后视模式不限于仅包含 in。他们也可以有更常用的词,例如 andis。我只是在寻找其中任何一个的最后一次出现,然后是非常独特的主要模式 - edit 假设匹配项必须包含 HomeStayLuxuryInn,为了示例。

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

非常感谢任何帮助。

在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(""); // If found

这将查找 last“...在...”,因为 .*(而不是热切的 .*?)将查找最长的序列。

上面的结果将是 Hotelin 之后没有空格)但它可以是任何东西。


  • Dot-All 会影响 . 也匹配换行符。
  • 模式将从开头 ^ 到结尾 $
  • 任意字符 .*(最长)后跟空白字符 \s
  • 然后是“in”,然后是组 1 中的一个词 (non-spaces \S+) (...)
  • 然后是任何字符直到结束 .*。对于纯度,最短序列应该是 .*?
  • 结束$.

如果要检索包含 HomeStay 并以某些词为前缀但不包含这些词的文本,可以使用内部使用否定 look-ahead 的捕获组。下面的正则表达式捕获了所有事件 (working fiddle).

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

在这里,正则表达式查找:

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

如果你只想要最后一次出现,你可以在 (fiddle).

之后添加另一个否定 look-ahead
\b(?:in|and|is)\s+((?:.(?!\b(?:in|and|is)\b))*HomeStay(?:.(?!\b(?:in|and|is)\b))*)(?!.*HomeStay.*)

与上面相同,只是匹配的文本后面不能跟包含 HomeStay.

的文本

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