Petua Java 112: Tingkatkan tokenisasi rentetan kaya maklumat

Sebilangan besar pengaturcara Java telah menggunakan java.util.StringTokenizerkelas pada satu ketika atau yang lain. Ini adalah kelas praktikal yang pada dasarnya menandakan (memecahkan) rentetan input berdasarkan pemisah, dan membekalkan token atas permintaan. (Tokenization adalah tindakan mengubah urutan watak menjadi token yang difahami oleh program anda.)

Walaupun berguna, StringTokenizerfungsi terhad. Kelas hanya mencari pembatas dalam rentetan input dan memecahkan rentetan setelah pembatas dijumpai. Ia tidak memeriksa keadaan seperti apakah pembatas berada dalam substring, dan juga tidak mengembalikan token sebagai ""(panjang tali 0) setelah dua pembatas berturut-turut dijumpai di input. Untuk memenuhi batasan ini, platform Java 2 (JDK 1.2 dan seterusnya) hadir dengan BreakIteratorkelas, yang merupakan tokenizer yang lebih baik StringTokenizer. Oleh kerana kelas seperti itu tidak terdapat dalam JDK 1.1.x, pembangun sering menghabiskan banyak masa untuk menulis tokenizer asli yang memenuhi keperluan mereka. Dalam projek besar yang melibatkan pengendalian format data, tidak biasa apabila terdapat banyak kelas khusus seperti itu.

Petua ini bertujuan untuk membimbing anda melalui menulis tokenizer yang canggih, dengan menggunakan yang ada StringTokenizer.

Batasan StringTokenizer

Anda boleh membuat StringTokenizerdengan menggunakan salah satu daripada tiga pembina berikut:

  1. StringTokenizer(String sInput): Pecah pada ruang putih ( " ", "\t", "\n").
  2. StringTokenizer(String sInput, String sDelimiter): Putus pada sDelimiter.
  3. StringTokenizer(String sInput, String sDelimiter, boolean bReturnTokens): Tidak aktif sDelimiter, tetapi jika bReturnTokensdisetel ke true, pembatas juga dikembalikan sebagai tanda.

Pembina pertama tidak memeriksa sama ada rentetan input mengandungi substring. Apabila rentetan "hello. Today \"I am \" going to my home town"adalah tokenized pada ruang putih, hasilnya adalah dalam token hello., Today, "I, am, ", going, bukan hello., Today, "I am ", going.

Pembina kedua tidak memeriksa penampilan pembatas berturut-turut. Apabila rentetan "book, author, publication,,,date published"adalah tokenized pada ","itu, StringTokenizerpulangan empat token dengan nilai-nilai book, author, publication, dan date publishedbukannya enam nilai book, author, publication, "", "", dan date published, di mana ""cara rentetan panjang 0. Untuk mendapatkan enam, anda mesti menetapkan StringTokenizer's bReturnTokensparameter kepada benar.

Ciri menetapkan parameter ke true adalah penting kerana memberikan idea mengenai kehadiran pembatas berturut-turut. Sebagai contoh, jika data diperoleh secara dinamis dan digunakan untuk mengemas kini tabel dalam pangkalan data, di mana token input memetakan ke nilai lajur, maka kita tidak dapat memetakan token dengan lajur pangkalan data kerana kita tidak pasti lajur mana yang harus ditetapkan ke "". Sebagai contoh, kami ingin menambahkan rekod ke jadual dengan enam lajur, dan data input mengandungi dua pembatas berturut-turut. Hasil dari StringTokenizerkes ini adalah lima token (kerana dua pembatas berturut-turut mewakili token "", yang StringTokenizermengabaikan), dan kita harus menetapkan enam bidang. Kami juga tidak tahu di mana pembatas berturut-turut muncul, lantas, lajur mana yang harus ditetapkan "".

Pembina ketiga tidak akan berfungsi jika token itu sendiri sama (panjang dan nilainya) dengan pembatas dan berada dalam substring. Apabila rentetan "book, author, publication,\",\",date published"adalah tokenized (string ini direka ,sebagai tanda, yang adalah sama seperti pembatas dengannya) pada tali ,, hasilnya ialah book, author, publication, ", ", date published(dengan enam token) dan bukannya book, author, publication, ,(watak koma), date published(dengan lima token). Ingatlah, walaupun menetapkan bReturnTokens(parameter ketiga ke StringTokenizer) menjadi benar tidak akan membantu anda dalam hal ini.

Keperluan asas tokenizer

Sebelum berurusan dengan kod, anda perlu mengetahui keperluan asas tokenizer yang baik. Sejak pemaju Java digunakan untuk StringTokenizerkelas, tokenizer baik harus mempunyai semua kaedah berguna yang kelas menyediakan, seperti hasMoreTokens(), nextToken(), countTokens().

Kod untuk tip ini mudah dan kebanyakannya jelas. Pada dasarnya, saya telah menggunakan StringTokenizerkelas (dibuat dengan bReturnTokensset ke benar) secara dalaman dan menyediakan kaedah yang disebutkan di atas. Oleh kerana dalam beberapa kes pembatas diperlukan sebagai token (kes yang sangat jarang berlaku) sementara di beberapa kes tidak, tokenizer mesti membekalkan pembatas sebagai tanda apabila diminta. Apabila anda membuat PowerfulTokenizerobjek, hanya melewati rentetan input dan pembatas, ia menggunakan dalaman StringTokenizerdengan bReturnTokensset ke true. (Sebabnya adalah jika a StringTokenizerdibuat tanpa bReturnTokensdisetel ke true, maka ia terbatas dalam mengatasi masalah yang dinyatakan sebelumnya). Untuk mengendalikan tokenizer dengan betul, kod tersebut memeriksa sama ada bReturnTokensditetapkan menjadi benar di beberapa tempat (mengira jumlah token dan nextToken()).

Seperti yang anda perhatikan, PowerfulTokenizermelaksanakan Enumerationantara muka, dengan demikian menerapkan hasMoreElements()dan nextElement()kaedah yang hanya menyerahkan panggilan ke hasMoreTokens()dan nextToken(), masing-masing. (Dengan melaksanakan Enumerationantara muka, PowerfulTokenizermenjadi serasi dengan belakang StringTokenizer.) Mari kita pertimbangkan satu contoh. Katakan rentetan input adalah "hello, Today,,, \"I, am \", going to,,, \"buy, a, book\""dan pembatasnya ,. Rentetan ini apabila nilai pengembalian token seperti yang ditunjukkan dalam Jadual 1:

Jadual 1: Nilai yang Dikembalikan oleh Tokenized String
Jenis Bilangan Token Token

StringTokenizer

(bReturnTokens = true)

19 hello:,: Today:,:,:,: "I:,: am ":,: going to:,:,:,: "buy:,: a:,: book"(di sini watak :memisahkan token)

PowerfulTokenizer

(bReturnTokens = true)

13 hello:,:Today:,:"":"":I, am:,:going to:,:"":"":buy a book(di mana ""bermaksud tali panjang 0)

PowerfulTokenizer

(bReturnTokens = false)

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

String input mengandungi 11 ,karakter koma ( ), di antaranya tiga berada dalam substring dan empat muncul berturut-turut (seperti Today,,,membuat dua penampilan koma berturut-turut, koma pertama menjadi Todaypembatas). Berikut adalah logik dalam mengira bilangan token dalam PowerfulTokenizerkes tersebut:

  1. Sekiranya bReturnTokens=true, darabkan bilangan pembatas di dalam substring dengan 2 dan tolak jumlah itu dari jumlah sebenar untuk mendapatkan jumlah token. Sebabnya, untuk substring "buy, a, book", StringTokenizerakan mengembalikan lima token (iaitu, buy:,:a:,:book), sementara PowerfulTokenizerakan mengembalikan satu token (iaitu, buy, a, book). Perbezaannya adalah empat (iaitu 2 * bilangan pembatas di dalam substring). Formula ini sesuai untuk substring yang mengandungi pembatas Ketahui kes khas di mana token itu sendiri sama dengan pembatas; ini tidak boleh mengurangkan nilai kiraan.
  2. Begitu juga, untuk kes bReturnTokens=false, tolak nilai ungkapan [jumlah pembatas (11) - pembatas berturut-turut (4) + bilangan pembatas di dalam substring (3)] dari jumlah sebenar (19) untuk mendapatkan jumlah token. Oleh kerana kami tidak mengembalikan pembatas dalam kes ini, mereka (tanpa muncul secara berturut-turut atau di dalam substring) tidak berguna bagi kami, dan formula di atas memberi kami jumlah token (9).

Ingat dua formula ini, yang merupakan inti dari PowerfulTokenizer. Formula ini berfungsi untuk hampir semua kes masing-masing. Walau bagaimanapun, jika anda mempunyai keperluan yang lebih kompleks yang tidak sesuai untuk formula ini, maka anda mesti mempertimbangkan pelbagai contoh untuk mengembangkan formula anda sendiri sebelum masuk ke dalam pengkodan.

 // periksa sama ada pembatas berada dalam substring untuk (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 .