Většina programátorů Java používá java.util.StringTokenizer
třídy v té či oné době. Je to v podstatě praktická třída tokenizuje (přeruší) vstupní řetězec na základě oddělovače a na požádání dodá tokeny. (Tokenizace je akt přeměny sekvencí znaků na tokeny, kterým váš program rozumí.)
I když šikovný, StringTokenizer
funkčnost je omezená. Třída jednoduše hledá oddělovač ve vstupním řetězci a po nalezení oddělovače řetězec přeruší. Nekontroluje podmínky, jako je to, zda je oddělovač v podřetězci, ani nevrací token jako ""
(délka řetězce 0), jakmile jsou na vstupu nalezeny dva oddělovače. Pro splnění těchto omezení je platforma Java 2 (JDK 1.2 a novější) dodávána s BreakIterator
třída, což je vylepšený tokenizer StringTokenizer
. Protože taková třída není v JDK 1.1.x k dispozici, vývojáři často tráví spoustu času psaním originálního tokenizátoru, který splňuje jejich požadavky. Ve velkém projektu zahrnujícím zpracování datového formátu není neobvyklé najít mnoho takových přizpůsobených tříd, které se vznášejí kolem.
Tento tip si klade za cíl vás provede psaní sofistikovaného tokenizer, pomocí stávající StringTokenizer
.
Omezení StringTokenizer
Můžete vytvořit StringTokenizer
pomocí kteréhokoli z následujících tří konstruktorů:
StringTokenizer (String sInput)
: Přestávky na prázdné místo ("", "\ t", "\ n"
).StringTokenizer (String sInput, String sDelimiter)
: PřestávkysDelimiter
.StringTokenizer (String sInput, String sDelimiter, boolean bReturnTokens)
: PřestávkysDelimiter
, ale pokudbReturnTokens
je nastavena na hodnotu true, pak se oddělovač také vrátí jako token.
První konstruktor nekontroluje, zda vstupní řetězec obsahuje podřetězce. Když řetězec "ahoj. Dnes \" jdu \ "jdu do svého rodného města"
je tokenizováno na prázdném místě, výsledek je v tokenech Ahoj.
, Dnes
, „Já
, dopoledne
, "
, jít
, namísto Ahoj.
, Dnes
, "Jsem "
, jít
.
Druhý konstruktor nekontroluje po sobě jdoucí vzhled oddělovačů. Když řetězec "kniha, autor, publikace ,,, datum vydání"
je tokenizováno dne ","
„ StringTokenizer
vrátí čtyři žetony s hodnotami rezervovat
, autor
, vydání
, a datum zveřejnění
místo šesti hodnot rezervovat
, autor
, vydání
, ""
, ""
, a datum zveřejnění
, kde ""
znamená řetězec délky 0. Abyste získali šest, musíte nastavit StringTokenizer
je bReturnTokens
parametr na true.
Funkce nastavení parametru na true je důležitá, protože poskytuje představu o přítomnosti po sobě následujících oddělovačů. Například pokud se data získávají dynamicky a používají se k aktualizaci tabulky v databázi, kde se vstupní tokeny mapují na hodnoty sloupců, nemůžeme mapovat tokeny se sloupci databáze, protože si nejsme jisti, které sloupce by měly být nastaveny na ""
. Například chceme přidat záznamy do tabulky se šesti sloupci a vstupní data obsahují dva po sobě jdoucí oddělovače. Výsledek z StringTokenizer
v tomto případě je pět tokenů (protože dva po sobě jdoucí oddělovače představují token ""
, který StringTokenizer
zanedbává) a musíme nastavit šest polí. Také nevíme, kde se objevuje následný oddělovač, tedy na který sloupec by měl být nastaven ""
.
Třetí konstruktor nebude fungovat, pokud se token sám bude rovnat (délkou a hodnotou) oddělovači a bude v podřetězci. Když řetězec "kniha, autor, publikace, \", \ "datum vydání"
je tokenizovaný (tento řetězec obsahuje ,
jako token, který je stejný jako jeho oddělovač) na řetězci ,
, výsledek je rezervovat
, autor
, vydání
, "
, "
, datum zveřejnění
(se šesti žetony) místo rezervovat
, autor
, vydání
, ,
(znak čárky), datum zveřejnění
(s pěti žetony). Mějte na paměti, že dokonce nastavíte bReturnTokens
(třetí parametr do StringTokenizer
) na true vám v tomto případě nepomůže.
Základní potřeby tokenizéru
Než začnete pracovat s kódem, musíte znát základní potřeby dobrého tokenizéru. Vzhledem k tomu, že vývojáři Java jsou zvyklí na StringTokenizer
třída, dobrý tokenizer by měl mít všechny užitečné metody, které třída poskytuje, například hasMoreTokens ()
, nextToken ()
, countTokens ()
.
Kód pro tento tip je jednoduchý a většinou srozumitelný. V zásadě jsem použil StringTokenizer
třída (vytvořeno pomocí bReturnTokens
nastavena na hodnotu true) interně a poskytla metody uvedené výše. Vzhledem k tomu, že v některých případech je oddělovač vyžadován jako tokeny (velmi vzácné případy), zatímco v některých není, musí tokenizer na požádání dodat oddělovač jako token. Když vytvoříte a PowerfulTokenizer
objekt, předávající pouze vstupní řetězec a oddělovač, interně používá a StringTokenizer
s bReturnTokens
nastavena na hodnotu true. (Důvodem je, pokud a StringTokenizer
je vytvořen bez bReturnTokens
nastavena na hodnotu true, pak je omezena při překonávání výše uvedených problémů). Chcete-li správně zpracovat tokenizer, kód zkontroluje, zda bReturnTokens
je na několika místech nastavena na hodnotu true (výpočet celkového počtu tokenů a nextToken ()
).
Jak jste si možná všimli, PowerfulTokenizer
realizuje Výčet
rozhraní, čímž implementuje hasMoreElements ()
a nextElement ()
metody, které jednoduše delegují volání hasMoreTokens ()
a nextToken ()
, resp. (Implementací Výčet
rozhraní, PowerfulTokenizer
stane se zpětně kompatibilní s StringTokenizer
.) Uvažujme o příkladu. Řekněme, že vstupní řetězec je „ahoj, dnes ,,, \" já, jdu, "jdu ,,, \" koupit, a, kniha \ ""
a oddělovač je ,
. Tento řetězec při tokenizaci vrací hodnoty, jak je znázorněno v tabulce 1:
Typ | Počet žetonů | Žetony |
---|---|---|
| 19 | ahoj:,: Today:,:,:,: "I:,: am":,: jít na:,:,:,: "koupit:,: a:,: rezervovat " (zde postava : odděluje žetony) |
| 13 | ahoj:,: Today:,: "": "": I, am:,: chystám se:,: "": "": koupit knihu (kde "" znamená řetězec délky 0) |
| 9 | ahoj: dnes: "": "": jdu: chystám se: "": "": koupit knihu |
Vstupní řetězec obsahuje 11 čárek (,
) znaky, z nichž tři jsou uvnitř podřetězců a čtyři se objevují postupně (jako Dnes,,,
dělá dvě po sobě jdoucí čárky, první čárka je Dnes
oddělovač). Zde je logika výpočtu počtu tokenů v PowerfulTokenizer
případ:
- V případě
bReturnTokens = true
, vynásobte počet oddělovačů uvnitř podřetězců 2 a odečtěte tuto částku od skutečného součtu, abyste získali počet tokenů. Důvod je pro podřetězec„koupit, rezervovat“
,StringTokenizer
vrátí pět žetonů (tj.koupit:,: a:,: kniha
), zatímcoPowerfulTokenizer
vrátí jeden token (tj.koupit, a, rezervovat
). Rozdíl je čtyři (tj. 2 * počet oddělovačů uvnitř podřetězce). Tento vzorec platí pro všechny podřetězce obsahující oddělovače. Uvědomte si speciální případ, kdy se token sám rovná oddělovači; toto by nemělo snižovat hodnotu počtu. - Podobně pro případ
bReturnTokens = false
, odečtěte hodnotu výrazu [celkem oddělovače (11) - po sobě jdoucí oddělovače (4) + počet oddělovačů uvnitř podřetězců (3)] od skutečného součtu (19), abyste získali počet tokenů. Vzhledem k tomu, že v tomto případě nevracíme oddělovače, jsou pro nás (aniž by se objevily postupně nebo uvnitř podřetězců) k ničemu a výše uvedený vzorec nám dává celkový počet tokenů (9).
Pamatujte si tyto dva vzorce, které jsou srdcem PowerfulTokenizer
. Tyto vzorce fungují téměř pro všechny příslušné případy. Pokud však máte složitější požadavky, které nejsou vhodné pro tyto vzorce, musíte před spuštěním kódování zvážit různé příklady, jak vytvořit svůj vlastní vzorec.
// zkontrolovat, zda je oddělovač v podřetězci pro (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="" if="" consecutive="" delimiters="" are="" found.="" if="" (="" (sprevtoken.equals(sdelim))="" &&="" (stoken.equals(sdelim))="" )="" {="" sprevtoken="sToken;" itokenno++;="" return="" "";="" }="" check="" whether="" the="" token="" itself="" is="" equal="" to="" the="" delimiter="" if="" (="" (stoken.trim().startswith("\""))="" &&="" (stoken.length()="=" 1)="" )="" {="" this="" is="" a="" special="" case="" when="" token="" itself="" is="" equal="" to="" delimiter="" string="" snexttoken="oTokenizer.nextToken();" while="" (!snexttoken.trim().endswith("\""))="" {="" stoken="" +="sNextToken;" snexttoken="oTokenizer.nextToken();" }="" stoken="" +="sNextToken;" sprevtoken="sToken;" itokenno++;="" return="" stoken.substring(1,="" stoken.length()-1);="" }="" check="" whether="" there="" is="" a="" substring="" inside="" the="" string="" else="" if="" (="" (stoken.trim().startswith("\""))="" &&="" (!((stoken.trim().endswith("\""))="" &&="" (!stoken.trim().endswith("\"\""))))="" )="" {="" if="" (otokenizer.hasmoretokens())="" {="" string="" snexttoken="oTokenizer.nextToken();" check="" for="" presence="" of="" "\"\""="" while="" (!((snexttoken.trim().endswith("\""))="" &&="" (!snexttoken.trim().endswith("\"\"")))="" )="" {="" stoken="" +="sNextToken;" if="" (!otokenizer.hasmoretokens())="" {="" snexttoken="" ;="" break;="" }="" snexttoken="oTokenizer.nextToken();" }="" stoken="" +="sNextToken;" }="" }="">
The nextToken ()
metoda získává tokeny pomocí StringTokenizer.nextToken
a zkontroluje znak dvojité uvozovky v tokenu. Pokud metoda tyto znaky najde, získá více tokenů, dokud nenajde žádné s dvojitou uvozovkou. Ukládá také token do proměnné (sPrevToken
; viz zdrojový kód) pro kontrolu následných vzhledů oddělovače. Li nextToken ()
najde po sobě jdoucí tokeny, které se rovnají oddělovači, poté se vrátí ""
(řetězec s délkou 0) jako token.
Podobně hasMoreTokens ()
metoda kontroluje, zda počet již požadovaných tokenů je menší než celkový počet tokenů.
Ušetřete čas na vývoj
Tento článek vás naučil, jak snadno napsat výkonný tokenizer. Pomocí těchto konceptů můžete rychle psát složité tokenizéry, což vám ušetří značný čas na vývoj.
Bhabani Padhi je Java architekt a programátor, který v současné době pracuje na vývoji webových a podnikových aplikací pomocí technologie Java v UniteSys v Austrálii. Dříve pracoval ve společnosti Baltimore Technologies v Austrálii na vývoji produktů pro elektronické zabezpečení a ve společnosti Fujitsu v Austrálii na projektu vývoje serveru EJB. Mezi zájmy Bhabani patří distribuovaný výpočet, mobil a vývoj webových aplikací pomocí technologie Java.Další informace o tomto tématu
- Získejte zdrojový kód pro tento tip
//images.techhive.com/downloads/idge/imported/article/jvw/2001/06/powerfultokenizer.java
- Další informace o BreakIterator
//java.sun.com/products/jdk/1.2/docs/api/java/text/BreakIterator.html
- Zobrazit všechny předchozí Tipy pro Java a odešlete vlastní
//www.javaworld.com/javatips/jw-javatips.index.html
- Více Úvodní úroveň články, navštivte JavaWorld 's Aktuální rejstřík
//www.javaworld.com/javaworld/topicalindex/jw-ti-introlevel.html
- Naučte se Java od základu v JavaWorld 's Java 101 sloupec
//www.javaworld.com/javaworld/topicalindex/jw-ti-java101.html
- Odborníci na jazyk Java odpovídají na vaše nejnáročnější otázky týkající se jazyka Java v JavaWorld 's Java Q&A sloupec
//www.javaworld.com/javaworld/javaqa/javaqa-index.html
- Zaregistrujte se JavaWorld tento týden bezplatný týdenní e-mailový zpravodaj, abyste zjistili, co je nového JavaWorld
//www.idg.net/jw-subscribe
Tento příběh, „Java Tip 112: Improve tokenization of information-rich strings“, původně publikoval JavaWorld.