Skip to content

Commit fde1ce2

Browse files
committed
text reader
1 parent ae171e6 commit fde1ce2

1 file changed

Lines changed: 194 additions & 0 deletions

File tree

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
package mil.nga.sf.util;
2+
3+
import java.io.IOException;
4+
import java.io.Reader;
5+
import java.io.StringReader;
6+
import java.util.logging.Level;
7+
import java.util.logging.Logger;
8+
9+
/**
10+
* Read through text string
11+
*
12+
* @author osbornb
13+
* @since 2.0.3
14+
*/
15+
public class TextReader {
16+
17+
/**
18+
* Logger
19+
*/
20+
private static final Logger logger = Logger
21+
.getLogger(TextReader.class.getName());
22+
23+
/**
24+
* Reader
25+
*/
26+
private final Reader reader;
27+
28+
/**
29+
* Next token cache for peeks
30+
*/
31+
private String nextToken;
32+
33+
/**
34+
* Next character number cache for between token caching
35+
*/
36+
private Integer nextCharacterNum;
37+
38+
/**
39+
* Constructor
40+
*
41+
* @param text
42+
* text
43+
*/
44+
public TextReader(String text) {
45+
this(new StringReader(text));
46+
}
47+
48+
/**
49+
* Constructor
50+
*
51+
* @param reader
52+
* reader
53+
*/
54+
public TextReader(Reader reader) {
55+
this.reader = reader;
56+
}
57+
58+
/**
59+
* Get the reader
60+
*
61+
* @return reader
62+
*/
63+
public Reader getReader() {
64+
return reader;
65+
}
66+
67+
/**
68+
* Close the text reader
69+
*/
70+
public void close() {
71+
try {
72+
reader.close();
73+
} catch (IOException e) {
74+
logger.log(Level.WARNING, "Failed to close text reader", e);
75+
}
76+
}
77+
78+
/**
79+
* Read the next token. Ignores whitespace until a non whitespace character
80+
* is encountered. Returns a contiguous block of token characters ( [a-z] |
81+
* [A-Z] | [0-9] | - | . ) or a non whitespace single character.
82+
*
83+
* @return token
84+
* @throws IOException
85+
* upon read error
86+
*/
87+
public String readToken() throws IOException {
88+
89+
String token = null;
90+
91+
// Get the next token, cached or read
92+
if (nextToken != null) {
93+
token = nextToken;
94+
nextToken = null;
95+
} else {
96+
97+
StringBuilder builder = null;
98+
99+
// Get the next character, cached or read
100+
int characterNum;
101+
if (nextCharacterNum != null) {
102+
characterNum = nextCharacterNum;
103+
nextCharacterNum = null;
104+
} else {
105+
characterNum = reader.read();
106+
}
107+
108+
// Continue while characters are left
109+
while (characterNum != -1) {
110+
111+
char character = (char) characterNum;
112+
113+
// Check if not the first character in the token
114+
if (builder != null) {
115+
116+
// Append token characters
117+
if (isTokenCharacter(character)) {
118+
builder.append(character);
119+
} else {
120+
// Complete the token before this character and cache
121+
// the character
122+
if (!Character.isWhitespace(character)) {
123+
nextCharacterNum = characterNum;
124+
}
125+
break;
126+
}
127+
128+
} else if (!Character.isWhitespace(character)) {
129+
130+
// First non whitespace character in the token
131+
builder = new StringBuilder();
132+
builder.append(character);
133+
134+
// Complete token if a single character token
135+
if (!isTokenCharacter(character)) {
136+
break;
137+
}
138+
139+
}
140+
141+
// Read the next character
142+
characterNum = reader.read();
143+
}
144+
145+
if (builder != null) {
146+
token = builder.toString();
147+
}
148+
149+
}
150+
return token;
151+
}
152+
153+
/**
154+
* Peek at the next token without reading past it
155+
*
156+
* @return next token
157+
* @throws IOException
158+
* upon read error
159+
*/
160+
public String peekToken() throws IOException {
161+
if (nextToken == null) {
162+
nextToken = readToken();
163+
}
164+
return nextToken;
165+
}
166+
167+
/**
168+
* Read a double
169+
*
170+
* @return double
171+
* @throws IOException
172+
* upon read error
173+
*/
174+
public double readDouble() throws IOException {
175+
String token = readToken();
176+
if (token == null) {
177+
throw new SFException("Failed to read expected double value");
178+
}
179+
return Double.parseDouble(token);
180+
}
181+
182+
/**
183+
* Check if the character is a contiguous block token character: ( [a-z] |
184+
* [A-Z] | [0-9] | - | . )
185+
*
186+
* @param c
187+
* @return
188+
*/
189+
private static boolean isTokenCharacter(char c) {
190+
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
191+
|| (c >= '0' && c <= '9') || c == '-' || c == '.';
192+
}
193+
194+
}

0 commit comments

Comments
 (0)