Advertisement
shchuko

Matcher.java

Jan 8th, 2020
519
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 4.46 KB | None | 0 0
  1. package regex.parser;
  2.  
  3. import javafx.util.Pair;
  4. import java.util.ArrayList;
  5. import java.util.Stack;
  6.  
  7.  
  8. public class Matcher {
  9.     private FSA fsa;
  10.  
  11.     private Matcher(FSA fsa) {
  12.         this.fsa = fsa;
  13.     }
  14.  
  15.     public static Matcher createMatcher(String pattern) {
  16.         FSA fsa = new FSA(pattern);
  17.         if (fsa.isBuildSuccess()) {
  18.             return new Matcher(fsa);
  19.         }
  20.  
  21.         return null;
  22.     }
  23.  
  24.     public boolean isMatch(String inputString) {
  25.         return fsa.isMatch(inputString);
  26.     }
  27. }
  28.  
  29.  
  30. class FSA {
  31.     private static class State {
  32.         boolean terminal = false;
  33.         boolean anyChar = false;
  34.         char charToState;
  35.  
  36.         State nextStateDirect = null;
  37.         ArrayList<State> otherWays = new ArrayList<>();
  38.     }
  39.  
  40.     private State start = new State();
  41.  
  42.     FSA(String pattern) {
  43.         if (pattern == null) {
  44.             start = null;
  45.             return;
  46.         }
  47.  
  48.         if (pattern.length() == 0) {
  49.             start.terminal = true;
  50.             return;
  51.         }
  52.  
  53.         // Only vertexes with chars without * modifier
  54.         State currentState = start;
  55.         char[] patternArray = pattern.toCharArray();
  56.         for (int i = 0; i < patternArray.length; i++) {
  57.             char c = patternArray[i];
  58.             if (c == '*') {
  59.                 continue;
  60.             }
  61.  
  62.             State state = new State();
  63.             if (c == '.') {
  64.                 state.anyChar = true;
  65.             } else {
  66.                 state.charToState = c;
  67.             }
  68.  
  69.  
  70.             if (i < patternArray.length - 1 && patternArray[i + 1] == '*') {
  71.                 if (i == patternArray.length - 2) {
  72.                     currentState.terminal = true;
  73.                 }
  74.                 currentState.otherWays.add(state);
  75.                 for (State otherState : currentState.otherWays) {
  76.                     if (i == patternArray.length - 2) {
  77.                         otherState.terminal = true;
  78.                     }
  79.                     otherState.otherWays.add(state);
  80.                 }
  81.             } else {
  82.                 if (i == patternArray.length - 1) {
  83.                     state.terminal = true;
  84.                 }
  85.               currentState.nextStateDirect = state;
  86.               for (State otherState : currentState.otherWays) {
  87.                   otherState.nextStateDirect = state;
  88.               }
  89.               currentState = state;
  90.             }
  91.         }
  92.     }
  93.  
  94.     boolean isBuildSuccess() {
  95.         return start != null;
  96.     }
  97.  
  98.  
  99.     boolean isMatch(String input) {
  100.         if (input.length() == 0) {
  101.             return start.terminal;
  102.         }
  103.  
  104.         // Node : visited node
  105.         // Integer : counter of visited node ways out
  106.         Stack<Pair<State, Integer>> visited = new Stack<>();
  107.         int i = 0;
  108.  
  109.         visited.push(new Pair<>(start, -1));
  110.  
  111.         while (i < input.length()) {
  112.             if (visited.empty()) {
  113.                 return false;
  114.             }
  115.             Pair<State, Integer> peeked = visited.peek();
  116.  
  117.             State nextDirect = peeked.getKey().nextStateDirect;
  118.             ArrayList<State> otherDirections = peeked.getKey().otherWays;
  119.             int checkCounter = peeked.getValue();
  120.  
  121.             // If there's way by next node
  122.             if (checkCounter == -1) {
  123.                 visited.pop();
  124.                 visited.push(new Pair<>(peeked.getKey(), checkCounter + 1));
  125.  
  126.                 if (nextDirect != null && (nextDirect.charToState == input.charAt(i) || nextDirect.anyChar)) {
  127.                     ++i;
  128.                     visited.push(new Pair<>(nextDirect, -1));
  129.                 }
  130.  
  131.             // If exists way through repeatable symbols
  132.             } else if (checkCounter < otherDirections.size()) {
  133.                 visited.pop();
  134.                 visited.push(new Pair<>(peeked.getKey(), checkCounter + 1));
  135.  
  136.                 if ((otherDirections.get(checkCounter).charToState == input.charAt(i) ||
  137.                         otherDirections.get(checkCounter).anyChar)) {
  138.                     ++i;
  139.                     visited.push(new Pair<>(otherDirections.get(checkCounter), -1));
  140.                 }
  141.  
  142.             // If there's no way from current state
  143.             } else if (!visited.empty()) {
  144.                 // Going back
  145.                 visited.pop();
  146.                 --i;
  147.             }
  148.         }
  149.  
  150.         if (visited.empty()) {
  151.             return false;
  152.         }
  153.  
  154.         return visited.peek().getKey().terminal;
  155.     }
  156. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement