1 package java.util.regex; 2 3 import java.util.HashMap; 4 import java.util.regex.Pattern.CharPredicate; 5 import java.util.regex.CharPredicates; 6 import static java.util.regex.ASCII.*; 7 8 /** 9 * A utility class to print out the pattern node tree. 10 */ 11 12 class PrintPattern { 13 14 private static HashMap<Pattern.Node, Integer> ids = new HashMap<>(); 15 16 private static void print(Pattern.Node node, String text, int depth) { 17 if (!ids.containsKey(node)) 18 ids.put(node, ids.size()); 19 Print("%6d:%" + (depth==0? "": depth<<1) + "s<%s>", ids.get(node), "", text); 20 if (ids.containsKey(node.next)) 21 Print(" (=>%d)", ids.get(node.next)); 22 Print("%n"); 23 } 24 25 private static void print(String s, int depth) { 26 Print(" %" + (depth==0?"":depth<<1) + "s<%s>%n", "", s); 27 } 28 29 private static void Print(String fmt, Object ... args) { 30 System.err.printf(fmt, args); 31 } 32 33 private static String toStringCPS(int[] cps) { 34 StringBuilder sb = new StringBuilder(cps.length); 35 for (int cp : cps) 36 sb.append(toStringCP(cp)); 37 return sb.toString(); 38 } 39 40 private static String toStringCP(int cp) { 41 return (isPrint(cp) ? "" + (char)cp 42 : "\\u" + Integer.toString(cp, 16)); 43 } 44 45 private static String toStringRange(int min, int max) { 46 if (max == Pattern.MAX_REPS) { 47 if (min == 0) 48 return " * "; 49 else if (min == 1) 50 return " + "; 51 return "{" + min + ", max}"; 52 } 53 return "{" + min + ", " + max + "}"; 54 } 55 56 private static String toStringCtype(int type) { 57 switch(type) { 58 case UPPER: return "ASCII.UPPER"; 59 case LOWER: return "ASCII.LOWER"; 60 case DIGIT: return "ASCII.DIGIT"; 61 case SPACE: return "ASCII.SPACE"; 62 case PUNCT: return "ASCII.PUNCT"; 63 case CNTRL: return "ASCII.CNTRL"; 64 case BLANK: return "ASCII.BLANK"; 65 case UNDER: return "ASCII.UNDER"; 66 case ASCII: return "ASCII.ASCII"; 67 case ALPHA: return "ASCII.ALPHA"; 68 case ALNUM: return "ASCII.ALNUM"; 69 case GRAPH: return "ASCII.GRAPH"; 70 case WORD: return "ASCII.WORD"; 71 case XDIGIT: return "ASCII.XDIGIT"; 72 default: return "ASCII ?"; 73 } 74 } 75 76 private static String toString(Pattern.Node node) { 77 String name = node.getClass().getName(); 78 return name.substring(name.lastIndexOf('$') + 1); 79 } 80 81 static HashMap<CharPredicate, String> pmap; 82 static { 83 pmap = new HashMap<>(); 84 pmap.put(Pattern.ALL, "All"); 85 pmap.put(Pattern.DOT, "Dot"); 86 pmap.put(Pattern.UNIXDOT, "UnixDot"); 87 pmap.put(Pattern.VertWS, "VertWS"); 88 pmap.put(Pattern.HorizWS, "HorizWS"); 89 90 pmap.put(CharPredicates.ASCII_DIGIT, "ASCII.DIGIT"); 91 pmap.put(CharPredicates.ASCII_WORD, "ASCII.WORD"); 92 pmap.put(CharPredicates.ASCII_SPACE, "ASCII.SPACE"); 93 } 94 95 private static void walk(Pattern.Node node, int depth) { 96 depth++; 97 while(node != null) { 98 String name = toString(node); 99 String str; 100 if (node instanceof Pattern.Prolog) { 101 print(node, name, depth); 102 // print the loop here 103 Pattern.Loop loop = ((Pattern.Prolog)node).loop; 104 name = toString(loop); 105 str = name + " " + toStringRange(loop.cmin, loop.cmax); 106 print(loop, str, depth); 107 walk(loop.body, depth); 108 print("/" + name, depth); 109 node = loop; 110 } else if (node instanceof Pattern.Loop) { 111 return; // stop here, body.next -> loop 112 } else if (node instanceof Pattern.Curly) { 113 Pattern.Curly c = (Pattern.Curly)node; 114 str = "Curly " + c.type + " " + toStringRange(c.cmin, c.cmax); 115 print(node, str, depth); 116 walk(c.atom, depth); 117 print("/Curly", depth); 118 } else if (node instanceof Pattern.GroupCurly) { 119 Pattern.GroupCurly gc = (Pattern.GroupCurly)node; 120 str = "GroupCurly " + gc.groupIndex / 2 + 121 ", " + gc.type + " " + toStringRange(gc.cmin, gc.cmax); 122 print(node, str, depth); 123 walk(gc.atom, depth); 124 print("/GroupCurly", depth); 125 } else if (node instanceof Pattern.GroupHead) { 126 Pattern.GroupHead head = (Pattern.GroupHead)node; 127 Pattern.GroupTail tail = head.tail; 128 print(head, "Group.head " + (tail.groupIndex / 2), depth); 129 walk(head.next, depth); 130 print(tail, "/Group.tail " + (tail.groupIndex / 2), depth); 131 node = tail; 132 } else if (node instanceof Pattern.GroupTail) { 133 return; // stopper 134 } else if (node instanceof Pattern.Ques) { 135 print(node, "Ques " + ((Pattern.Ques)node).type, depth); 136 walk(((Pattern.Ques)node).atom, depth); 137 print("/Ques", depth); 138 } else if (node instanceof Pattern.Branch) { 139 Pattern.Branch b = (Pattern.Branch)node; 140 print(b, name, depth); 141 int i = 0; 142 while (true) { 143 if (b.atoms[i] != null) { 144 walk(b.atoms[i], depth); 145 } else { 146 print(" (accepted)", depth); 147 } 148 if (++i == b.size) 149 break; 150 print("-branch.separator-", depth); 151 } 152 node = b.conn; 153 print(node, "/Branch", depth); 154 } else if (node instanceof Pattern.BranchConn) { 155 return; 156 } else if (node instanceof Pattern.CharProperty) { 157 str = pmap.get(((Pattern.CharProperty)node).predicate); 158 if (str == null) 159 str = toString(node); 160 else 161 str = "Single \"" + str + "\""; 162 print(node, str, depth); 163 } else if (node instanceof Pattern.SliceNode) { 164 str = name + " \"" + 165 toStringCPS(((Pattern.SliceNode)node).buffer) + "\""; 166 print(node, str, depth); 167 } else if (node instanceof Pattern.CharPropertyGreedy) { 168 Pattern.CharPropertyGreedy gcp = (Pattern.CharPropertyGreedy)node; 169 String pstr = pmap.get(gcp.predicate); 170 if (pstr == null) 171 pstr = gcp.predicate.toString(); 172 else 173 pstr = "Single \"" + pstr + "\""; 174 str = name + " " + pstr + ((gcp.cmin == 0) ? "*" : "+"); 175 print(node, str, depth); 176 } else if (node instanceof Pattern.BackRef) { 177 str = "GroupBackRef " + ((Pattern.BackRef)node).groupIndex / 2; 178 print(node, str, depth); 179 } else if (node instanceof Pattern.LastNode) { 180 print(node, "END", depth); 181 } else if (node == Pattern.accept) { 182 return; 183 } else { 184 print(node, name, depth); 185 } 186 node = node.next; 187 } 188 } 189 190 public static void main(String[] args) { 191 Pattern p = Pattern.compile(args[0]); 192 System.out.println(" Pattern: " + p); 193 walk(p.root, 0); 194 } 195 }