Cancelling a long running regex match?

后端 未结 7 1733
借酒劲吻你
借酒劲吻你 2020-11-27 04:25

Say I\'m running a service where users can submit a regex to search through lots of data. If the user submits a regex that is very slow (ie. takes minutes for Matcher.find()

7条回答
  •  粉色の甜心
    2020-11-27 04:58

    A long-running pattern matching process can be stopped using the below method.

    • Create StateFulCharSequence class which manages the state of pattern matching. When that state is changed, an exception is thrown on the next call to charAt method.
    • That state change can be scheduled using ScheduledExecutorService with a required timeout.
    • Here pattern matching is happening in the main thread and there is no need to check the thread interrupt state every time.

      public class TimedPatternMatcher {
      public static void main(String[] args) {
          ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
          Pattern pattern = Pattern.compile("some regex pattern");
          StateFulCharSequence stateFulCharSequence = new StateFulCharSequence("some character sequence");
          Matcher matcher = pattern.matcher(stateFulCharSequence);
          executorService.schedule(stateFulCharSequence, 10, TimeUnit.MILLISECONDS);
          try {
              boolean isMatched = matcher.find();
          }catch (Exception e) {
              e.printStackTrace();
          }
      
      }
      
      /*
      When this runnable is executed, it will set timeOut to true and pattern matching is stopped by throwing exception.
       */
      public static class StateFulCharSequence implements CharSequence, Runnable{
          private CharSequence inner;
      
          private boolean isTimedOut = false;
      
          public StateFulCharSequence(CharSequence inner) {
              super();
              this.inner = inner;
          }
      
          public char charAt(int index) {
              if (isTimedOut) {
                  throw new RuntimeException(new TimeoutException("Pattern matching timeout occurs"));
              }
              return inner.charAt(index);
          }
      
          @Override
          public int length() {
              return inner.length();
          }
      
          @Override
          public CharSequence subSequence(int start, int end) {
              return new StateFulCharSequence(inner.subSequence(start, end));
          }
      
          @Override
          public String toString() {
              return inner.toString();
          }
      
          public void setTimedOut() {
              this.isTimedOut = true;
          }
      
          @Override
          public void run() {
              this.isTimedOut = true;
          }
      }}
      

提交回复
热议问题