找到与Java regex matcher的最后一场比赛

我试图获得匹配的最后结果,而不必循环通过.find()

这是我的代码:

String in = "num 123 num 1 num 698 num 19238 num 2134"; Pattern p = Pattern.compile("num '([0-9]+) "); Matcher m = p.matcher(in); if (m.find()) { in = m.group(1); } 

这将给我第一个结果。 我怎样才能找到最后一场比赛,而不是通过潜在的巨大名单?

你可以在你的正则表达式前加上.* ,它将贪婪地消耗所有字符直到最后一个匹配:

 import java.util.regex.*; class Test { public static void main (String[] args) { String in = "num 123 num 1 num 698 num 19238 num 2134"; Pattern p = Pattern.compile(".*num ([0-9]+)"); Matcher m = p.matcher(in); if(m.find()) { System.out.println(m.group(1)); } } } 

打印:

 2134 

您也可以反转字符串以及更改正则表达式以匹配反向字符串:

 import java.util.regex.*; class Test { public static void main (String[] args) { String in = "num 123 num 1 num 698 num 19238 num 2134"; Pattern p = Pattern.compile("([0-9]+) mun"); Matcher m = p.matcher(new StringBuilder(in).reverse()); if(m.find()) { System.out.println(new StringBuilder(m.group(1)).reverse()); } } } 

但是这两种解决方案都不比使用while (m.find()) ,IMO循环遍历所有匹配更好。

要获得最后一场比赛,即使这样也行,并且不确定为什么之前没有提到过:

 String in = "num 123 num 1 num 698 num 19238 num 2134"; Pattern p = Pattern.compile("num '([0-9]+) "); Matcher m = p.matcher(in); if (m.find()) { in= m.group(m.groupCount()); } 

为什么不保持简单?

 in.replaceAll(".*[^\\d](\\d+).*", "$1") 

Java没有提供这样的机制。 我唯一可以建议的是对最后一个索引的二进制搜索。

它会是这样的:

 N = haystack.length(); if ( matcher.find(N/2) ) { recursively try right side else recursively try left side 

编辑

这是代码,因为我发现这是一个有趣的问题:

 import org.junit.Test; import java.util.regex.Matcher; import java.util.regex.Pattern; import static org.junit.Assert.assertEquals; public class RecursiveFind { @Test public void testFindLastIndexOf() { assertEquals(0, findLastIndexOf("abcdddddd", "abc")); assertEquals(1, findLastIndexOf("dabcdddddd", "abc")); assertEquals(4, findLastIndexOf("aaaaabc", "abc")); assertEquals(4, findLastIndexOf("aaaaabc", "a+b")); assertEquals(6, findLastIndexOf("aabcaaabc", "a+b")); assertEquals(2, findLastIndexOf("abcde", "c")); assertEquals(2, findLastIndexOf("abcdef", "c")); assertEquals(2, findLastIndexOf("abcd", "c")); } public static int findLastIndexOf(String haystack, String needle) { return findLastIndexOf(0, haystack.length(), Pattern.compile(needle).matcher(haystack)); } private static int findLastIndexOf(int start, int end, Matcher m) { if ( start > end ) { return -1; } int pivot = ((end-start) / 2) + start; if ( m.find(pivot) ) { //recurse on right side return findLastIndexOfRecurse(end, m); } else if (m.find(start)) { //recurse on left side return findLastIndexOfRecurse(pivot, m); } else { //not found at all between start and end return -1; } } private static int findLastIndexOfRecurse(int end, Matcher m) { int foundIndex = m.start(); int recurseIndex = findLastIndexOf(foundIndex + 1, end, m); if ( recurseIndex == -1 ) { return foundIndex; } else { return recurseIndex; } } } 

我还没有找到破解测试用例。

默认情况下,Java模式是贪婪的,以下应该这样做。

  String in = "num 123 num 1 num 698 num 19238 num 2134"; Pattern p = Pattern.compile( ".*num ([0-9]+).*$" ); Matcher m = p.matcher( in ); if ( m.matches() ) { System.out.println( m.group( 1 )); } 

使用否定前瞻:

 String in = "num 123 num 1 num 698 num 19238 num 2134"; Pattern p = Pattern.compile("num (\\d+)(?!.*num \\d+)"); Matcher m = p.matcher(in); if (m.find()) { in= m.group(1); } 

正则表达式读作“num后跟一个空格和至少一个数字,没有任何数字(num后跟一个空格和至少一个数字)”。

通过将它与积极的观察结合起来,你可以变得更加漂亮:

 String in = "num 123 num 1 num 698 num 19238 num 2134"; Pattern p = Pattern.compile("(?<=num )\\d+(?!.*num \\d+)"); Matcher m = p.matcher(in); if (m.find()) { in = m.group(); } 

那个读作“至少有一个数字前面有(num和一个空格),后面跟着(num后跟一个空格和至少一个数字)”。 这样你就不必Matcher.group(int)分组并担心从Matcher.group(int)引发的潜在IndexOutOfBoundsException

 String in = "num 123 num 1 num 698 num 19238 num 2134"; Pattern p = Pattern.compile("num '([0-9]+) "); Matcher m = p.matcher(in); String result = ""; while (m.find()) { result = m.group(1); } 

正则表达式是贪婪的:

 Matcher m=Pattern.compile(".*num '([0-9]+) ",Pattern.DOTALL).matcher("num 123 num 1 num 698 num 19238 num 2134"); 

将为您提供最后一场比赛的匹配器,您可以通过添加“。*”将其应用于大多数正则表达式。 当然,如果你不能使用DOTALL ,你可能想要使用(?:\d|\D)或类似的通配符。

这看起来似乎更合理。

  public class LastMatchTest { public static void main(String[] args) throws Exception { String target = "num 123 num 1 num 698 num 19238 num 2134"; Pattern regex = Pattern.compile("(?:.*?num.*?(\\d+))+"); Matcher regexMatcher = regex.matcher(target); if (regexMatcher.find()) { System.out.println(regexMatcher.group(1)); } } } 

.*? 是一个不情愿的比赛,所以它不会吞噬一切。 ?:强制非捕获组,因此内部组是组1.以贪婪的方式匹配多个使得它在整个字符串中匹配,直到所有匹配都用尽,使组1具有您的最后一个匹配的值。

与当前接受的答案相比,这个答案不会使用".*"前缀盲目地丢弃列表中的元素。 相反,它使用"(element delimiter)*(element)"来使用.group(2)选出最后一个元素。 请参阅下面的代码中的magic_last函数。

为了certificate这种方法的好处,我还提供了一个函数来挑选第n个元素,该元素足够强大,可以接受少于n个元素的列表。 请参阅下面的代码中的函数magic

过滤掉“num”文本并仅获取该数字作为读者的练习(只需在数字模式周围添加一个额外的组: ([0-9]+)并选择组4而不是组2)。

 package com.example; import static java.lang.System.out; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Foo { public static void main (String [] args) { String element = "num [0-9]+"; String delimiter = ", "; String input; input = "here is a num bro: num 001; hope you like it"; magic_last(input, element, delimiter); magic(1, input, element, delimiter); magic(2, input, element, delimiter); magic(3, input, element, delimiter); input = "here are some nums bro: num 001, num 002, num 003, num 004, num 005, num 006; hope you like them"; magic_last(input, element, delimiter); magic(1, input, element, delimiter); magic(2, input, element, delimiter); magic(3, input, element, delimiter); magic(4, input, element, delimiter); magic(5, input, element, delimiter); magic(6, input, element, delimiter); magic(7, input, element, delimiter); magic(8, input, element, delimiter); } public static void magic_last (String input, String element, String delimiter) { String regexp = "(" + element + delimiter + ")*(" + element + ")"; Pattern pattern = Pattern.compile(regexp); Matcher matcher = pattern.matcher(input); if (matcher.find()) { out.println(matcher.group(2)); } } public static void magic (int n, String input, String element, String delimiter) { String regexp = "(" + element + delimiter + "){0," + (n - 1) + "}(" + element + ")(" + delimiter + element + ")*"; Pattern pattern = Pattern.compile(regexp); Matcher matcher = pattern.matcher(input); if (matcher.find()) { out.println(matcher.group(2)); } } } 

输出:

 num 001 num 001 num 001 num 001 num 006 num 001 num 002 num 003 num 004 num 005 num 006 num 006 num 006