`
deepinmind
  • 浏览: 449415 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
1dc14e59-7bdf-33ab-841a-02d087aed982
Java函数式编程
浏览量:41416
社区版块
存档分类
最新评论

如何中断正则的执行

阅读更多
如果你在工作经常使用正则表达式的话,你可能对灾难性回溯(catastrophic backtracking)这个概念并不陌生,这说明你在强迫正则引擎去进行指数级的排列运算。比如说,点击这里运行下这个用例来看看它得花多长时间(大概是5到10秒):


public class LongRunningRegexExample
{
   public static void main(String[] args) throws InterruptedException
   {
      final Pattern pattern = Pattern.compile("(0*)*A");
      final String input = "00000000000000000000000000";

      long startTime = System.currentTimeMillis();
      Matcher matcher = pattern.matcher(input);
      matcher.find(); // runs for a long time!
      System.out.println("Regex took:" + (System.currentTimeMillis() - startTime) + "ms");
   }
}



然而只需一个很小的改动就能让它马上返回。为什么?引用 Dzone的Andreas Haufler在他的_如何使用正则表达式杀掉Java程序_一文中的一句话,这个简洁的示例程序也是来自这篇文章的:


乍一看它像是一个无限循环,这其实是一个灾难性回溯。这说明匹配器在输入结尾处没有找到'A'字符。因此外部检测器会后退一步,而内部的则前进一步,但仍然没有发现。

因此匹配器会不断地回退,尝试完所有的组合,来看一下是否存在一个匹配的字符串。它最终仍会返回(没有匹配上),但时间复杂度却是指数级的(增加一个字符运行时间会翻倍)。


那么我们该如何做才能避免这样的影响,有没有可能会遇到这么一个场景,要让Java进程运行好几天,甚至好几年的?

如果你不嫌麻烦的话,你可以在自己的正则模式中注意去避免这样的情况。但是如果你部署了一个应用,它接受一个输入作为正则表达式的话——比如说一个在线的Java正则校验器,那么你需要防止这种情况,否则就可能会遭受拒绝服务攻击。

答案非常简单,不过你需要引入一个线程,下面是我在stackoverflow上找到的一个特殊的字符序列的实现。


public class InterruptibleRegexExample
{
   public static void main(String[] args) throws InterruptedException
   {
      final Pattern pattern = Pattern.compile("(0*)*A");
      final String input = "00000000000000000000000000";

      Runnable runnable = new Runnable() {
         @Override
         public void run()
         {
            long startTime = System.currentTimeMillis();
            Matcher interruptableMatcher = pattern.matcher(new InterruptibleCharSequence(input));
            interruptableMatcher.find(); // runs for a long time!
            System.out.println("Regex took:" + (System.currentTimeMillis() - startTime) + "ms");
         }
      };

      Thread thread = new Thread(runnable);
      thread.start();

      Thread.sleep(500);
      thread.interrupt();
   }
}


这样这个正则就非常棒了,它是可中断的。

Exception in thread "Thread-2" java.lang.RuntimeException: Die! ... Why won't you DIE!
at org.ocpsoft.tutorial.regex.server.InterruptRegex$InterruptibleCharSequence.charAt(InterruptRegex.java:72)
at java.util.regex.Pattern$BmpCharProperty.match(Pattern.java:3366)
at java.util.regex.Pattern$Curly.match0(Pattern.java:3760)
at java.util.regex.Pattern$Curly.match(Pattern.java:3744)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4168)



当然了你需要用到InterruptibleCharSequence,这多少会影响到程序的性能,不过总比干等一年要好得多:

/**
 * {@link CharSequence} that notices {@link Thread} interrupts
 * 
 * @author gojomo - http://stackoverflow.com/questions/910740/cancelling-a-long-running-regex-match
 */
private static class InterruptibleCharSequence implements CharSequence {
   CharSequence inner;

   public InterruptibleCharSequence(CharSequence inner) {
      super();
      this.inner = inner;
   }

   @Override
   public char charAt(int index) {
      if (Thread.currentThread().isInterrupted()) {
         throw new RuntimeException("Interrupted!");
      }
      return inner.charAt(index);
   }

   @Override
   public int length() {
      return inner.length();
   }

   @Override
   public CharSequence subSequence(int start, int end) {
      return new InterruptibleCharSequence(inner.subSequence(start, end));
   }

   @Override
   public String toString() {
      return inner.toString();
   }
}




原创文章转载请注明出处:http://it.deepinmind.com


英文原文链接
2
0
分享到:
评论
1 楼 QuarterLifeForJava 2014-06-18  
(任意字符)*  应该是匹配一切吧?

然后如果改为((0*)*)*A  这个就不知道要匹配多久了。。。
给我感觉多加一个*就多加个n次方,像上面这个感觉就是n的n次方的n次方

相关推荐

    java超时代码处理:以正则表达式设置超时时间为例

    java超时取消正则表达式匹配方法,代码超时处理,设置代码执行时间,超棒的工具类 lambda,Callable,ExecutorService,超过执行5秒退出

    C#超时方法 正则超时

    标题提到的"超时方法 正则超时"是关于如何在C#中处理正则表达式执行时间过长的问题。下面将详细介绍这一主题。 首先,`OutTimeClass.cs`可能包含了一个自定义的超时类,它可能提供了设置超时时间、执行任务以及在超...

    C#字符串和正则表达式参考手册.pdf VBA语句集400句

    根据给定文件的信息,我们可以从中提炼出一系列与Visual Basic for Applications (VBA)相关的知识点,以及部分关于C#字符串和正则表达式的概念。以下是对这些知识点的详细解析: ### VBA语句集 #### 1. Option ...

    Nginx关于Rewrite执行顺序详解.docx

    其中,`<regex>`是匹配的正则表达式,`<replacement>`是替换后的URL,`[flag]`是一些可选的标志,如`last`、`break`、`redirect`、`permanent`等,它们控制着重写规则的执行行为。 二、Rewrite执行顺序 Nginx中的...

    php正则匹配文章中的远程图片地址并下载图片至本地

    页面上还包含了PHP脚本执行的入口,通过设置`set_time_limit(0)`可以确保长时间运行的脚本不会因时间限制而中断。 总结来说,通过使用PHP正则表达式匹配远程图片地址,并利用文件处理函数将图片下载并保存到本地...

    mysqlhotcopy 正则使用小技巧

    这个工具在不中断服务的情况下能够创建数据的物理备份,极大地提高了备份效率。在使用`mysqlhotcopy`时,我们可以结合正则表达式来更精确地选择需要备份的数据。 首先,确保已经为`mysqlhotcopy`分配了一个具有适当...

    ARM编程:Scatter文件的编写、分析

    2. **代码与数据分配**:`vectors.o (+RO, +FIRST)`确保中断向量表被放置在最前面的位置。`*(InRoot$$Sections)`复制必需处于rootregion的库段。`*(+RW, +ZI)`将可写数据段和未初始化数据段放入SRAM中,而`stack.o ...

    FreeRTOS API Reference 8.1.2 API参考手册完整版

    taskENTER_CRITICAL和taskEXIT_CRITICAL宏可以用来创建临界区,以防止中断打断代码片段的执行。taskYIELD函数则用于主动放弃CPU的使用权,允许其他就绪态任务运行。 5. 列表(Lists)模块是FreeRTOS中用来管理数据...

    basic解释器源代码.rar

    错误处理通常包括产生错误消息和中断程序执行。 9. **优化** 高级解释器可能包含一些优化策略,如死代码删除、常量折叠等,以提高代码执行效率。 10. **跨平台能力** Basic解释器的源代码通常设计为可移植的,...

    shell script学习

    另一个常用的工具是trap命令,它能够捕获脚本运行期间的信号,如SIGINT(中断信号),并执行预定义的动作。此外,还可以利用脚本内部的echo命令输出变量和执行流的信息来帮助我们理解脚本的执行过程。 Shell脚本的...

    Exception

    在编程中,异常是程序执行期间发生的不正常条件,它中断了正常的代码流程。异常处理是编程语言中的一个重要概念,用于捕获并处理这些错误,以确保程序的稳定性和可靠性。 描述中提供的链接指向了一篇关于技术博客的...

    PowerShell概要PowerShell Succinctly

    管理流程允许用户控制脚本的执行流程,如中断、跳过或退出循环。脚本调度执行是自动化管理的重要部分,PowerShell提供了相关的cmdlet来设置和管理定时任务。可扩展性和代码重用是编程中的重要概念,PowerShell支持...

    JAVA异常捕获

    异常(Exception)是程序执行期间发生的错误,它中断了正常的控制流程。Java提供了异常处理机制来优雅地处理这些异常,而不是让程序突然崩溃。 在Java中,异常捕获通过`try-catch`语句块实现。`try`块包含可能会抛...

    wscript解析

    - **`DisconnectObject`**:从当前脚本中断开与某个对象的连接。 - **`Echo`**:用于输出信息到控制台。 - **`GetObject`**:获取已存在的COM对象。 - **`Quit`**:终止脚本运行。 - **`Sleep`**:使脚本暂停执行...

    信用卡系统

    这时,我们需要使用try-catch块来捕获并处理这些异常,防止程序因意外情况而中断。 6. **并发与线程安全**: 如果系统需要支持多个用户同时访问,那么需要考虑并发控制。Java的synchronized关键字和Thread类可以...

    chrome调试&代码逆向分析.docx

    此外,还有**Timer**选项,可在setTimeout或setInterval处理函数开始执行时中断。 ##### 5. JavaScript异常中断 - **Pretty Print**按钮左侧有一个开关,用于控制JavaScript抛出异常时是否中断。可以选择在所有...

    入门学习Java For Beginners: A Simple Start To Java Programming

    异常处理则涉及到如何使用try、catch、finally关键字来捕获和处理程序执行过程中可能发生的异常情况,以避免程序因错误而中断执行。 接口和包是Java语言中用于组织代码的高级概念。接口定义了一组方法规范,供不同...

    Linux 45 道面试题及答案.docx

    答案:不可中断状态、暂停状态、就绪状态、运行状态、可中断睡眠状态 其他 1. Linux 下命令有哪几种可使用的通配符?分别代表什么含义? 答案:“?” 可以替代单个字符,“*” 可以替代任意多个字符,方括号 “...

Global site tag (gtag.js) - Google Analytics