2009-05-28 20 views
7

Acabo de empezar a jugar con Clojure y lo primero que pensé sería intentar almacenar y recuperar una lista de estructuras, como en el ejemplo de Suart Halloway here.Clojure: estructuras de slurping del archivo falla con atributos de cadena que contienen espacios en blanco

mi saliva/slurp de un hash de estructuras funciona bien con, si uso instancias struct sin espacios en las cadenas de atributos como la siguiente:

(struct customer "Apple" "InfiniteLoop") 

Pero si uso esto:

(struct customer "Apple" "Infinite Loop 1") 

me sale un error:

Exception in thread "main" clojure.lang.LispReader$ReaderException: java.lang.ArrayIndexOutOfBoundsException: 7 (test-storing.clj:19) 
    at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:2719) 
    at clojure.lang.Compiler$DefExpr.eval(Compiler.java:298) 
    at clojure.lang.Compiler.eval(Compiler.java:4537) 
    at clojure.lang.Compiler.load(Compiler.java:4857) 
    at clojure.lang.Compiler.loadFile(Compiler.java:4824) 
    at clojure.main$load_script__5833.invoke(main.clj:206) 
    at clojure.main$init_opt__5836.invoke(main.clj:211) 
    at clojure.main$initialize__5846.invoke(main.clj:239) 
    at clojure.main$null_opt__5868.invoke(main.clj:264) 
    at clojure.main$legacy_script__5883.invoke(main.clj:295) 
    at clojure.lang.Var.invoke(Var.java:346) 
    at clojure.main.legacy_script(main.java:34) 
    at clojure.lang.Script.main(Script.java:20) 
Caused by: clojure.lang.LispReader$ReaderException: java.lang.ArrayIndexOutOfBoundsException: 7 
    at clojure.lang.LispReader.read(LispReader.java:180) 
    at clojure.core$read__4168.invoke(core.clj:2083) 
    at clojure.core$read__4168.invoke(core.clj:2081) 
    at clojure.core$read__4168.invoke(core.clj:2079) 
    at clojure.core$read__4168.invoke(core.clj:2077) 
    at chap_03$load_db__54.invoke(chap_03.clj:71) 
    at clojure.lang.AFn.applyToHelper(AFn.java:173) 
    at clojure.lang.AFn.applyTo(AFn.java:164) 
    at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:2714) 
    ... 12 more 
Caused by: java.lang.ArrayIndexOutOfBoundsException: 7 
    at clojure.lang.PersistentArrayMap$Seq.first(PersistentArrayMap.java:216) 
    at clojure.lang.APersistentMap.hashCode(APersistentMap.java:101) 
    at clojure.lang.Util.hash(Util.java:55) 
    at clojure.lang.PersistentHashMap.entryAt(PersistentHashMap.java:134) 
    at clojure.lang.PersistentHashMap.containsKey(PersistentHashMap.java:130) 
    at clojure.lang.APersistentSet.contains(APersistentSet.java:33) 
    at clojure.lang.PersistentHashSet.cons(PersistentHashSet.java:59) 
    at clojure.lang.PersistentHashSet.create(PersistentHashSet.java:34) 
    at clojure.lang.LispReader$SetReader.invoke(LispReader.java:974) 
    at clojure.lang.LispReader$DispatchReader.invoke(LispReader.java:540) 
    at clojure.lang.LispReader.read(LispReader.java:145) 
    ... 20 more 

Dependiendo de la cantidad de los campos en la estructura, podría también solo obtenga una parte de la cadena como un nombre de atributo en lugar del error. Por ejemplo: Loop 1

utilizo una tienda-función como esta:

(defn store-customer-db [customer-db filename] 
    (spit filename (with-out-str (print customer-db)))) 

y una función de lectura de esta manera:

(defn load-db [filename] 
    (with-in-str (slurp filename)(read))) 

Desde el archivo de salida de saliva puedo ver que la impresión no da comillas dobles a las cuerdas, lo que parece ser un problema para sorber. ¿Cuál sería la solución correcta para esto?

Mi versión Clojure es 1.0, y el contrib es una instantánea de hace algunas semanas.

+0

Es probable que obtenga respuestas autorizadas e inmediatas en #clojure (irc). – alphazero

Respuesta

10

print y println son productos legibles para humanos. Si desea imprimir algo que debe leerse más tarde, use pr o prn.

user> (read-string (with-out-str (prn {"Apple" "Infinite Loop"}))) 
{"Apple" "Infinite Loop"} 

Considerando lo siguiente:

user> (read-string (with-out-str (print {"Apple" "Infinite Loop"}))) 
java.lang.ArrayIndexOutOfBoundsException: 3 (NO_SOURCE_FILE:0) 

que está tratando de ejecutar este código:

(read-string "{Apple Infinite Loop}") 

que tiene un número impar de llaves/valores. Tenga en cuenta la falta de comillas en torno a las claves/valores hash individuales. Incluso si esta lectura funciona (es decir, si por coincidencia proporciona un número par de parámetros), lo que lee no será un mapa hash lleno de cadenas, sino más bien símbolos. Entonces recibirás algo que no sea lo que sacaste.

user> (map class (keys (read-string (with-out-str (print {"foo bar" "baz quux"}))))) 
(clojure.lang.Symbol clojure.lang.Symbol) 
2

para, por ejemplo:

(def hashed-hobbits {:bilbo "Takes after his Mother's family" :frodo "ring bearer"}) 

Sólo es necesario:

(spit "hobbitses.txt" hashed-hobbits) 

y leer de nuevo:

(def there-and-back-again (read-string (slurp "hobbitses.txt"))) 

saliva/slurp lo envuelve todo en una cadena, pero utilizando cadena de lectura en el sorbo interpreta la cadena de nuevo a cl código/datos de ojure ¡Funciona en estructuras de datos trollish también!

+0

esto es genial, gracias – scape

Cuestiones relacionadas