Programovanie

Spracovanie argumentov príkazového riadku v Jave: Prípad uzavretý

Mnoho aplikácií Java spustených z príkazového riadku berie na kontrolu svojho správania argumenty. Tieto argumenty sú k dispozícii v argumente reťazcového poľa odovzdaného do statického kódu aplikácie hlavný() metóda. Spravidla existujú dva typy argumentov: možnosti (alebo prepínače) a argumenty skutočných údajov. Aplikácia Java musí tieto argumenty spracovať a vykonať dve základné úlohy:

  1. Skontrolujte, či je použitá syntax platná a podporovaná
  2. Načítajte skutočné údaje potrebné na to, aby aplikácia mohla vykonávať svoje operácie

Kód, ktorý vykonáva tieto úlohy, je často vyrobený na mieru pre každú aplikáciu, a preto vyžaduje značné úsilie pri jeho vytváraní a údržbe, najmä ak požiadavky presahujú rámec jednoduchých prípadov iba s jednou alebo dvoma možnosťami. The možnosti trieda popísaná v tomto článku implementuje všeobecný prístup k ľahkému zvládnutiu najzložitejších situácií. Trieda umožňuje jednoduchú definíciu požadovaných volieb a argumentov údajov a poskytuje dôkladné kontroly syntaxe a ľahký prístup k výsledkom týchto kontrol. Pre tento projekt boli použité aj nové funkcie Java 5, ako sú generické a bezpečné typy.

Typy argumentov príkazového riadku

V priebehu rokov som napísal niekoľko nástrojov Java, ktoré na kontrolu svojho správania používajú argumenty príkazového riadku. Hneď na začiatku mi prišlo nepríjemné manuálne vytvárať a udržiavať kód na spracovanie rôznych možností. To viedlo k vývoju triedy prototypov na uľahčenie tejto úlohy, ale táto trieda mala nepochybne svoje obmedzenia, pretože pri dôkladnom preskúmaní sa počet možných rôznych variácií argumentov príkazového riadku ukázal byť značný. Nakoniec som sa rozhodol vyvinúť všeobecné riešenie tohto problému.

Pri vývoji tohto riešenia som musel vyriešiť dva hlavné problémy:

  1. Identifikujte všetky odrody, v ktorých sa môžu vyskytnúť možnosti príkazového riadku
  2. Nájdite jednoduchý spôsob, ako umožniť používateľom vyjadriť tieto odrody pri použití triedy, ktorá sa má ešte vyvinúť

Analýza problému 1 viedla k týmto pozorovaniam:

  • Možnosti príkazového riadku v rozpore s argumentmi údajov príkazového riadku - začnite predponou, ktorá ich jedinečne identifikuje. Príklady predpôn zahŕňajú pomlčku (-) na platformách Unix pre možnosti ako -a alebo lomítko (/) na platformách Windows.
  • Možnosti môžu byť buď jednoduché prepínače (tj. -a môže byť prítomný alebo nie) alebo získať hodnotu. Príkladom je:

    java MyTool -a -b logfile.inp 
  • Možnosti, ktoré majú hodnotu, môžu mať rôzne oddeľovače medzi skutočným kľúčom možnosti a hodnotou. Takéto oddeľovače môžu byť prázdne miesto, dvojbodka (:) alebo znamienko rovnosti (=):

    java MyTool -a -b logfile.inp java MyTool -a -b: logfile.inp java MyTool -a -b = logfile.inp 
  • Možnosti, ktoré majú hodnotu, môžu pridať ďalšiu úroveň zložitosti. Ako príklad zvážte spôsob, akým Java podporuje definíciu vlastností prostredia:

    java -Djava.library.path = / usr / lib ... 
  • Takže nad skutočný kľúč voľby (D), oddeľovač (=) a skutočná hodnota opcie (/ usr / lib), ďalší parameter (java.library.path) môže nadobúdať ľubovoľný počet hodnôt (vo vyššie uvedenom príklade možno pomocou tejto syntaxe určiť početné vlastnosti prostredia). V tomto článku sa tento parameter nazýva „detail“.
  • Možnosti majú tiež vlastnosť multiplicity: môžu byť povinné alebo voliteľné a počet povolených povolení sa môže tiež líšiť (napríklad presne jedenkrát, raz alebo viackrát alebo iné možnosti).
  • Argumenty údajov sú všetky argumenty príkazového riadku, ktoré nezačínajú predponou. Tu sa prijateľný počet argumentov takýchto údajov môže pohybovať medzi minimálnym a maximálnym počtom (ktoré nemusia byť nevyhnutne rovnaké). Aplikácia navyše zvyčajne vyžaduje, aby tieto dátové argumenty boli na príkazovom riadku posledné, ale nemusí to tak vždy byť. Napríklad:

    java MyTool -a -b = logfile.inp data1 data2 data3 // Všetky dáta na konci 

    alebo

    java MyTool -a data1 data2 -b = logfile.inp data3 // Môže byť prijateľný pre aplikáciu 
  • Zložitejšie aplikácie môžu podporovať viac ako jednu skupinu možností:

    java MyTool -a -b datafile.inp java MyTool -k [-verbose] foo bar duh java MyTool -check -verify logfile.out 
  • Nakoniec sa aplikácia môže rozhodnúť ignorovať akékoľvek neznáme možnosti alebo môže považovať tieto možnosti za chybu.

Pri navrhovaní spôsobu, ktorý používateľom umožní vyjadriť všetky tieto odrody, som teda prišiel s nasledujúcim formulárom všeobecných možností, ktorý slúži ako základ pre tento článok:

[[]] 

Tento formulár musí byť kombinovaný s vlastnosťou multiplicity, ako je popísané vyššie.

V rámci obmedzení týkajúcich sa všeobecnej formy možnosti opísanej vyššie, možnosti trieda popísaná v tomto článku je navrhnutá ako všeobecné riešenie pre všetky potreby spracovania príkazového riadku, ktoré môže mať Java aplikácia.

Triedy pomocníkov

The možnosti class, ktorá je základnou triedou pre riešenie popísané v tomto článku, prichádza s dvoma pomocnými triedami:

  1. OptionData: Táto trieda obsahuje všetky informácie o jednej konkrétnej možnosti
  2. OptionSet: Táto trieda obsahuje množinu možností. možnosti sama môže obsahovať ľubovoľný počet takýchto súborov

Pred popisom podrobností týchto tried sú potrebné ďalšie dôležité pojmy možnosti triedy treba zaviesť.

Typické bezpečné výčty

Predpona, oddeľovač a vlastnosť multiplicity boli zachytené pomocou enums, čo je vlastnosť, ktorú poskytuje Java 5 prvýkrát:

public enum Predpona {DASH ('-'), SLASH ('/'); súkromný char c; private Prefix (char c) {this.c = c; } char getName () {return c; }} public enum Separator {COLON (':'), EQUALS ('='), BLANK (''), NONE ('D'); súkromný char c; súkromný oddeľovač (char c) {this.c = c; } char getName () {return c; }} public enum Multiplicity {ONCE, ONCE_OR_MORE, ZERO_OR_ONE, ZERO_OR_MORE; } 

Používanie enumov má niektoré výhody: vyššiu bezpečnosť typu a prísnu a ľahkú kontrolu nad sadou prípustných hodnôt. Enumy sa dajú pohodlne použiť aj so zovšeobecnenými zbierkami.

Všimnite si, že Predpona a Oddeľovač enumy majú svojich vlastných konštruktorov, čo umožňuje definíciu skutočného znak predstavujúce túto inštanciu enum (oproti názov sa používa na označenie konkrétnej inštancie enum). Tieto znaky je možné získať pomocou týchto enumov ' getName () metódy a znaky sa používajú pre java.util.regex syntax vzoru balíka. Tento balík sa používa na vykonávanie niektorých kontrol syntaxe v priečinku možnosti triedy, ktorej podrobnosti budú nasledovať.

The Multiplicita enum v súčasnosti podporuje štyri rôzne hodnoty:

  1. RAZ: Táto možnosť sa musí vyskytnúť presne raz
  2. ONCE_OR_MORE: Táto možnosť sa musí vyskytnúť aspoň raz
  3. ZERO_OR_ONCE: Možnosť môže chýbať alebo sa môže zobraziť presne raz
  4. ZERO_OR_MORE: Táto možnosť môže byť neprítomná alebo sa môže vyskytnúť ľubovoľný počet opakovaní

V prípade potreby je možné ľahko pridať viac definícií.

Trieda OptionData

The OptionData trieda je v podstate dátový kontajner: po prvé pre údaje popisujúce samotnú možnosť a po druhé pre skutočné údaje nájdené na príkazovom riadku pre túto možnosť. Tento návrh sa už odráža v konštruktore:

OptionData (Možnosti. Predpona prefixu, Kľúč reťazca, Booleovský detail, Možnosti. Oddeľovač oddeľovača, Boolovská hodnota, Možnosti. Multiplicita multiplicita) 

Kľúč sa používa ako jednoznačný identifikátor tejto možnosti. Upozorňujeme, že tieto argumenty priamo odrážajú zistenia opísané skôr: úplný popis možnosti musí mať aspoň predponu, kľúč a multiplicitu. Možnosti, ktoré majú hodnotu, majú tiež oddeľovač a môžu prijímať podrobnosti. Upozorňujeme tiež, že tento konštruktor má prístup k balíkom, takže ho aplikácie nemôžu priamo používať. Trieda OptionSetje addOption () metóda pridáva možnosti. Výhodou tohto princípu návrhu je, že máme oveľa lepšiu kontrolu nad skutočnými možnými kombináciami argumentov použitých na vytvorenie OptionData inštancie. Ak by bol napríklad tento konštruktor verejný, mohli by ste vytvoriť inštanciu s nastavenými podrobnosťami na pravda a hodnota nastavená na nepravdivé, čo je samozrejme nezmysel. Namiesto zložitých kontrol v samotnom konštruktore som sa rozhodol poskytnúť kontrolovanú množinu addOption () metódy.

Konštruktor tiež vytvorí inštanciu java.util.regex.Vzor, ktorý sa používa pre proces porovnávania vzorov tejto možnosti. Jedným príkladom by mohol byť vzor možnosti, ktorá má hodnotu, žiadne podrobnosti a neprázdny oddeľovač:

pattern = java.util.regex.Pattern.compile (prefix.getName () + kľúč + oddeľovač.getName () + "(. +) $"); 

The OptionData triedy, ako už bolo spomenuté, uchováva aj výsledky kontrol vykonaných organizáciou možnosti trieda. Poskytuje nasledujúce verejné metódy na prístup k týmto výsledkom:

int getResultCount () String getResultValue (int index) String getResultDetail (int index) 

Prvá metóda, getResultCount (), vráti počet nájdení možnosti. Tento návrh metódy priamo súvisí s multiplicitou definovanou pre túto možnosť. Pre možnosti, ktoré majú hodnotu, je možné túto hodnotu získať pomocou getResultValue (int index) metóda, pri ktorej sa index môže pohybovať medzi 0 a getResultCount () - 1. Pre možnosti hodnoty, ktoré akceptujú aj podrobnosti, k nim možno podobne získať pomocou znaku getResultDetail (int index) metóda.

Trieda OptionSet

The OptionSet trieda je v podstate kontajner pre množinu OptionData inštancie a tiež dátové argumenty nájdené v príkazovom riadku.

Konštruktér má tvar:

OptionSet (Options.Prefix prefix, Optionss.Multiplicity defaultMultiplicity, String setName, int minData, int maxData) 

Tento konštruktor má opäť prístup k balíkom. Sady volieb je možné vytvárať iba prostredníctvom servera možnosti trieda je iná addSet () metódy. Predvolená multiplicita tu uvedených možností môže byť prepísaná pri pridávaní možnosti do sady. Tu uvedený názov súpravy je jedinečný identifikátor, ktorý sa používa na označenie súpravy. minDáta a maxData sú minimálny a maximálny počet prijateľných argumentov údajov pre túto množinu.

Verejné API pre OptionSet obsahuje nasledujúce metódy:

Všeobecné metódy prístupu:

Reťazec getSetName () int getMinData () int getMaxData () 

Spôsoby pridania možností:

OptionSet addOption (kľúč reťazca) OptionSet addOption (kľúč reťazca, multiplicita multiplicity) OptionSet addOption (kľúč reťazca, oddeľovač oddeľovača) OptionSet addOption (kľúč reťazca, oddeľovač oddeľovača, multiplicita multiplicity) OptionSet addOption (kľúč reťazca, booleovské podrobnosti, oddeľovač oddeľovača) OptionSet addOption (Kľúč reťazca, logické podrobnosti, oddeľovač oddeľovača, multiplicita multiplicita) 

Metódy prístupu k údajom o výsledkoch kontroly:

java.util.ArrayList getOptionData () OptionData getOption (reťazec) boolean isSet (reťazec) java.util.ArrayList getData () java.util.ArrayList getUnmatched () 

Všimnite si, že metódy pridávania možností, ktoré vyžadujú a Oddeľovač argument vytvoriť OptionData inštancia akceptujúca hodnotu. The addOption () metódy vrátia samotnú inštanciu množiny, ktorá umožňuje reťazenie vyvolania:

Možnosti options = nové Možnosti (args); options.addSet ("MySet"). addOption ("a"). addOption ("b"); 

Po vykonaní kontrol sú ich výsledky k dispozícii prostredníctvom zostávajúcich metód. getOptionData () vráti zoznam všetkých OptionData inštancie, zatiaľ čo getOption () umožňuje priamy prístup k konkrétnej možnosti. isSet (reťazcový kľúč) je pohodlná metóda, ktorá kontroluje, či sa možnosti na príkazovom riadku našli aspoň raz. getData () poskytuje prístup k nájdeným argumentom údajov, zatiaľ čo getUmatched () vypíše všetky možnosti nájdené na príkazovom riadku, pre ktoré neexistuje žiadna zhoda OptionData prípady sa našli.

Trieda Možnosti

možnosti je základná trieda, s ktorou budú aplikácie interagovať. Poskytuje niekoľko konštruktorov, z ktorých všetci preberajú pole reťazcov argumentov príkazového riadku, ktoré hlavný() metóda poskytuje ako prvý argument:

Možnosti (String args []) Options (String args [], int data) Options (String args [], int defMinData, int defMaxData) Options (String args [], Multiplicity defaultMultiplicity) Options (String args [], Multiplicity defaultMultiplicity, int data) Options (String args [], Multiplicity defaultMultiplicity, int defMinData, int defMaxData) Options (String args [], Prefix prefix) Options (String args [], Prefix prefix, int data) Options (String args [], Prefix prefix, int defMinData, int defMaxData) Možnosti (String args [], Prefix prefix, Multiplicity defaultMultiplicity) Možnosti (String args [], Prefix prefix, Multiplicity defaultMultiplicity, int dáta) Možnosti (String args [], Prefix prefix, Multiplicity defaultMultiplicity, int defMinData, int defMaxData) 

Prvý konštruktor v tomto zozname je najjednoduchší pomocou všetkých predvolených hodnôt, zatiaľ čo posledný je najobecnejší.

Tabuľka 1: Argumenty pre konštruktory Options () a ich význam

Hodnota Popis Predvolené
predponaTento argument konštruktora je jediným miestom, kde je možné určiť predponu. Táto hodnota sa odovzdá akejkoľvek množine možností a akejkoľvek možnosti vytvorenej následne. Myšlienka tohto prístupu spočíva v tom, že v rámci danej aplikácie sa ukazuje nepravdepodobné, že bude potrebné použiť rôzne predpony.Predpona. DASH
defaultMultiplicityTáto predvolená multiplicita sa odovzdá každej množine možností a použije sa ako predvolená pre možnosti pridané do sady bez určenia multiplicity. Túto multiplicitu je možné samozrejme prepísať pre každú pridanú možnosť.Mnohonásobnosť. JEDEN
defMinDatadefMinData je predvolený minimálny počet podporovaných údajových argumentov odovzdaných každej množine možností, ale pri pridávaní množiny ju možno samozrejme prepísať.0
defMaxDatadefMaxData je predvolený maximálny počet podporovaných údajových argumentov odovzdaných každej množine možností, ale pri pridávaní množiny ju možno samozrejme prepísať.0
$config[zx-auto] not found$config[zx-overlay] not found