Javaのヒント112:情報が豊富な文字列のトークン化を改善する

ほとんどのJavaプログラマーは、java.util.StringTokenizerいつかこのクラスを使用しています。これは、基本的にセパレータに基づいて入力文字列をトークン化(分割)し、要求に応じてトークンを提供する便利なクラスです。(トークン化は、文字のシーケンスをプログラムが理解できるトークンに変換する行為です。)

便利ですが、StringTokenizerの機能は制限されています。クラスは単に入力文字列で区切り文字を探し、区切り文字が見つかると文字列を分割します。区切り文字が部分文字列内にあるかどうかなどの条件をチェックしません""。また、入力で2つの連続する区切り文字が見つかると、トークンを(文字列の長さ0)として返しません。これらの制限を満たすために、Java 2プラットフォーム(JDK 1.2以降)にはBreakIteratorクラスが付属していStringTokenizerます。これは、よりも改良されたトークナイザーです。このようなクラスはJDK1.1.xには存在しないため、開発者は要件を満たすオリジナルのトークナイザーの作成に多くの時間を費やすことがよくあります。データ形式の処理を伴う大規模なプロジェクトでは、そのようなカスタマイズされたクラスがたくさん浮かんでいるのを見つけるのは珍しいことではありません。

このヒントは、既存のを使用して、洗練されたトークナイザーを作成する方法を説明することを目的としていますStringTokenizer

StringTokenizerの制限

StringTokenizer次の3つのコンストラクターのいずれかを使用してを作成できます。

  1. StringTokenizer(String sInput):空白で中断します(" ", "\t", "\n")。
  2. StringTokenizer(String sInput, String sDelimiter):で中断しsDelimiterます。
  3. StringTokenizer(String sInput, String sDelimiter, boolean bReturnTokens):で中断しますがsDelimiter、がbReturnTokenstrueに設定されている場合、区切り文字もトークンとして返されます。

最初のコンストラクターは、入力文字列に部分文字列が含まれているかどうかをチェックしません。文字列がとき"hello. Today \"I am \" going to my home town"空白にトークン化され、その結果はトークンであるhello.Today"Iam"going、代わりにhello.Today"I am "going

2番目のコンストラクターは、区切り文字の連続した出現をチェックしません。文字列がとき"book, author, publication,,,date published"にトークン化され","StringTokenizer値を持つリターン4つのトークンはbookauthorpublication、とdate published代わりに6つの値のbookauthorpublication""""、とdate published、どこ""長さ0の手段文字列が6を取得するには、設定しなければならないStringTokenizerbReturnTokensパラメータをtrueに。

パラメータをtrueに設定する機能は、連続する区切り文字の存在についてのアイデアを提供するため、重要です。たとえば、データが動的に取得され、入力トークンが列の値にマップされるデータベース内のテーブルを更新するために使用される場合、どの列を設定する必要があるかわからないため、トークンをデータベースの列にマップすることはできません。に""。たとえば、6列のテーブルにレコードを追加し、入力データに2つの連続する区切り文字が含まれているとします。結果StringTokenizer、この場合には、5つの(二つの連続する区切り文字は、トークンを表すように、トークンである""StringTokenizer無視)、我々は、6つのフィールドを設定しなければなりません。また、連続する区切り文字がどこに表示されるかもわからないため、どの列をに設定する必要があります""

3番目のコンストラクターは、トークン自体が(長さと値が)区切り文字と等しく、部分文字列にある場合は機能しません。文字列が場合"book, author, publication,\",\",date published"(この文字列が含まれてトークン化され,た文字列にその区切り文字と同じである、トークンとして),、結果はbookauthorpublication""date published(6つのトークンで)代わりにbookauthorpublication,(コンマ文字)、 date published(と5つのトークン)。この場合、bReturnTokens(3番目のパラメーターをStringTokenizer)trueに設定しても役に立ちません。

トークナイザーの基本的なニーズ

コードを扱う前に、優れたトークナイザーの基本的なニーズを知る必要があります。 Java開発者がするために使用されているのでStringTokenizer、クラス、良いのトークナイザは、次のような、クラスが提供するすべての有用なメソッドを持っていなければなりませんhasMoreTokens()nextToken()countTokens()

このヒントのコードは単純で、ほとんどの場合自明です。基本的に、私はStringTokenizerクラス(bReturnTokenstrueに設定して作成)を内部的に使用し、上記のメソッドを提供しました。区切り文字がトークンとして必要な場合もあれば(非常にまれなケース)、そうでない場合もあるため、トークナイザーは要求に応じて区切り文字をトークンとして提供する必要があります。PowerfulTokenizer入力文字列と区切り文字のみを渡してオブジェクトを作成すると、内部でStringTokenizerwithbReturnTokensがtrueに設定されて使用されます。 (これは、aStringTokenizerbReturnTokenstrueに設定されずに作成された場合、前述の問題の克服に制限があるためです)。bReturnTokensトークナイザーを適切に処理するために、コードはいくつかの場所でtrueに設定されているかどうかをチェックします(トークンの総数とを計算しますnextToken())。

お気づきかもしれませんがPowerfulTokenizerEnumerationインターフェースを実装し、呼び出しをそれぞれとに委任するだけのメソッドhasMoreElements()nextElement()メソッドを実装します。(インターフェースを実装することにより、との下位互換性があります。)例を考えてみましょう。入力文字列がであり、区切り文字がであるとします。トークン化された場合、この文字列は表1に示す値を返します。hasMoreTokens()nextToken()EnumerationPowerfulTokenizerStringTokenizer"hello, Today,,, \"I, am \", going to,,, \"buy, a, book\"",

表1:トークン化された文字列によって返される値
タイプ トークンの数 トークン

StringTokenizer

(bReturnTokens = true)

19 hello:,: Today:,:,:,: "I:,: am ":,: going to:,:,:,: "buy:,: a:,: book"(ここでは、文字:がトークンを区切ります)

PowerfulTokenizer

(bReturnTokens = true)

13 hello:,:Today:,:"":"":I, am:,:going to:,:"":"":buy a book(ここで、""は長さ0の文字列を意味します)

PowerfulTokenizer

(bReturnTokens = false)

9 hello:Today:"":"":I am:going to:"":"":buy a book

入力文字列には11個のコンマ(,)文字が含まれ、そのうち3個は部分文字列内にあり、4個は連続して表示されToday,,,ます(2回連続してコンマが表示され、最初のコンマはToday区切り文字です)。このPowerfulTokenizer場合のトークン数を計算するロジックは次のとおりです。

  1. の場合、bReturnTokens=true部分文字列内の区切り文字の数に2を掛け、実際の合計からその量を引いて、トークン数を取得します。その理由は、部分文字列の"buy, a, book"場合、StringTokenizer5つのトークン(つまり、buy:,:a:,:bookPowerfulTokenizerを返し、1つのトークン(つまり、buy, a, book)を返します。違いは4つです(つまり、2 *部分文字列内の区切り文字の数)。この式は、区切り文字を含むすべての部分文字列に適しています。トークン自体が区切り文字と等しい特殊なケースに注意してください。これはカウント値をデクリメントするべきではありません。
  2. 同様に、の場合bReturnTokens=false、式[合計区切り文字(11)-連続区切り文字(4)+部分文字列内の区切り文字の数(3)]の値を実際の合計(19)から減算して、トークン数を取得します。この場合、区切り文字を返さないため、区切り文字は(連続してまたは部分文字列内に表示されることなく)役に立たず、上記の式からトークンの総数(9)が得られます。

の心臓部であるこれらの2つの式を覚えておいてくださいPowerfulTokenizer。これらの式は、ほぼすべての場合に機能します。ただし、これらの式に適さないより複雑な要件がある場合は、コーディングに突入する前に、さまざまな例を検討して独自の式を開発する必要があります。

 //区切り文字が(int i = 1; iの部分文字列内にあるかどうかを確認します
   
    

The nextToken() method gets tokens by using StringTokenizer.nextToken, and checks for the double quote character in the token. If the method finds those characters, it gets more tokens until it doesn't find any with a double quote. It also stores the token in a variable (sPrevToken; see source code) for checking consecutive delimiter appearances. If nextToken() finds consecutive tokens that are equal to the delimiter, then it returns "" (string with length 0) as the token.

Similarly, the hasMoreTokens() method checks whether the number of tokens already requested is less than the total number of tokens.

Save development time

This article has taught you how to easily write a powerful tokenizer. Using these concepts, you can write complex tokenizers quickly, thus saving you significant development time.

Bhabani Padhi is a Java architect and programmer currently working on Web and enterprise application development using Java technology at UniteSys, Australia. Previously he worked at Baltimore Technologies, Australia on e-security product development and at Fujitsu, Australia on an EJB server development project. Bhabani's interests include distributed computing, mobile, and Web application development using Java technology.

Learn more about this topic

  • Get the source code for this tip

    //images.techhive.com/downloads/idge/imported/article/jvw/2001/06/powerfultokenizer.java

  • For more information on BreakIterator

    //java.sun.com/products/jdk/1.2/docs/api/java/text/BreakIterator.html

  • View all previous Java Tips and submit your own

    //www.javaworld.com/javatips/jw-javatips.index.html

  • For more Intro Level articles, visit JavaWorld's Topical Index

    //www.javaworld.com/javaworld/topicalindex/jw-ti-introlevel.html

  • Learn Java from the ground up in JavaWorld's Java 101 column

    //www.javaworld.com/javaworld/topicalindex/jw-ti-java101.html

  • Java experts answer your toughest Java questions in JavaWorld's Java Q&A column

    //www.javaworld.com/javaworld/javaqa/javaqa-index.html

  • Sign up for the JavaWorld This Week free weekly email newsletter to find out what's new on JavaWorld

    //www.idg.net/jw-subscribe

This story, "Java Tip 112: Improve tokenization of information-rich strings" was originally published by JavaWorld .