2009-05-28 8 views
7

Je viens de commencer à jouer avec Clojure et la première chose que je voulais faire est de stocker et récupérer une liste de structures, comme dans l'exemple here de Suart Halloway.Clojure: les structures de slurping du fichier échouent avec des attributs de chaîne contenant des espaces

Ma broche/slurp d'un hachage de struct fonctionne très bien avec, si j'utiliser des instances struct sans espaces dans les chaînes d'attributs comme les suivantes:

(struct customer "Apple" "InfiniteLoop") 

Mais si j'utilise ceci:

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

Je reçois une erreur:

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 

en fonction du montant des champs de la struct, je pourrais aussi juste obtenir une partie de la chaîne comme un nom d'attribut au lieu de l'erreur. Par exemple: la boucle 1

J'utilise un magasin-fonction comme ceci:

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

Et une fonction de lecture comme ceci:

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

A partir du fichier de sortie de la broche, je peux voir que l'impression ne donne pas de guillemets aux cordes qui semblent être un problème pour slurp. Quelle serait la bonne solution pour cela?

Ma version de Clojure est 1.0, et la contribution est un instantané de quelques semaines.

+0

Vous obtiendrez probablement des réponses officielles et immédiates dans #clojure (irc). – alphazero

Répondre

10

print et println sont destinés à une sortie lisible par l'homme. Si vous voulez imprimer quelque chose qui doit être relu plus tard, utilisez pr ou prn.

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

Attendu que:

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

Il essaie d'exécuter ce code:

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

qui a un nombre impair de clés/valeurs. Notez l'absence de guillemets autour des clés/valeurs de hachage individuelles. Même si cette lecture fonctionne (c'est-à-dire si vous fournissez par hasard un nombre pair de paramètres), ce qu'elle lit ne sera pas une table de hachage pleine de chaînes, mais plutôt des symboles. Vous récupérerez donc autre chose que ce que vous produisez.

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

Pour, disent:

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

Vous avez seulement besoin:

(spit "hobbitses.txt" hashed-hobbits) 

et de le lire en arrière:

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

enveloppe broche/slurp tout dans un chaîne mais en utilisant read-string sur le slurp interprète la chaîne en cl code/données ojure. Fonctionne aussi sur les structures de données trollish!

+0

c'est super, merci – scape