<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 10.6 `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章提供。 ## 10.6.1 `StringTokenizer` 盡管并不必要IO庫的一部分,但`StringTokenizer`提供了與`StreamTokenizer`極相似的功能,所以在這里一并講述。 `StringTokenizer`的作用是每次返回字符串內的一個記號。這些記號是一些由制表站、空格以及新行分隔的連續字符。因此,字符串`"Where is my cat?"`的記號分別是`"Where"`、`"is"`、`"my"`和`"cat?"`。與`StreamTokenizer`類似,我們可以指示`StringTokenizer`按照我們的愿望分割輸入。但對于`StringTokenizer`,卻需要向構造器傳遞另一個參數,即我們想使用的分隔字符串。通常,如果想進行更復雜的操作,應使用`StreamTokenizer`。 可用`nextToken()`向`StringTokenizer`對象請求字符串內的下一個記號。該方法要么返回一個記號,要么返回一個空字符串(表示沒有記號剩下)。 作為一個例子,下述程序將執行一個有限的句法分析,查詢鍵短語序列,了解句子暗示的是快樂亦或悲傷的含義。 ``` //: AnalyzeSentence.java // Look for particular sequences // within sentences. import java.util.*; public class AnalyzeSentence { public static void main(String[] args) { analyze("I am happy about this"); analyze("I am not happy about this"); analyze("I am not! I am happy"); analyze("I am sad about this"); analyze("I am not sad about this"); analyze("I am not! I am sad"); analyze("Are you happy about this?"); analyze("Are you sad about this?"); analyze("It's you! I am happy"); analyze("It's you! I am sad"); } static StringTokenizer st; static void analyze(String s) { prt("\nnew sentence >> " + s); boolean sad = false; st = new StringTokenizer(s); while (st.hasMoreTokens()) { String token = next(); // Look until you find one of the // two starting tokens: if(!token.equals("I") && !token.equals("Are")) continue; // Top of while loop if(token.equals("I")) { String tk2 = next(); if(!tk2.equals("am")) // Must be after I break; // Out of while loop else { String tk3 = next(); if(tk3.equals("sad")) { sad = true; break; // Out of while loop } if (tk3.equals("not")) { String tk4 = next(); if(tk4.equals("sad")) break; // Leave sad false if(tk4.equals("happy")) { sad = true; break; } } } } if(token.equals("Are")) { String tk2 = next(); if(!tk2.equals("you")) break; // Must be after Are String tk3 = next(); if(tk3.equals("sad")) sad = true; break; // Out of while loop } } if(sad) prt("Sad detected"); } static String next() { if(st.hasMoreTokens()) { String s = st.nextToken(); prt(s); return s; } else return ""; } static void prt(String s) { System.out.println(s); } } ///:~ ``` 對于準備分析的每個字符串,我們進入一個`while`循環,并將記號從那個字符串中取出。請注意第一個if語句,假如記號既不是`"I"`,也不是`"Are"`,就會執行`continue`(返回循環起點,再一次開始)。這意味著除非發現一個`"I"`或者`"Are"`,才會真正得到記號。大家可能想用`==`代替`equals()`方法,但那樣做會出現不正常的表現,因為`==`比較的是引用值,而`equals()`比較的是內容。 `analyze()`方法剩余部分的邏輯是搜索`"I am sad"`(我很憂傷、`"I am nothappy"`(我不快樂)或者`"Are you sad?"`(你悲傷嗎?)這樣的句法格式。若沒有`break`語句,這方面的代碼甚至可能更加散亂。大家應注意對一個典型的解析器來說,通常都有這些記號的一個表格,并能在讀取新記號的時候用一小段代碼在表格內移動。 無論如何,只應將`StringTokenizer`看作`StreamTokenizer`一種簡單而且特殊的簡化形式。然而,如果有一個字符串需要進行記號處理,而且`StringTokenizer`的功能實在有限,那么應該做的全部事情就是用`StringBufferInputStream`將其轉換到一個數據流里,再用它創建一個功能更強大的`StreamTokenizer`。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看