java匹配正则设置超时_如何中断⼀个长时间运⾏的”⽆限”Java
正则表达式
本⽂由 ImportNew - ⼈晓 翻译⾃ ocpsoft。欢迎加⼊Java⼩组。转载请参见⽂章末尾的要求。
如果你处理过⼤量的正则表达式,那么你对“catastrophic backtracking”的概念⼀定不陌⽣,这种情况下处理器被强迫执⾏指数倍的计算。例如,点击该⽰例,看看它需要多久完成(应该在5-10秒后超时)。
LongRunningRegexExample.java
01
public class LongRunningRegexExample
02
{
03
public static void main(String[] args)throws InterruptedException
04
{
05
final Pattern pattern = Patternpile("(0*)*A");
06
final String input ="00000000000000000000000000";
07
08
long startTime = System.currentTimeMillis();
09
Matcher matcher = pattern.matcher(input);
10
matcher.find();// runs for a long time!
11
System.out.println("Regex took:" + (System.currentTimeMillis() - startTime) +"ms");
12时间正则表达式java
}
13
}
但是,⼩⼩的改动就能让该程序⽴即响应。为什么呢?这⾥引⽤Dzone中Andreas Haufler的⽂章《How to Kill Java with a Regular
第⼀眼看上去像是⽆限循环的东西会造成catastrophic backtracking
意思是说匹配器在输⼊的末尾并没有检测到”A”。现在外侧的限定符后退⼀次,内存的则前进⼀次,如此重复,⽆法得到结果。
因此,匹配器逐步回退,并尝试所有的组合以出匹配符号。它最终将返回(没有匹配的结果),但是该过程的复杂性是指数型的(输⼊中添加⼀个字符加倍了运⾏时间)。
所以,我们究竟该采取何种⽅式避免这种破坏性的影响,我们是否会遇到Java程序运⾏数天甚⾄⼏年的情形?
在你的资源⾮常充⾜的情况下,你也许可以简单⼩⼼的在你的模式中避免这种情况。但是,如果你正在开发⼀个接受正则表达式作为输⼊的应⽤程序,例如⼀个在线Java可视化的正则表达式⽰例,那么你就应该避免这种情情况或是受到拒绝服务器攻击。
幸运的是,答案⾮常简单,但需要引⼊⼀个线程,以及⼀个⾮常特殊的字符串序列。我是在StackOverflow上到该实现的。
InterruptibleRegexExample.java
01
public class InterruptibleRegexExample
02
{
03
public static void main(String[] args)throws InterruptedException
04
{
05
final Pattern pattern = Patternpile("(0*)*A");
06
final String input ="00000000000000000000000000";
07
Runnable runnable =new Runnable() {
08
@Override
09
public void run()
10
{
11
long startTime = System.currentTimeMillis();
12
Matcher interruptableMatcher = pattern.matcher(new InterruptibleCharSequence(input));
13
System.out.println("Regex took:" + (System.currentTimeMillis() - startTime) +"ms");
15
}
16
};
17
18
Thread thread =new Thread(runnable);
19
thread.start();
20
21
Thread.sleep(500);
22
thread.interrupt();
23
}
24
}
结果很好的中断了正则表达式:
Exception in thread “Thread-2″ java.lang.RuntimeException: Die! … Why won’t you DIE!
server.InterruptRegex$InterruptibleCharSequence.charAt(InterruptRegex.java:72) at Pattern$BmpCharProperty.match(Pattern.java:3366)
at Pattern$Curly.match0(Pattern.java:3760)
at Pattern$Curly.match(Pattern.java:3744)
at Pattern$GroupHead.match(Pattern.java:4168)
你还需要⼀个InterruptibleCharSequence类,它在某种程度上也会影响性能,但是要⽐等上⼀年要好的多:InterruptibleCharSequence.java
01
/**
02
* {@link CharSequence} that notices {@link Thread} interrupts
04
* @author gojomo
05
*/
06
private static class InterruptibleCharSequenceimplements CharSequence { 07
CharSequence inner;
08
public InterruptibleCharSequence(CharSequence inner) {
09
super();
10
this.inner = inner;
11
}
12
13
@Override
14
public char charAt(int index) {
15
if (Thread.currentThread().isInterrupted()) {
16
throw new RuntimeException("Interrupted!");
17
}
18
return inner.charAt(index);
19
}
20
@Override
22
public int length() {
23
return inner.length();
24
}
25
26
@Override
27
public CharSequence subSequence(int start,int end) {
28
return new InterruptibleCharSequence(inner.subSequence(start, end));
29
}
30
31
@Override
32
public String toString() {
33
String();
34
}
35
}
结论
我很开⼼能学习并撰写这些内容,这篇博客总结了正则表达式的⽆限运⾏及解决⽅案(Java中),希望它能帮到其他遇到该问题的⼈。愉快的过程!
原⽂链接: ocpsoft 翻译: ImportNew- ⼈晓
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论