StreamTokenizer简单介绍

StreamTokenizer是Java中的一个类,用于将输入流(比如文件或者字符串)分解为词法单元(tokens)。它可以识别不同类型的词法单元,如数字、字符串、标识符、运算符等,并将它们以相应的类型进行分类。在处理文本文件或解析简单的文本格式时,StreamTokenizer非常有用。

StreamTokenizer提供了一种简单而有效的方法来读取和解析输入流,它具有灵活性和高效性,可以适应各种输入源的需要。通过逐个读取输入流中的字符,并根据字符的类型将其组合成不同类型的词法单元,StreamTokenizer使得文本解析变得更加方便和直观。

StreamTokenizer读取Java int范围内的整形

对于StreamTokenizer,使用他的nextToken()方法读取一个单词,使用StreamTokenizer对象的nval属性来获取单词,但是由于nval属性为double类型,需要使用(int)强制类型转换。

读取代码:

public class FastInputInt {
    /**
     * 构建最快的StreamTokenizer对象
     */
    public static final StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));

    /**
     * 封装的读取整数方法
     *
     * @return 读取的整数
     */
    public static int readInt() {
        try {
            // 固定写法
            st.nextToken();
            return (int) st.nval;
        } catch (Exception ignored) {
            // 忽略异常
        }
        return -1;
    }

    public static void main(String[] args) {
        // 测试输入StreamTokenizer快速读取 n 个数据
        int n = readInt();
        // 申请内存
        int[] data = new int[n];
        for (int i = 0; i < n; i++) {
            // 为数组赋值
            data[i] = readInt();
        }
        // 数据接收完毕, 使用Arrays.toString()查看数组的内容
        System.out.println(Arrays.toString(data));
    }
}

使用上方代码,可以读取下面类型的控制台输入

10
1 2 3 4 5 6 7 8 9 10

10
1
2
3
4
5
6
7
8
9
10

下面为测试截图,可以看到数组内容为刚刚在控制台输入的数字

java 解析出字符串中的数字 java字符串读取字符_java 解析出字符串中的数字

StreamTokenizer读取Java long范围内的整形

因为StreamTokenizer读取的数字类型会被存入一个类型为double,变量名为nval的变量中,也就是说,这个数字会受到double类型精度的影响,不能精确的存储long范围内的值,所以我们需要使用StreamTokenizer读取“数字字符串”,然后使用Long.parseLong()方法把这个读取到的字符串转为long。

我们可以调用StreamTokenizer对象的ordinaryChars('0','9')和wordChars('0','9')方法修改StreamTokenizer对象分隔单词的规则,使得'0'到'9'的字符不再识别为数字。

调用nextToken()方法后,读取StreamTokenizer对象的sval属性就可以拿到数字字符串。

读取long的代码:

public class FastInputLong {
    /**
     * 构建最快的StreamTokenizer对象
     */
    public static final StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));

    // 静态方法,配置StreamTokenizer
    static {
        // 为StreamTokenizer配置, 把 0 - 9 当成字符串识别
        st.ordinaryChars('0', '9');
        st.wordChars('0', '9');
    }
    /**
     * 封装的方法
     *
     * @return 读取的整数
     */
    public static long readLong() {
        try {
            // 固定写法
            st.nextToken();
            return Long.parseLong(st.sval);
        } catch (Exception ignored) {
            // 忽略异常
        }
        return -1;
    }

    public static void main(String[] args) {
        // 因为java数组最大长度不超过int最大值, 所以这里需要强制转为int让编译通过
        int n = (int) readLong();
        long[] data = new long[n];
        for (int i = 0; i < n; i++) {
            data[i] = readLong();
        }
        System.out.println(Arrays.toString(data));
    }
}

测试输入以下案例

10
1 2 3 4 5 6 7 8 9 10

运行结果:

java 解析出字符串中的数字 java字符串读取字符_java_02

测试读取大一点的整数,9223372036854775807为java long最大值

10
1000000000000000000
1111111111111111111
2222222222222222222
3333333333333333333
4444444444444444444
5555555555555555555
6666666666666666666
7777777777777777777
8888888888888888888
9223372036854775807

输出:

java 解析出字符串中的数字 java字符串读取字符_java 解析出字符串中的数字_03

我们再来测试一下如果不读取数字字符串,而是直接使用long val = st.nval;读取,看看会读取到什么内容。

public class DoubleReadTest {
    public static final StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));

    public static void main(String[] args) throws IOException {
        st.nextToken();
        int n = (int) st.nval;
        long[] data = new long[n];
        for (int i = 0; i < n; i++) {
            st.nextToken();
            data[i] =(long) st.nval;
        }
        for (long l : data) {
            System.out.println(l);
        }
    }
}

测试结果如下,可以看到输出的值与输入的值不同,存在精度问题,所以我们在要读取long范围内的数字时需要先读取到数字字符串再通过Long.parseLong()进行转换。

java 解析出字符串中的数字 java字符串读取字符_开发语言_04