Programování

Java Tip 112: Vylepšete tokenizaci řetězců bohatých na informace

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ý, StringTokenizerfunkč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ů:

  1. StringTokenizer (String sInput): Přestávky na prázdné místo ("", "\ t", "\ n").
  2. StringTokenizer (String sInput, String sDelimiter): Přestávky sDelimiter.
  3. StringTokenizer (String sInput, String sDelimiter, boolean bReturnTokens): Přestávky sDelimiter, ale pokud bReturnTokens 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 StringTokenizerje 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:

Tabulka 1: Hodnoty vrácené tokenizovaným řetězcem
TypPočet žetonůŽetony

StringTokenizer

(bReturnTokens = true)

19ahoj:,: Today:,:,:,: "I:,: am":,: jít na:,:,:,: "koupit:,: a:,: rezervovat" (zde postava : odděluje žetony)

PowerfulTokenizer

(bReturnTokens = true)

13ahoj:,: Today:,: "": "": I, am:,: chystám se:,: "": "": koupit knihu (kde "" znamená řetězec délky 0)

PowerfulTokenizer

(bReturnTokens = false)

9ahoj: 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 Dnesoddělovač). Zde je logika výpočtu počtu tokenů v PowerfulTokenizer případ:

  1. 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ímco PowerfulTokenizer 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.
  2. 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; i

The nextToken () metoda získává tokeny pomocí StringTokenizer.nextTokena 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.