StreamTokenizer

尽管StreamTokenizer并不是从InputStream或OutputStream衍生的,但它只随同InputStream工作,所以十分恰当地包括在库的IO部分中。
StreamTokenizer类用于将任何InputStream分割为一系列“记号”(Token)。这些记号实际是一些断续的文本块,中间用我们选择的任何东西分隔。例如,我们的记号可以是单词,中间用空白(空格)以及标点符号分隔。
下面是一个简单的程序,用于计算各个单词在文本文件中重复出现的次数:
 

//: SortedWordCount.java
// Counts words in a file, outputs
// results in sorted form.
import java.io.*;
import java.util.*;
import c08.*; // Contains StrSortVector

class Counter {
  private int i = 1;
  int read() { return i; }
  void increment() { i++; }
}

public class SortedWordCount {
  private FileInputStream file;
  private StreamTokenizer st;
  private Hashtable counts = new Hashtable();
  SortedWordCount(String filename)
    throws FileNotFoundException {
    try {
      file = new FileInputStream(filename);
      st = new StreamTokenizer(file);
      st.ordinaryChar('.');
      st.ordinaryChar('-');
    } catch(FileNotFoundException e) {
      System.out.println(
        "Could not open " + filename);
      throw e;
    }
  }
  void cleanup() {
    try {
      file.close();
    } catch(IOException e) {
      System.out.println(
        "file.close() unsuccessful");
    }
  }
  void countWords() {
    try {
      while(st.nextToken() !=
        StreamTokenizer.TT_EOF) {
        String s;
        switch(st.ttype) {
          case StreamTokenizer.TT_EOL:
            s = new String("EOL");
            break;
          case StreamTokenizer.TT_NUMBER:
            s = Double.toString(st.nval);
            break;
          case StreamTokenizer.TT_WORD:
            s = st.sval; // Already a String
            break;
          default: // single character in ttype
            s = String.valueOf((char)st.ttype);
        }
        if(counts.containsKey(s))
          ((Counter)counts.get(s)).increment();
        else
          counts.put(s, new Counter());
      }
    } catch(IOException e) {
      System.out.println(
        "st.nextToken() unsuccessful");
    }
  }
  Enumeration values() {
    return counts.elements();
  }
  Enumeration keys() { return counts.keys(); }
  Counter getCounter(String s) {
    return (Counter)counts.get(s);
  }
  Enumeration sortedKeys() {
    Enumeration e = counts.keys();
    StrSortVector sv = new StrSortVector();
    while(e.hasMoreElements())
      sv.addElement((String)e.nextElement());
    // This call forces a sort:
    return sv.elements();
  }
  public static void main(String[] args) {
    try {
      SortedWordCount wc =
        new SortedWordCount(args[0]);
      wc.countWords();
      Enumeration keys = wc.sortedKeys();
      while(keys.hasMoreElements()) {
        String key = (String)keys.nextElement();
        System.out.println(key + ": "
                 + wc.getCounter(key).read());
      }
      wc.cleanup();
    } catch(Exception e) {
      e.printStackTrace();
    }
  }
} ///:~

最好将结果按排序格式输出,但由于Java 1.0和Java 1.1都没有提供任何排序方法,所以必须由自己动手。这个目标可用一个StrSortVector方便地达成(创建于第8章,属于那一章创建的软件包的一部分。记住本书所有子目录的起始目录都必须位于类路径中,否则程序将不能正确地编译)。
为打开文件,使用了一个FileInputStream。而且为了将文件转换成单词,从FileInputStream中创建了一个StreamTokenizer。在StreamTokenizer中,存在一个默认的分隔符列表,我们可用一系列方法加入更多的分隔符。在这里,我们用ordinaryChar()指出“该字符没有特别重要的意义”,所以解析器不会把它当作自己创建的任何单词的一部分。例如,st.ordinaryChar('.')表示小数点不会成为解析出来的单词的一部分。在与Java配套提供的联机文档中,可以找到更多的相关信息。
在countWords()中,每次从数据流中取出一个记号,而ttype信息的作用是判断对每个记号采取什么操作——因为记号可能代表一个行尾、一个数字、一个字串或者一个字符。
找到一个记号后,会查询Hashtable counts,核实其中是否已经以“键”(Key)的形式包含了一个记号。若答案是肯定的,对应的Counter(计数器)对象就会增值,指出已找到该单词的另一个实例。若答案为否,则新建一个Counter——因为Counter构建器会将它的值初始化为1,正是我们计算单词数量时的要求。
SortedWordCount并不属于Hashtable(散列表)的一种类型,所以它不会继承。它执行的一种特定类型的操作,所以尽管keys()和values()方法都必须重新揭示出来,但仍不表示应使用那个继承,因为大量Hashtable方法在这里都是不适当的。除此以外,对于另一些方法来说(比如getCounter()——用于获得一个特定字串的计数器;又如sortedKeys()——用于产生一个枚举),它们最终都改变了SortedWordCount接口的形式。
在main()内,我们用SortedWordCount打开和计算文件中的单词数量——总共只用了两行代码。随后,我们为一个排好序的键(单词)列表提取出一个枚举。并用它获得每个键以及相关的Count(计数)。注意必须调用cleanup(),否则文件不能正常关闭。
采用了StreamTokenizer的第二个例子将在第17章提供。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索单词计数
, string
, enumeration
, 单词
, 一个
, counter
记号
,以便于您获取更多的相关知识。

时间: 2024-08-30 22:49:07

StreamTokenizer的相关文章

使用StreamTokenizer统计文件的字符数

 关键技术: 类java.io.StreamTokenizer可以获取输入流并将其分析为Token(标记).StreamTokenizer的nextToken方法将读取下一个标记 默认情况下,StreamTokenizer认为下列内容是Token:字母.数字.除C和C++注释符号以外的其他符号.如符号"/"不是Token,注释后的内容也不是,而"\"是Token.单引号和双引号以及其中的内容,只能算是一个Token. 要统计文件的字符数,不能简单地统计Token数,

什么时候不应该使用 XML(1)

xml <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />  当今计算世界趋向于任何所有正式规范和数据描述都使用 XML.本文作者 - XML 的忠实拥护者 - 提出了一个亵渎神明的问题:"XML 极权主义是个好主意吗?"在这篇观点性文章中,Terence Parr,jGuru 的共同创始人,演示了 XML 形成的糟糕的人机界面.他还提出了一些问题,这些

Stream Tokenizing(分解字符串)

stream|字符串 从sun网站看到的Stream TokenizingIn Tech Tips: June 23, 1998, an example of string tokenization was presented, using the class java.util.StringTokenizer. There's also another way to do tokenization, using java.io.StreamTokenizer. StreamTokenizer

将java代码生成html并且高亮显示

高亮显示|生成html import java.util.*;import java.io.*; public class java2html {    private static boolean comment=false;    private static boolean lineComment=false;    private static boolean START = true;    private static boolean END = false;    private

JSP/JAVABEAN+TOMCAT4.0.5+MYSQL组合建站总结

js|mysql 系统配置:win2000英文版+JDK1.4.1+TOMCAT4.0.5+APACHE2.043开发周期:竭尽全力,前后历时近15天.实现功能:1.    画廊:图片及相关文字的提交,分页显示,删除.2.    相册:相册主题的新建,相片及相关文字的提交,分主题,分页显示,删除.3.    文章/新闻发布系统:文章分类目录的新建,文章的分类显示,文章的编辑,删除.(具有10个插图上传能力)4.    文章按主题搜索及模糊查找.5.    将硬盘一指定目录以列表的形式显示出来,自

调整JavaTM 的I/O性能(三)(zt)

性能 压缩 Java提供了对字节流进行压缩和解压缩的类.它们可以在java.util.zip包中被找到,同时也作为Jar文件的基 础(Jar文件是具有一个清单的Zip文件). 以下的程序采用一个单一的输入文件,并且生成一个压缩了的Zip输出文件,该程序带有一个表示输入文件的 入口项.       import java.io.*;       import java.util.zip.*;       public class compress {           public static

调整JavaTM 的I/O性能(四)(zt)

性能 第二个程序比第一个大约快20%,代价是不得不写一些技巧性的底层代码. StreamTokenizer是一个杂和的类,因为它从基于字符的流中读取(象BufferedReader)数据,但同时又以字节进 行操作,即尽管它们是字母,也要用两字节的值来处理所有的字符(大于0xff). 序列化 序列化使用一个标准格式,将任意一个Java数据结构转换为字节流.例如,如下程序输出一个随机的整数数 组:       import java.io.*;       import java.util.*;  

一个java类方法提取器

很少需要直接使用反射工具:之所以在语言中提供它们,仅仅是为了支持其他Java特性,比如对象序列化(第10章介绍).Java Beans以及RMI(本章后面介绍).但是,我们许多时候仍然需要动态提取与一个类有关的资料.其中特别有用的工具便是一个类方法提取器.正如前面指出的那样,若检视类定义源码或者联机文档,只能看到在那个类定义中被定义或覆盖的方法,基础类那里还有大量资料拿不到.幸运的是,"反射"做到了这一点,可用它写一个简单的工具,令其自动展示整个接口.下面便是具体的程序:   //:

修改数据流的行为

在Java 1.0中,数据流通过FilterInputStream和FilterOutputStream的"装饰器"(Decorator)子类适应特定的需求.Java 1.1的IO流沿用了这一思想,但没有继续采用所有装饰器都从相同"filter"(过滤器)基础类中衍生这一做法.若通过观察类的层次结构来理解它,这可能令人出现少许的困惑. 在下面这张表格中,对应关系比上一张表要粗糙一些.之所以会出现这个差别,是由类的组织造成的:尽管BufferedOutputStrea