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

时间:2011-06-20 20:59:03

标签: java regex

我试图获得匹配的最后结果,而不必循环通过.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);
}

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

11 个答案:

答案 0 :(得分:17)

您可以将.*添加到正则表达式中,greedily将使用截至上一场比赛的所有字符:

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。

循环所有匹配更好

答案 1 :(得分:14)

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

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());
}

答案 2 :(得分:5)

为什么不保持简单?

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

答案 3 :(得分:3)

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;
        }
    }

}

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

答案 4 :(得分:2)

默认情况下,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 ));
    }

答案 5 :(得分:2)

使用否定前瞻:

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();
}

那个读取为&#34;至少一个数字前面带有(num和一个空格),并且在&#34;之后的任何点都没有跟着(num后跟一个空格和至少一个数字)。 这样你就不必混淆分组并担心IndexOutOfBoundsException引发的潜在Matcher.group(int)

答案 6 :(得分:1)

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);
}

答案 7 :(得分:0)

正则表达式是贪婪的:

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

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

答案 8 :(得分:0)

这似乎是一种更合理的方法。

    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具有您最后一个匹配的值。

答案 9 :(得分:0)

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

为了证明这种方法的好处,我还提供了一个函数来挑选第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

答案 10 :(得分:0)

只需使用\ Z-字符串马赫数的结尾

String in = "num 123 num 1 num 698 num 19238 num 2134";
Pattern p = Pattern.compile("num ([0-9]+)\\Z");
Matcher m = p.matcher(in);

if (m.find()) {
     in = m.group(1);
}