Java正则表达式有什么性能优势吗?

Java正则表达式有什么性能优势吗?,java,regex,performance,Java,Regex,Performance,在Java中,当我们尝试使用正则表达式进行模式匹配时。e、 g.获取一个输入字符串,并使用正则表达式确定它是否为数字。如果不是,抛出一个异常。 在这种情况下,我理解,使用正则表达式会使代码比我们获取字符串的每个字符、检查它是否是数字以及如果不抛出异常时更不冗长 但我的假设是,regex也能提高流程的效率。这是真的吗?在这一点上我找不到任何证据。regex在幕后是如何进行比赛的?它不是也在字符串上迭代并逐个检查每个字符吗?我还没有技术上的答案,但我可以编写一些代码并查看。 我不认为正则表达式是将字

在Java中,当我们尝试使用正则表达式进行模式匹配时。e、 g.获取一个输入字符串,并使用正则表达式确定它是否为数字。如果不是,抛出一个异常。 在这种情况下,我理解,使用正则表达式会使代码比我们获取字符串的每个字符、检查它是否是数字以及如果不抛出异常时更不冗长


但我的假设是,regex也能提高流程的效率。这是真的吗?在这一点上我找不到任何证据。regex在幕后是如何进行比赛的?它不是也在字符串上迭代并逐个检查每个字符吗?

我还没有技术上的答案,但我可以编写一些代码并查看。 我不认为正则表达式是将字符串转换为数字的方法。在许多情况下,它们可以更有效,但如果写得不好,速度会很慢

但是,我可以问一下,您为什么不使用:
Integer.parseInt(“124”)
?这将引发NumberFormatException。应该能够处理它,并且它将数字的检测留给核心Java。

好吧,很难说清楚,但是在一般情况下,正则表达式与显式字符检查相比不太可能更有效。RE是最终状态自动机,因此在自动机的构建和维护上有一些开销。在我的实践中,显式代码总是比正则表达式更快(因此效率更高)

但这是一个两难的问题。正则表达式在提供观点时几乎总是更有效,在正确使用时更具可读性。这是另一个困境。我很少看到正则表达式的正确用法

在您的场景中,我建议使用guava library:

boolean isValid = DIGIT.matchesAllOf("1234");

最后,它确实在字符串上迭代并检查每个字符,试图找到与所提供模式的匹配项。此外,它使用回溯(如果有许多方法可能匹配,引擎将全部尝试),这可能会导致某些异常情况下的性能非常差(不太可能遇到这种情况,但理论上是可能的)。在最坏的情况下,java正则表达式引擎的性能是O(2N),其中N是输入字符串的长度

有一些算法可以实现更快的模式匹配,提供O(N)性能,但与Java正则表达式相比,它们的功能更少

这是一篇详细讨论这个问题的文章


但在大多数情况下,正则表达式引擎不会成为应用程序的性能瓶颈。它的速度足够快,所以通常不用担心它,除非您的分析器指向它。它提供了对算法的声明性描述,这非常有用,因为几乎所有的迭代算法实现都会更加冗长,可读性也会大大降低。

为了好玩,我运行了这个微基准测试。最后一次运行(即JVM后预热/JIT)的结果如下(从一次运行到另一次运行的结果都相当一致):

换句话说,chars是非常有效的,Integer.parseInt在字符串是数字时与char一样有效,但在字符串不是数字时速度非常慢。正则表达式介于两者之间

结论

如果将字符串解析为数字,并且希望字符串通常是数字,则使用Integer.parseInt是最佳解决方案(高效且可读)。如果字符串不是一个数字,那么如果不是太频繁,那么得到的惩罚应该很低

ps:我的正则表达式可能不是最优的,请随意评论

public class TestNumber {

    private final static List<String> numbers = new ArrayList<>();
    private final static List<String> words = new ArrayList<>();

    public static void main(String args[]) {
        long start, end;
        Random random = new Random();

        for (int i = 0; i < 1000000; i++) {
            numbers.add(String.valueOf(i));
            words.add(String.valueOf(i) + "x");
        }

        for (int i = 0; i < 5; i++) {
            start = System.nanoTime();
            regex(numbers);
            System.out.println("regex with numbers " + (System.nanoTime() - start) / 1000000);
            start = System.nanoTime();
            chars(numbers);
            System.out.println("chars with numbers " + (System.nanoTime() - start) / 1000000);
            start = System.nanoTime();
            exception(numbers);
            System.out.println("exceptions with numbers " + (System.nanoTime() - start) / 1000000);

            start = System.nanoTime();
            regex(words);
            System.out.println("regex with words " + (System.nanoTime() - start) / 1000000);
            start = System.nanoTime();
            chars(words);
            System.out.println("chars with words " + (System.nanoTime() - start) / 1000000);
            start = System.nanoTime();
            exception(words);
            System.out.println("exceptions with words " + (System.nanoTime() - start) / 1000000);
        }
    }

    private static int regex(List<String> list) {
        int sum = 0;
        Pattern p = Pattern.compile("[0-9]+");
        for (String s : list) {
            sum += (p.matcher(s).matches() ? 1 : 0);
        }
        return sum;
    }

    private static int chars(List<String> list) {
        int sum = 0;

        for (String s : list) {
            boolean isNumber = true;
            for (char c : s.toCharArray()) {
                if (c < '0' || c > '9') {
                    isNumber = false;
                    break;
                }
            }
            if (isNumber) {
                sum++;
            }
        }
        return sum;
    }

    private static int exception(List<String> list) {
        int sum = 0;

        for (String s : list) {
            try {
                Integer.parseInt(s);
                sum++;
            } catch (NumberFormatException e) {
            }
        }
        return sum;
    }
}
公共类TestNumber{
private final static List number=new ArrayList();
private final static List words=new ArrayList();
公共静态void main(字符串参数[]){
漫长的开始,漫长的结束;
随机=新随机();
对于(int i=0;i<1000000;i++){
添加(String.valueOf(i));
单词.add(字符串.valueOf(i)+“x”);
}
对于(int i=0;i<5;i++){
start=System.nanoTime();
正则表达式(数字);
System.out.println(“带有数字的正则表达式”+(System.nanoTime()-start)/1000000);
start=System.nanoTime();
字符(数字);
System.out.println(“带数字的字符”+(System.nanoTime()-start)/1000000);
start=System.nanoTime();
例外情况(数字);
System.out.println(“数字异常”+(System.nanoTime()-start)/1000000);
start=System.nanoTime();
正则表达式(大写);
System.out.println(“带有单词“+(System.nanoTime()-start)/1000000的正则表达式);
start=System.nanoTime();
字数;
System.out.println(“带有单词“+(System.nanoTime()-start)/1000000的字符);
start=System.nanoTime();
例外情况(文字);
System.out.println(“带有单词“+(System.nanoTime()-start)/1000000的异常);
}
}
私有静态int regex(列表){
整数和=0;
Pattern p=Pattern.compile(“[0-9]+”);
用于(字符串s:列表){
sum+=(p.matcher.matches()?1:0);
}
回报金额;
}
私有静态int字符(列表){
整数和=0;
用于(字符串s:列表){
布尔值isNumber=true;
for(char c:s.toCharArray()){
如果(c<'0'| c>'9'){
isNumber=false;
打破
}
}
如果(isNumber){
sum++;
}
}
回报金额;
}
私有静态int异常(列表){
整数和=0;
用于(字符串s:列表){
试一试{
整数.parseInt(s);
sum++;
}捕获(数字格式){
}
}
回报金额;
}
}
public class TestNumber {

    private final static List<String> numbers = new ArrayList<>();
    private final static List<String> words = new ArrayList<>();

    public static void main(String args[]) {
        long start, end;
        Random random = new Random();

        for (int i = 0; i < 1000000; i++) {
            numbers.add(String.valueOf(i));
            words.add(String.valueOf(i) + "x");
        }

        for (int i = 0; i < 5; i++) {
            start = System.nanoTime();
            regex(numbers);
            System.out.println("regex with numbers " + (System.nanoTime() - start) / 1000000);
            start = System.nanoTime();
            chars(numbers);
            System.out.println("chars with numbers " + (System.nanoTime() - start) / 1000000);
            start = System.nanoTime();
            exception(numbers);
            System.out.println("exceptions with numbers " + (System.nanoTime() - start) / 1000000);

            start = System.nanoTime();
            regex(words);
            System.out.println("regex with words " + (System.nanoTime() - start) / 1000000);
            start = System.nanoTime();
            chars(words);
            System.out.println("chars with words " + (System.nanoTime() - start) / 1000000);
            start = System.nanoTime();
            exception(words);
            System.out.println("exceptions with words " + (System.nanoTime() - start) / 1000000);
        }
    }

    private static int regex(List<String> list) {
        int sum = 0;
        Pattern p = Pattern.compile("[0-9]+");
        for (String s : list) {
            sum += (p.matcher(s).matches() ? 1 : 0);
        }
        return sum;
    }

    private static int chars(List<String> list) {
        int sum = 0;

        for (String s : list) {
            boolean isNumber = true;
            for (char c : s.toCharArray()) {
                if (c < '0' || c > '9') {
                    isNumber = false;
                    break;
                }
            }
            if (isNumber) {
                sum++;
            }
        }
        return sum;
    }

    private static int exception(List<String> list) {
        int sum = 0;

        for (String s : list) {
            try {
                Integer.parseInt(s);
                sum++;
            } catch (NumberFormatException e) {
            }
        }
        return sum;
    }
}