1 package org.cyclopsgroup.caff.token;
2
3
4
5
6
7
8 public class EscapingValueTokenizer implements ValueTokenizer {
9 private static enum ProcessingState {
10
11 ESCAPING,
12
13 READY,
14
15 WORD;
16 }
17
18 private final char delimiter;
19
20 private final char escaper;
21
22
23
24
25 public EscapingValueTokenizer() {
26 this(' ', '\\');
27 }
28
29
30
31
32
33 public EscapingValueTokenizer(char delimiter, char escaper) {
34 this.escaper = escaper;
35 this.delimiter = delimiter;
36 }
37
38 @Override
39 public String escape(String output) {
40 if (output.indexOf(escaper) == -1 && output.indexOf(delimiter) == -1) {
41 return output;
42 }
43 StringBuffer sb = new StringBuffer();
44 for (int i = 0, j = 0; i < output.length(); ) {
45 int e = output.indexOf(escaper, i);
46 int d = output.indexOf(delimiter, i);
47 if (e == -1 && d == -1) {
48 sb.append(output.substring(i));
49 break;
50 }
51 if (e >= 0 && d >= 0) {
52 j = Math.min(e, d);
53 } else {
54 j = Math.max(e, d);
55 }
56 sb.append(output.substring(i, j)).append(escaper).append(output.charAt(j));
57 i = ++j;
58 }
59 return sb.toString();
60 }
61
62
63 public final char getDelimiter() {
64 return delimiter;
65 }
66
67
68 public final char getEscaper() {
69 return escaper;
70 }
71
72 @Override
73 public void parse(CharSequence input, TokenEventHandler handler) {
74 ProcessingState state = ProcessingState.READY;
75 StringBuilder word = null;
76 int wordStart = 0;
77 for (int i = 0; i < input.length(); i++) {
78 char c = input.charAt(i);
79 switch (state) {
80 case READY:
81 if (c == delimiter) {
82 continue;
83 } else {
84 wordStart = i;
85 word = new StringBuilder();
86 if (c == escaper) {
87 state = ProcessingState.ESCAPING;
88 } else {
89 state = ProcessingState.WORD;
90 word.append(c);
91 }
92 }
93 break;
94 case WORD:
95 if (c == delimiter) {
96 state = ProcessingState.READY;
97 TokenEvent ev = new TokenEvent(word.toString(), wordStart, i, true);
98 handler.handleEvent(ev);
99 word = null;
100 } else if (c == escaper) {
101 state = ProcessingState.ESCAPING;
102 } else {
103 word.append(c);
104 }
105 break;
106 case ESCAPING:
107 state = ProcessingState.WORD;
108 word.append(c);
109 }
110 }
111 if (word != null) {
112 TokenEvent ev = new TokenEvent(word.toString(), wordStart, input.length(), false);
113 handler.handleEvent(ev);
114 }
115 }
116 }