1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.xnap.commons.util;
22
23 import java.util.NoSuchElementException;
24
25 /***
26 * Provides a string tokenizer that respects quotes. If a separator is followed
27 * by a quote the next token will extend to the next quote even if there are
28 * separators in between.
29 */
30 public class QuotedStringTokenizer
31 {
32 public static final String QUOTE = "\"";
33 public static final char QUOTE_CHAR = '"';
34
35 int index;
36 boolean returnSeparators;
37 private String separators;
38 private String text;
39 private int maxIndex;
40
41 /***
42 * Constructs a <code>QuotedStringTokenizer</code>.
43 *
44 * @see java.util.StringTokenizer
45 */
46 public QuotedStringTokenizer(String text, String separators, boolean returnSeparators)
47 {
48 this.text = text;
49 this.maxIndex = text.length() - 1;
50 this.separators = separators;
51 this.returnSeparators = returnSeparators;
52 }
53
54 /***
55 * Constructs a <code>QuotedStringTokenizer</code>.
56 *
57 * @see java.util.StringTokenizer
58 */
59 public QuotedStringTokenizer(String text, String separators)
60 {
61 this(text, separators, false);
62 }
63
64 /***
65 * Constructs a <code>QuotedStringTokenizer</code>.
66 *
67 * @see java.util.StringTokenizer
68 */
69 public QuotedStringTokenizer(String text)
70 {
71 this(text, " ", false);
72 }
73
74 public int countTokens()
75 {
76 int count = 0;
77 int i = index;
78 Token token;
79 while ((token = nextToken(i)) != null) {
80 count++;
81 i = token.nextIndex;
82 }
83 return count;
84 }
85
86 public boolean hasMoreTokens()
87 {
88 return nextToken(index) != null;
89 }
90
91 public String nextToken(String separators) {
92 this.separators = separators;
93 return nextToken();
94 }
95
96 public String nextToken()
97 {
98 Token token = nextToken(index);
99 if (token != null) {
100 index = token.nextIndex;
101 return token.text;
102 }
103 throw new NoSuchElementException();
104 }
105
106 protected Token nextToken(int index)
107 {
108 if (index > maxIndex) {
109 return null;
110 }
111
112 if (returnSeparators && separators.indexOf(text.charAt(index)) != -1) {
113 return new Token(text.substring(index, index + 1), index + 1);
114 }
115
116
117 int i = index;
118 boolean inQuotes = false;
119 StringBuilder token = new StringBuilder();
120
121
122 while (i <= maxIndex && separators.indexOf(text.charAt(i)) != -1) {
123 i++;
124 }
125
126 if (i > maxIndex) {
127 return null;
128 }
129
130 while(i <= maxIndex) {
131 char c = text.charAt(i);
132 if (separators.indexOf(c) != -1) {
133 if (inQuotes) {
134 token.append(c);
135 }
136 else {
137 return new Token(token.toString(), i);
138 }
139 }
140 else if (c == QUOTE_CHAR) {
141
142 inQuotes = !inQuotes;
143 }
144 else {
145 token.append(c);
146 }
147 i++;
148 }
149
150 return new Token(token.toString(), i);
151 }
152
153 class Token {
154
155 Token(String text, int nextIndex) {
156 this.text = text;
157 this.nextIndex = nextIndex;
158 }
159
160 String text;
161 int nextIndex;
162 }
163
164 }