设为首页 加入收藏

TOP

Java 正则表达式 StackOverflowError 问题及其优化(一)
2017-09-30 11:23:53 】 浏览:872
Tags:Java 正则 表达式 StackOverflowError 问题 及其 优化

正则可以看做一门 DSL,但它却应用极其广泛,可以轻松解决很多场景下的字符串匹配、筛选问题。同时呢有句老话:

“ 如果你有一个问题,用正则表达式解决,那么你现在就有两个问题了。”

Some people, when confronted with a problem, think “I know, I’ll use regular expressions.” Now they have two problems.

今天我们就来聊聊 Java 正则表达式 StackOverflowError 的问题及其一些优化点。

1、问题

最近,有同事发现一段正则在本地怎么跑都没问题,但是放到 Hadoop 集群上总会时不时的抛 StackOverflowError 。

代码我先简化下:

package java8test;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Test {

	public static void main(String[] args) {

		final String TEST_REGEX = "([=+]|[\\s]|[\\p{P}]|[A-Za-z0-9]|[\u4E00-\u9FA5])+";
		StringBuilder line = new StringBuilder();
		System.out.println("++++++++++++++++++++++++++++++");
		for (int i = 0; i < 10; i++) {
			line.append(
					"http://hh.ooxx.com/ershoufang/?PGTID=14366988648680=+.7342327926307917&ClickID=1&key=%2525u7261%2525u4E39%2525u5BCC%2525u8D35%2525u82B1%2525u56ED&sourcetype=1_5");
			line.append(
					"http://wiki.corp.com/index.php?title=Track%E6%A0%87%E5%87%86%E6%97%A5%E5%BF%97Hive%E8%A1%A8-%E5%8D%B3%E6%B8%85%E6%B4%97%E5%90%8E%E7%9A%84%E6%97%A5%E5%BF%97");
			line.append(
					"http://www.baidu.com/s?ie=UTF-8&wd=58%cd%ac%b3%c7%b6%fe%ca%d6%b3%b5%b2%e2%ca%d4%ca%fd%be%dd&tn=11000003_hao_dg");
			line.append("http://cs.ooxx.com/yewu/?key=城&cmcskey=的设计费开始低&final=1&jump=1&specialtype=gls");
			line.append(
					"http%3A%2F%2Fcq.ooxx.com%2Fjob%2F%3Fkey%3D%25E7%25BD%2591%25E4%25B8%258A%25E5%2585%25BC%25E8%2581%258C%26cmcskey%3D%25E7%25BD%2591%25E4%25B8%258A%25E5%2585%25BC%25E8%2581%258C%26final%3D1%26jump%3D2%26specialtype%3Dgls%26canclequery%3Disbiz%253D0%26sourcetype%3D4");
		}
		line.append(" \001 11111111111111111111111111");
		Pattern p_a = null;
		try {
			p_a = Pattern.compile(TEST_REGEX);
			Matcher m_a = p_a.matcher(line);
			while (m_a.find()) {
				String a = m_a.group();
				System.out.println(a);
			}
		} catch (Exception e) {
			// TODO: handle exception
		}

		System.out.println("line size: " + line.length());
	}
}

执行之后的结果是:

++++++++++++++++++++++++++++++
Exception in thread "main" java.lang.StackOverflowError
	at java.util.regex.Pattern$Loop.match(Unknown Source)
	at java.util.regex.Pattern$GroupTail.match(Unknown Source)
	at java.util.regex.Pattern$BranchConn.match(Unknown Source)
	at java.util.regex.Pattern$CharProperty.match(Unknown Source)
......

起初这个问题是从集群上抛出来的,大家可以看到这个异常有两个特点:

(1)不可用 Exception 捕获,因为 Error 直接继承自 Throwable 而非 Exception,所以即使你要捕获也应当捕获 Error。

(2)另外一点是大家可以看到抛出的错误并没有指明行号,当这段代码混在一个数百行的工具类,有数十条类似的正则的时候,无疑给定位问题带来了难度,这就需要我们能有一定的单元测试能力。

注:

(1)如果你的环境没有抛出上述错误,尝试调大 for 循环的次数或者指定 jvm 参数:-Xss1k

(2)如果你还不明白 StackOverflowError 是什么含义,可以参考上一篇文章:JVM 运行时数据区简介

2、问题分析

正则表达式引擎分成两类,一类称为DFA(确定性有穷自动机),另一类称为NFA(非确定性有穷自动机)。两类引擎要顺利工作,都必须有一个正则式和一个文本串。DFA捏着文本串去比较正则式,看到一个子正则式,就把可能的匹配串全标注出来,然后再看正则式的下一个部分,根据新的匹配结果更新标注。而NFA是捏着正则式去比文本,吃掉一个字符,就把它跟正则式比较,匹配就记下来,然后接着往下干。一旦不匹配,就把刚吃的这个字符吐出来,一个个的吐,直到回到上一次匹配的地方。

DFA与NFA机制上的不同带来5个影响:

1. DFA 对于文本串里的每一个字符只需扫描一次,比较快,但特性较少;NFA要翻来覆去吃字

首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Java synchronized 中的 while 和.. 下一篇Dagger2 神器入门(一)

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目