actualizado con una nueva versión, aún más enrevesado. Esto es oficialmente ridículo; la próxima iteración usará un analizador apropiado (o c.c.monads y un poco de lógica parecida a Parsec además de eso). Ver el historial de revisión en esta respuesta para el original.
Este grupo complicado de funciones parece hacer el truco (no en mi DRYest con éste, lo siento!):
(defn initial-state [input]
{:expecting nil
:blocks (mapcat #(str/split % #"(?<=\s)|(?=\s)")
(str/split input #"(?<=(?:'|\"|\\))|(?=(?:'|\"|\\))"))
:arg-blocks []})
(defn arg-parser-step [s]
(if-let [bs (seq (:blocks s))]
(if-let [d (:expecting s)]
(loop [bs bs]
(cond (= (first bs) d)
[nil (-> s
(assoc-in [:expecting] nil)
(update-in [:blocks] next))]
(= (first bs) "\\")
[nil (-> s
(update-in [:blocks] nnext)
(update-in [:arg-blocks]
#(conj (pop %)
(conj (peek %) (second bs)))))]
:else
[nil (-> s
(update-in [:blocks] next)
(update-in [:arg-blocks]
#(conj (pop %) (conj (peek %) (first bs)))))]))
(cond (#{"\"" "'"} (first bs))
[nil (-> s
(assoc-in [:expecting] (first bs))
(update-in [:blocks] next)
(update-in [:arg-blocks] conj []))]
(str/blank? (first bs))
[nil (-> s (update-in [:blocks] next))]
:else
[nil (-> s
(update-in [:blocks] next)
(update-in [:arg-blocks] conj [(.trim (first bs))]))]))
[(->> (:arg-blocks s)
(map (partial apply str)))
nil]))
(defn split-args [input]
(loop [s (initial-state input)]
(let [[result new-s] (arg-parser-step s)]
(if result result (recur new-s)))))
Algo alentador, los siguientes rendimientos true
:
(= (split-args "asdf 'asdf \" asdf' \"asdf ' asdf\" asdf")
'("asdf" "asdf \" asdf" "asdf ' asdf" "asdf"))
Lo mismo ocurre con:
(= (split-args "asdf asdf ' asdf \" asdf ' \" foo bar ' baz \" \" foo bar \\\" baz \"")
'("asdf" "asdf" " asdf \" asdf " " foo bar ' baz " " foo bar \" baz "))
Espero que s debe recortar argumentos regulares, pero no rodeados de comillas, manejar comillas dobles e individuales, incluidas comillas dobles entre comillas dobles sin comillas (tenga en cuenta que actualmente trata las comillas simples entre comillas simples sin comillas de la misma manera, que aparentemente está en desacuerdo) con la forma de caparazón * nix ... argh) etc. Tenga en cuenta que se trata básicamente de un cálculo en una mónada de estado ad-hoc, que se acaba de escribir de una manera particularmente fea y con una necesidad urgente de DRYing up. :-P
Creo que su shell está a cargo de dividir args de línea de comandos, no Java. –
De todos modos, todavía estoy buscando una forma decente para hacer esto. – Rayne