Sebagian besar programmer Java telah menggunakan java.util.StringTokenizer
kelas 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, StringTokenizer
fungsinya 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 BreakIterator
kelas, 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 StringTokenizer
dengan menggunakan salah satu dari tiga konstruktor berikut:
StringTokenizer(String sInput)
: Jeda di spasi putih (" ", "\t", "\n"
).StringTokenizer(String sInput, String sDelimiter)
: IstirahatsDelimiter
.StringTokenizer(String sInput, String sDelimiter, boolean bReturnTokens)
: Breaks onsDelimiter
, tetapi jikabReturnTokens
disetel 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 StringTokenizer
kembali empat token dengan nilai-nilai book
, author
, publication
, dan date published
bukannya enam nilai-nilai book
, author
, publication
, ""
, ""
, dan date published
, di mana ""
sarana string dengan panjang 0. Untuk mendapatkan enam, Anda harus mengatur StringTokenizer
's bReturnTokens
parameter 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 StringTokenizer
kasus ini adalah lima token (karena dua pembatas berturut-turut mewakili token ""
, yang StringTokenizer
mengabaikan), 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 StringTokenizer
kelas, 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 StringTokenizer
kelas (dibuat dengan bReturnTokens
set 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 PowerfulTokenizer
objek, hanya meneruskan string input dan pembatas, secara internal menggunakan StringTokenizer
dengan bReturnTokens
set ke true. (Alasannya adalah jika a StringTokenizer
dibuat tanpa bReturnTokens
set true, maka terbatas dalam mengatasi masalah yang disebutkan sebelumnya). Untuk menangani tokenizer dengan benar, kode memeriksa apakah bReturnTokens
disetel ke true di beberapa tempat (menghitung jumlah token dan nextToken()
).
Seperti yang mungkin telah Anda amati, PowerfulTokenizer
mengimplementasikan Enumeration
antarmuka, sehingga mengimplementasikan metode hasMoreElements()
dan nextElement()
yang hanya mendelegasikan panggilan ke hasMoreTokens()
dan nextToken()
, masing-masing. (Dengan mengimplementasikan Enumeration
antarmuka, PowerfulTokenizer
menjadi 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:
Tipe | Jumlah Token | Token |
---|---|---|
|
19 | hello:,: Today:,:,:,: "I:,: am ":,: going to:,:,:,: "buy:,: a:,: book " (disini karakter : memisahkan token) |
|
13 | hello:,:Today:,:"":"":I, am:,:going to:,:"":"":buy a book (di mana "" berarti string dengan panjang 0) |
|
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 Today
pembatas). Berikut logika dalam menghitung jumlah token pada PowerfulTokenizer
case:
- 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"
,StringTokenizer
akan mengembalikan lima token (yaitu,buy:,:a:,:book
), sementaraPowerfulTokenizer
akan 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. - 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; iThe
countTokens()
method checks whether the input string contains double quotes. If it does, then it decrements the count and updates the index to the index of the next double quote in that string (as shown in the above code segment). IfbReturnTokens
is false, then it decrements the count by the total number of nonsubsequent delimiters present in the input string.// return " "="" as="" token="" consecutive="" delimiters="" are="" found.="" (="" (sprevtoken.equals(sdelim))="" &&="" (stoken.equals(sdelim))="" )="" sprevtoken="sToken;" itokenno++;="" return="" "";="" check="" whether="" itself="" equal="" (stoken.trim().startswith("\""))="" (stoken.length()="=" 1)="" this="" special="" case="" when="" string="" snexttoken="oTokenizer.nextToken();" (!snexttoken.trim().endswith("\""))="" stoken="" stoken.substring(1,="" stoken.length()-1);="" there="" substring="" inside="" else="" (!((stoken.trim().endswith("\""))="" (!stoken.trim().endswith("\"\""))))="" (otokenizer.hasmoretokens())="" for="" presence="" "\"\""="" (!((snexttoken.trim().endswith("\""))="" (!snexttoken.trim().endswith("\"\"")))="" (!otokenizer.hasmoretokens())="" ;="" <="" re="">The
nextToken()
method gets tokens by usingStringTokenizer.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. IfnextToken()
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 .