Tip Java 112: Tingkatkan tokenisasi string kaya informasi

Sebagian besar programmer Java telah menggunakan java.util.StringTokenizerkelas pada beberapa waktu atau waktu lain. Ini adalah kelas praktis yang pada dasarnya memberi tokenize (memecah) string input berdasarkan pemisah, dan memasok token berdasarkan permintaan. (Tokenisasi adalah tindakan mengubah urutan karakter menjadi token yang dipahami oleh program Anda.)

Meskipun praktis, StringTokenizerfungsinya terbatas. Kelas hanya mencari pembatas dalam string masukan dan memutus string setelah pembatas ditemukan. Itu tidak memeriksa kondisi seperti apakah pembatas berada dalam substring, juga tidak mengembalikan token sebagai ""(panjang string 0) setelah dua pembatas berturut-turut ditemukan dalam input. Untuk memenuhi batasan ini, platform Java 2 (JDK 1.2 dan seterusnya) hadir dengan BreakIteratorkelas, yang merupakan tokenizer yang lebih baik StringTokenizer. Karena kelas seperti itu tidak ada di JDK 1.1.x, pengembang sering menghabiskan banyak waktu untuk menulis tokenizer asli yang memenuhi persyaratan mereka. Dalam proyek besar yang melibatkan penanganan format data, tidak jarang menemukan banyak kelas yang disesuaikan seperti itu.

Tip ini bertujuan untuk memandu Anda melalui penulisan tokenizer yang canggih, menggunakan yang sudah ada StringTokenizer.

Batasan StringTokenizer

Anda dapat membuat StringTokenizerdengan menggunakan salah satu dari tiga konstruktor berikut:

  1. StringTokenizer(String sInput): Jeda di spasi putih ( " ", "\t", "\n").
  2. StringTokenizer(String sInput, String sDelimiter): Istirahat sDelimiter.
  3. StringTokenizer(String sInput, String sDelimiter, boolean bReturnTokens): Breaks on sDelimiter, tetapi jika bReturnTokensdisetel ke true, maka pembatas juga dikembalikan sebagai token.

Konstruktor pertama tidak memeriksa apakah string input berisi substring. Ketika string "hello. Today \"I am \" going to my home town"tokenized di ruang putih, hasilnya adalah dalam token hello., Today, "I, am, ", going, bukan hello., Today, "I am ", going.

Konstruktor kedua tidak memeriksa kemunculan pembatas yang berurutan. Ketika string "book, author, publication,,,date published"tokenized pada ",", yang StringTokenizerkembali empat token dengan nilai-nilai book, author, publication, dan date publishedbukannya enam nilai-nilai book, author, publication, "", "", dan date published, di mana ""sarana string dengan panjang 0. Untuk mendapatkan enam, Anda harus mengatur StringTokenizer's bReturnTokensparameter untuk benar.

Fitur pengaturan parameter ke true penting karena memberikan gambaran tentang keberadaan pembatas yang berurutan. Misalnya, jika data diperoleh secara dinamis dan digunakan untuk memperbarui tabel dalam database, di mana token input dipetakan ke nilai kolom, maka kami tidak dapat memetakan token dengan kolom database karena kami tidak yakin kolom mana yang harus disetel kepada "". Misalnya, kami ingin menambahkan record ke tabel dengan enam kolom, dan data input berisi dua pembatas yang berurutan. Hasil dari StringTokenizerkasus ini adalah lima token (karena dua pembatas berturut-turut mewakili token "", yang StringTokenizermengabaikan), dan kita harus menyetel enam bidang. Kami juga tidak tahu di mana pemisah berurutan muncul, jadi, kolom mana yang harus disetel "".

Konstruktor ketiga tidak akan berfungsi jika token itu sendiri sama (panjang dan nilainya) dengan pembatas dan berada dalam substring. Ketika string "book, author, publication,\",\",date published"tokenized (string ini mengandung ,sebagai tanda, yang sama dengan pembatas nya) pada string ,, hasilnya adalah book, author, publication, ", ", date published(dengan enam token) bukan book, author, publication, ,(karakter koma), date published(dengan lima token). Pikiran Anda, bahkan mengatur bReturnTokens(parameter ketiga ke StringTokenizer) menjadi benar tidak akan membantu Anda dalam kasus ini.

Kebutuhan dasar tokenizer

Sebelum berurusan dengan kode, Anda harus mengetahui kebutuhan dasar tokenizer yang baik. Karena pengembang Java digunakan untuk StringTokenizerkelas, sebuah tokenizer yang baik harus memiliki semua metode yang berguna kelas menyediakan, seperti hasMoreTokens(), nextToken(), countTokens().

Kode untuk tip ini sederhana dan sebagian besar sudah cukup jelas. Pada dasarnya, saya telah menggunakan StringTokenizerkelas (dibuat dengan bReturnTokensset ke true) secara internal dan memberikan metode yang disebutkan di atas. Karena dalam beberapa kasus pembatas diperlukan sebagai token (kasus yang sangat jarang terjadi) sementara dalam beberapa kasus tidak, tokenizer harus menyediakan pembatas sebagai token atas permintaan. Saat Anda membuat PowerfulTokenizerobjek, hanya meneruskan string input dan pembatas, secara internal menggunakan StringTokenizerdengan bReturnTokensset ke true. (Alasannya adalah jika a StringTokenizerdibuat tanpa bReturnTokensset true, maka terbatas dalam mengatasi masalah yang disebutkan sebelumnya). Untuk menangani tokenizer dengan benar, kode memeriksa apakah bReturnTokensdisetel ke true di beberapa tempat (menghitung jumlah token dan nextToken()).

Seperti yang mungkin telah Anda amati, PowerfulTokenizermengimplementasikan Enumerationantarmuka, sehingga mengimplementasikan metode hasMoreElements()dan nextElement()yang hanya mendelegasikan panggilan ke hasMoreTokens()dan nextToken(), masing-masing. (Dengan mengimplementasikan Enumerationantarmuka, PowerfulTokenizermenjadi kompatibel dengan mundur StringTokenizer.) Mari pertimbangkan sebuah contoh. Katakanlah string input adalah "hello, Today,,, \"I, am \", going to,,, \"buy, a, book\""dan pembatasnya adalah ,. String ini ketika tokenized mengembalikan nilai seperti yang ditunjukkan pada Tabel 1:

Tabel 1: Nilai yang Dikembalikan oleh Tokenized String
Tipe Jumlah Token Token

StringTokenizer

(bReturnTokens = true)

19 hello:,: Today:,:,:,: "I:,: am ":,: going to:,:,:,: "buy:,: a:,: book"(disini karakter :memisahkan token)

PowerfulTokenizer

(bReturnTokens = true)

13 hello:,:Today:,:"":"":I, am:,:going to:,:"":"":buy a book(di mana ""berarti string dengan panjang 0)

PowerfulTokenizer

(bReturnTokens = false)

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

String input berisi 11 ,karakter koma ( ), tiga di antaranya berada di dalam substring dan empat muncul secara berurutan (seperti yang Today,,,membuat dua koma muncul berturut-turut, koma pertama adalah Todaypembatas). Berikut logika dalam menghitung jumlah token pada PowerfulTokenizercase:

  1. Dalam kasus bReturnTokens=true, kalikan jumlah pembatas di dalam substring dengan 2 dan kurangi jumlah itu dari total sebenarnya untuk mendapatkan jumlah token. Alasannya, untuk substring "buy, a, book", StringTokenizerakan mengembalikan lima token (yaitu, buy:,:a:,:book), sementara PowerfulTokenizerakan mengembalikan satu token (yaitu, buy, a, book). Perbedaannya adalah empat (yaitu, 2 * jumlah pembatas di dalam substring). Rumus ini berlaku untuk setiap substring yang berisi pembatas. Waspadai kasus khusus di mana token itu sendiri sama dengan pembatas; ini seharusnya tidak mengurangi nilai hitungan.
  2. Demikian pula, untuk kasus bReturnTokens=false, kurangi nilai ekspresi [pembatas total (11) - pembatas berurutan (4) + jumlah pembatas di dalam substring (3)] dari total sebenarnya (19) untuk mendapatkan jumlah token. Karena kita tidak mengembalikan pembatas dalam kasus ini, mereka (tanpa muncul secara berurutan atau di dalam substring) tidak berguna bagi kita, dan rumus di atas memberi kita jumlah token (9).

Ingat dua rumus ini, yang merupakan inti dari PowerfulTokenizer. Rumus ini berfungsi untuk hampir semua kasus masing-masing. Namun, jika Anda memiliki persyaratan yang lebih kompleks yang tidak cocok untuk rumus ini, Anda harus mempertimbangkan berbagai contoh untuk mengembangkan rumus Anda sendiri sebelum beralih ke pengkodean.

 // periksa apakah 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 .