StringTokenizer源码阅读

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;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
package lsy; import java.util.StringTokenizer; /** * * @author lushuaiyin * */ public class StringTokenizerTest { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub String ivrdata="v1|v2|你好|哈哈"; getTokenizer1(ivrdata); System.out.println("----------------------------------"); getTokenizer2(ivrdata); System.out.println("----------------------------------"); getTokenizer2Array(ivrdata,"|"); System.out.println("----------------------------------"); String ssss="y1 y2 split实现 哈哈"; String[] strarr=getTokenizer2Array(ssss,""); } public static void getTokenizer1(String str){ StringTokenizer st = new StringTokenizer(str, "|",true); System.out.println("countTokens:"+st.countTokens()); int j=0; while(st.hasMoreTokens()){ System.out.println(j+":"+st.nextToken()); j++; } } public static void getTokenizer2(String str){ StringTokenizer st = new StringTokenizer(str, "|",false); System.out.println("countTokens:"+st.countTokens()); int j=0; while(st.hasMoreTokens()){ System.out.println(j+":"+st.nextToken()); j++; } } //////////////split实现////////// public static String[] getTokenizer2Array(String str,String splitStr){ String[] arr=null; if(str==null||str.trim().equals("")){ }else{ if(splitStr==null||splitStr.trim().equals("")){ splitStr=" "; } StringTokenizer st = new StringTokenizer(str, splitStr,false); System.out.println("ArraySize:"+st.countTokens()); arr=new String[st.countTokens()]; int j=0; while(st.hasMoreTokens()){ String temp=st.nextToken(); System.out.println(j+":"+temp); arr[j]=temp; j++; } } return arr; } /*api解释 public StringTokenizer(String str, String delim, boolean returnDelims) str是要处理的字符串; delim是分隔符; returnDelims 是否把分隔符也作为结果返回 (public StringTokenizer(String str, String delim) returnDelims默认false; StringTokenizer(String str)默认分隔符delim是 " \t\n\r\f",returnDelims是false) 遍历的api中注意,hasMoreElements()等于hasMoreTokens(); nextElement()等于nextToken()。可以 看源码验证。 打印: countTokens:7 0:v1 1:| 2:v2 3:| 4:你好 5:| 6:哈哈 ---------------------------------- countTokens:4 0:v1 1:v2 2:你好 3:哈哈 ---------------------------------- ArraySize:4 0:v1 1:v2 2:你好 3:哈哈 ---------------------------------- ArraySize:4 0:y1 1:y2 2:split实现 3:哈哈 */ }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值