StringTokenizer是为了保持兼容性而保留下来的一个类,不推荐使用,官方推荐用String的split或用正则表达式替换。
在使用java做OJ的时候,由于Scanner是按字符扫描,导致效率很低,很多题报TLE(Time Limit Exceed),尝试用String的split方法结合数组做替换后,发现在处理效率上,还是StringTokenizer的效率较高,如下是完整的源码及批注,供参考:
package java.util;
import java.lang.*;
public class StringTokenizer implements Enumeration<Object> {
private int currentPosition;//当前位置
private int newPosition;//新位置
private int maxPosition;//最大位置
private String str;//操作的字符串
private String delimiters;//分隔符
private boolean retDelims;//标记分隔符是否也可以做为token返回
private boolean delimsChanged;
private int maxDelimCodePoint;
private boolean hasSurrogates = false;
private int[] delimiterCodePoints;
private void setMaxDelimCodePoint() {
if (delimiters == null) {
maxDelimCodePoint = 0;
return;
}
int m = 0;//save the max char of delimiter while looping
int c;
int count = 0;
for (int i = 0; i < delimiters.length(); i += Character.charCount(c)) {
c = delimiters.charAt(i);
// in range of UTF-16 encoding Unicode high-surrogate code unit to Unicode low-surrogate code unit
// 如果字符需要使用两个UTF-16即4个字节才能表示时,称为代理对
if (c >= Character.MIN_HIGH_SURROGATE && c <= Character.MAX_LOW_SURROGATE) {
c = delimiters.codePointAt(i);
hasSurrogates = true;
}
if (m < c)
m = c;
count++;
}
maxDelimCodePoint = m;
//如果存在代理对,把所有分隔符存储在delimiterCodePoints中
if (hasSurrogates) {
delimiterCodePoints = new int[count];
for (int i = 0, j = 0; i < count; i++, j += Character.charCount(c)) {
c = delimiters.codePointAt(j);
delimiterCodePoints[i] = c;
}
}
}
public StringTokenizer(String str, String delim, boolean returnDelims) {
currentPosition = 0;
newPosition = -1;
delimsChanged = false;
this.str = str;
maxPosition = str.length();
delimiters = delim;
retDelims = returnDelims;
setMaxDelimCodePoint();
}
public StringTokenizer(String str, String delim) {
this(str, delim, false);
}
public StringTokenizer(String str) {
this(str, " \t\n\r\f", false);
}
//从startPos位置开始扫描,如果是分隔符就跳过,直到找到非分隔符的字符,返回对应的位置
private int skipDelimiters(int startPos) {
if (delimiters == null)
throw new NullPointerException();
int position = startPos;
while (!retDelims && position < maxPosition) {
if (!hasSurrogates) {
char c = str.charAt(position);
if ((c > maxDelimCodePoint) || (delimiters.indexOf(c) < 0))
break;
position++;
} else {
int c = str.codePointAt(position);
if ((c > maxDelimCodePoint) || !isDelimiter(c)) {
break;
}
position += Character.charCount(c);
}
}
return position;
}
//从startPos开始扫描,返回遇到的第一个分隔符的位置
private int scanToken(int startPos) {
int position = startPos;
//从Position开始扫描下一个分隔符
while (position < maxPosition) {
if (!hasSurrogates) {
char c = str.charAt(position);
if ((c <= maxDelimCodePoint) && (delimiters.indexOf(c) >= 0))
break;
position++;
} else {
int c = str.codePointAt(position);
if ((c <= maxDelimCodePoint) && isDelimiter(c))
break;
position += Character.charCount(c);
}
}
//如果从扫描位置一开始就是分隔符,并且需要返回分隔符,开始扫描从当前位置开始的第一个非分隔符字符位置
if (retDelims && (startPos == position)) {
if (!hasSurrogates) {
char c = str.charAt(position);
if ((c <= maxDelimCodePoint) && (delimiters.indexOf(c) >= 0))
position++;
} else {
int c = str.codePointAt(position);
if ((c <= maxDelimCodePoint) && isDelimiter(c))
position += Character.charCount(c);
}
}
return position;
}
//在存在代理对的情况下,使用该函数判断当前字符是否是分隔符
private boolean isDelimiter(int codePoint) {
for (int i = 0; i < delimiterCodePoints.length; i++) {
if (delimiterCodePoints[i] == codePoint) {
return true;
}
}
return false;
}
/**是否还有token*/
public boolean hasMoreTokens() {
newPosition = skipDelimiters(currentPosition);
return (newPosition < maxPosition);
}
public String nextToken() {
//调用hasMoreTokens时会更新newPosition,如果没有显式调用hasMoreTokens,则直接从当前位置开始扫描选择下一个分隔符的位置
currentPosition = (newPosition >= 0 && !delimsChanged) ? newPosition : skipDelimiters(currentPosition);
delimsChanged = false;
newPosition = -1;//重置的目的是判断有没有显式调用nextToken
if (currentPosition >= maxPosition)
throw new NoSuchElementException();
int start = currentPosition;
//在找到字符串的起始位置后,扫描获取下一个分隔符的位置
currentPosition = scanToken(currentPosition);
return str.substring(start, currentPosition);
}
/**下一个token*/
public String nextToken(String delim) {
delimiters = delim;
delimsChanged = true;
setMaxDelimCodePoint();
return nextToken();
}
/**是否还有元素*/
public boolean hasMoreElements() {
return hasMoreTokens();
}
/**下一个元素*/
public Object nextElement() {
return nextToken();
}
/**计算Tokens的数量*/
public int countTokens() {
int count = 0;
int currpos = currentPosition;
while (currpos < maxPosition) {
currpos = skipDelimiters(currpos);
if (currpos >= maxPosition)
break;
currpos = scanToken(currpos);
count++;
}
return count;
}
}