2009-07-04 15 views
12

Esiste un'alternativa shlex per Java? Mi piacerebbe essere in grado di dividere stringhe delimitate da virgolette come la shell le elaborerebbe. Per esempio, se manderei: alternativa shlex per Java

one two "three four"
ed eseguire una spaccatura, mi piacerebbe ricevere i gettoni
one
two
three four

+0

In particolare - "come se la shell li elaborasse" è un compito abbastanza difficile; 'shlex' lo fa bene, ma molti algoritmi ingenui non lo faranno. Ad esempio, in shell, "tre quattro" e "tre" quattro sono esattamente equivalenti, così come "tre \ quattro". –

risposta

6

Guardate Apache Commons Lang:

org.apache.commons.lang.text. StrTokenizer dovrebbe essere in grado di fare ciò che si vuole:

 
new StringTokenizer("one two \"three four\"", ' ', '"').getTokenArray(); 
+2

Sfortunatamente, diversamente da 'shlex', commons.lang non è POSIX compatibile. '(-> (StrTokenizer." \ "Foo \" 'bar'baz ") (.getTokenList))' restituisce una singola voce che contiene '" foo "' bar'baz', in contrapposizione al (corretto)' foobarbaz' . –

+0

@CharlesDuffy conosci la vera risposta? – bukzor

+0

@bukzor, che presuppone che * sia * uno. A mia conoscenza, uno strumento del genere non è stato scritto in questo momento, a meno di usare Python's shlex da Java tramite Jython (possibile, ma piuttosto una grande catena di dipendenze da inserire). –

7

ho avuto un problema simile oggi, e non aveva l'aspetto di tutte le opzioni standard come StringTokenizer, StrTokenizer, Sc Anner era una buona misura. Tuttavia, non è difficile implementare le basi.

Questo esempio gestisce tutti i casi limite attualmente commentati su altre risposte. Stai attento, non l'ho ancora verificato per la piena conformità POSIX. Elenco comprensivo dei test unitari disponibili on GitHub - rilasciato in pubblico dominio tramite l'unlicenza.

public List<String> parseArgs(CharSequence argString) { 
    List<String> tokens = new ArrayList<String>(); 
    boolean escaping = false; 
    char quoteChar = ' '; 
    boolean quoting = false; 
    StringBuilder current = new StringBuilder() ; 
    for (int i = 0; i<argString.length(); i++) { 
     char c = argString.charAt(i); 
     if (escaping) { 
      current.append(c); 
      escaping = false; 
     } else if (c == '\\' && !(quoting && quoteChar == '\'')) { 
      escaping = true; 
     } else if (quoting && c == quoteChar) { 
      quoting = false; 
     } else if (!quoting && (c == '\'' || c == '"')) { 
      quoting = true; 
      quoteChar = c; 
     } else if (!quoting && Character.isWhitespace(c)) { 
      if (current.length() > 0) { 
       tokens.add(current.toString()); 
       current = new StringBuilder(); 
      } 
     } else { 
      current.append(c); 
     } 
    } 
    if (current.length() > 0) { 
     tokens.add(current.toString()); 
    } 
    return tokens; 
} 
+0

Considereresti di allegare una licenza a questo (o di donarlo esplicitamente al pubblico dominio)? –

+0

Ah, eccolo, ultima riga di questa pagina: contributi utente concessi in licenza cc by-sa 3.0 con attribuzione obbligatoria – bukzor

+0

@RayMyers: Dobbiamo ancora sapere se questo è il tuo lavoro, altrimenti la licenza è sconosciuta. Inoltre, la licenza CC-BY-SA non è completamente compatibile con la licenza Apache di Hadoop ([Avrei bisogno di usarlo non modificato] (http://www.apache.org/legal/resolved.html#cc-sa)) . Se dovessi dedicare questo codice sotto [the Unlicense] (http://unlicense.org/) questi problemi spariranno, altrimenti dovrò scrivere simili da zero. ... Vorrei che SO cambiasse la loro licenza di default. – bukzor