StreamTokenizer的使用

关键点:
  • 类java.io.StreamTokenizer可以获取输入流并将其分析为Token(标记)。StreamTokenizer的nextToken方法将读取下一个标记
  • 默认情况下,StreamTokenizer认为下列内容是Token:字母、数字、除C和C++注释符号以外的其他符号。如符号“/”不是Token,注释后的内容也不是,而“\”是Token。单引号和双引号以及其中的内容,只能算是一个Token。
  • 要统计文件的字符数,不能简单地统计Token数,因为字符数不等于Token,按照Token的规定,引号中的内容就算是10页也算是一个Token。如果希望引号和引号中的内容都算作Token,应该通过StreamTokenizer的ordinaryCha方法将单引号和双引号当做普通字符处理。

例1:
//直接在程序中指定了文件输入路径:String fileName = “d:/ceshi.txt”;

package szu.edu;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.StreamTokenizer;

/**
 * 使用StreamTokenizer来统计文件中的字符数
 * StreamTokenizer 类获取输入流并将其分析为“标记”,允许一次读取一个标记。
 * 分析过程由一个表和许多可以设置为各种状态的标志控制。
 * 该流的标记生成器可以识别标识符、数字、引用的字符串和各种注释样式。
 * 
 *  默认情况下,StreamTokenizer认为下列内容是Token: 字母、数字、除C和C++注释符号以外的其他符号。
 *  如符号"/"不是Token,注释后的内容也不是,而"\"是Token。单引号和双引号以及其中的内容,只能算是一个Token。
 *  统计文章字符数的程序,不是简单的统计Token数就万事大吉,因为字符数不等于Token。按照Token的规定,
 *  引号中的内容就算是10页也算一个Token。如果希望引号和引号中的内容都算作Token,应该调用下面的代码:
 *     st.ordinaryChar('\'');
 * st.ordinaryChar('\"');
 */
public class StatisFileChars {

    /**
     * 统计字符数
     * @param fileName 文件名
     * @return    字符数
     */
    public static long statis(String fileName) {

        FileReader fileReader = null;
        try {
            fileReader = new FileReader(fileName);
            //创建分析给定字符流的标记生成器
            StreamTokenizer st = new StreamTokenizer(new BufferedReader(
                    fileReader));

            //ordinaryChar方法指定字符参数在此标记生成器中是“普通”字符。
            //下面指定单引号、双引号和注释符号是普通字符
            st.ordinaryChar('\'');
            st.ordinaryChar('\"');
            st.ordinaryChar('/');

            String s;
            int numberSum = 0;
            int wordSum = 0;
            int symbolSum = 0;
            int total = 0;
            //nextToken方法读取下一个Token.
            //TT_EOF指示已读到流末尾的常量。
            while (st.nextToken() != StreamTokenizer.TT_EOF) {
                //在调用 nextToken 方法之后,ttype字段将包含刚读取的标记的类型
                switch (st.ttype) {
                //TT_EOL指示已读到行末尾的常量。
                case StreamTokenizer.TT_EOL:
                    break;
                //TT_NUMBER指示已读到一个数字标记的常量
                case StreamTokenizer.TT_NUMBER:
                    //如果当前标记是一个数字,nval字段将包含该数字的值
                    s = String.valueOf((st.nval));
                    System.out.println(s);
                    numberSum += s.length();
                    break;
                //TT_WORD指示已读到一个文字标记的常量
                case StreamTokenizer.TT_WORD:
                    //如果当前标记是一个文字标记,sval字段包含一个给出该文字标记的字符的字符串
                    s = st.sval;
                    wordSum += s.length();
                    break;
                default:
                    //如果以上3中类型都不是,则为英文的标点符号
                    s = String.valueOf((char) st.ttype);
                    symbolSum += s.length();
                }
            }
            System.out.println("sum of number = " + numberSum);
            System.out.println("sum of word = " + wordSum);
            System.out.println("sum of symbol = " + symbolSum);
            total = symbolSum + numberSum + wordSum;
            System.out.println("Total = " + total);
            return total;
        } catch (Exception e) {
            e.printStackTrace();
            return -1;
        } finally {
            if (fileReader != null) {
                try {
                    fileReader.close();
                } catch (IOException e1) {
                }
            }
        }
    }

    public static void main(String[] args) {
        String fileName = "d:/ceshi.txt";
        StatisFileChars.statis(fileName);
    }
}

例2:
//没有指定文件的输入路径!自己在运行中输入路径。

package szu.edu;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;

public class Test1 {


    public static void main(String[] args) {

        try
        {
            System.out.println("请输入文件名:");
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            String filename = br.readLine();
            FileInputStream fileIn = new FileInputStream(filename);
            StreamTokenizer in = new StreamTokenizer(fileIn);


            //in.ordinaryChar(46);  
            //in.ordinaryChar(34);  
            int wordCount=0,numCount=0,punctionCount=0,count=0;  
            double token;  
            while ((token=in.nextToken())!=StreamTokenizer.TT_EOF)  
            {  
                count++;          
                if (token==StreamTokenizer.TT_WORD)  
                    wordCount++;  
                else if (token==StreamTokenizer.TT_NUMBER)  
                    numCount++;  
                else  
                    punctionCount++;     
            }  
            System.out.println("单词总数为:"+count);  
            System.out.println("单词数为:"+wordCount);  
            System.out.println("数字数为:"+numCount);  
            System.out.println("标点符号数为:"+punctionCount++);  
        }  
        catch (IOException e)  
        {  
            System.out.println(e.getMessage());              
        }           
    }
}

注意:除了以上的用法,还有一个输入效率比较高的用法,用于基本的输入操作,常用于ACM比赛中。

BufferedReader provides quite fast read operations for almost all problems. But this class may be used to read single characters and lines only. To read tokens and numbers you should use StringTokenizer or StreamTokenizer.

import java.io.*;

public class Main
{
    public static void main(String[] args) throws IOException
    {
        StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
        //PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
        int a, b;
        while(in.nextToken() != StreamTokenizer.TT_EOF)
        {
            a = (int)in.nval;
            in.nextToken();
            b = (int)in.nval;
            System.out.println("a + b = "+(a+b));
        }
        out.flush();
    }
}
注意

用Java解题一般用Scanner类来进行输入,但对时间要求严格的题,用它可能会超时,POJ1823的时候就遇到这样的问题,后改用StreamTokenizer类进行输入才能AC。后者处理输入的效率要高点。

小结

1、类java.io.StreamTokenizer可以获取输入流并将其分析为Token(标记)。
StreamTokenizer的nextToken方法读取下一个标记

2、默认情况下,StreamTokenizer认为下列内容是Token:字母、数字、除c和c++注释符号以外的其他符号。
如符号“/”不是Token,注释后的内容也不是,而”/”是Token。单引号和双引号以及其总的内容,只能算一个Token。

3、为了提高效率,使用BufferedReader,如下,创建StreamTokenizer对象

StreamTokenizer st =new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in))); 

4、为了从流中获取标记,可以调用StreamTokenizer的nextToken()方法。
调用nextToken()方法以后,如果标记是字符串,可用 String s=st.sval,如果是整数用 int n=(int) st.nval得到。

st.nextToken();     
int i = (int)st.nval;     //st.navl默认解析出的格式是double

st.nextToken();     
int j = (int)st.nval; 

st.nextToken();     
String s = st.sval;
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值