2009-11-06 5 views
46

Disons que j'ai un LazySeq de java.lang.Character commeComment puis-je convertir un LazySeq de caractères en une chaîne dans Clojure?

(\b \ \! \/ \b \ \% \1 \9 \/ \. \i \% \$ \i \space \^@) 

Comment puis-je convertir en une chaîne? J'ai essayé l'évidence

(String. my-char-seq) 

mais il jette

java.lang.IllegalArgumentException: No matching ctor found for class java.lang.String (NO_SOURCE_FILE:0) 
[Thrown class clojure.lang.Compiler$CompilerException] 

Je pense que le constructeur String attend un primitif char [] au lieu d'un LazySeq. Alors j'ai essayé quelque chose comme

(String. (into-array my-char-seq)) 

mais il lance la même exception. Le problème est maintenant que dans le tableau renvoie java.lang.Character [] au lieu d'une primitive char []. Ceci est frustrant, parce que je générer effectivement ma séquence de caractères comme celui-ci

(map #(char (Integer. %)) seq-of-ascii-ints) 

Fondamentalement, j'ai un seq de ints représentant des caractères ASCII; 65 = A, etc. Vous pouvez voir que j'utilise explicitement la fonction de coercition de type primitif (char x).

Ce que cela signifie est que ma carte fonction renvoie une omble primitive mais le Clojure carte fonction est de retour ensemble du java.lang.Character objet.

Répondre

97

Cela fonctionne:

(apply str my-char-seq) 

Fondamentalement, str appelle toString() sur chacun de ses args, puis de les concaténer. Ici, nous utilisons appliquer pour passer les caractères de la séquence en tant qu'args à str.

10

Une autre façon est d'utiliser clojure.string/join, comme suit:

(require '[clojure.string :as str]) 
(assert (= (vec "abcd")    [\a \b \c \d])) 
(assert (= (str/join (vec "abcd")) "abcd")) 
(assert (= (apply str (vec "abcd")) "abcd")) 

Il existe une autre forme de clojure.string/join qui accepte un séparateur.Voir:

http://clojuredocs.org/clojure_core/clojure.string/join

Pour des problèmes plus complexes, vous pouvez également LookAt strcatfrom the Tupelo library:

(require '[tupelo.core :as t]) 
(prn (t/strcat "I " [ \h \a nil \v [\e \space (byte-array [97]) 
        [ nil 32 "complicated" (Math/pow 2 5) '("str" nil "ing") ]]])) 
;=> "I have a complicated string" 
3

En cas particulier, si le type sous-jacent de la séquence en question est clojure.lang.StringSeq vous pouvez aussi faire:

(.s (my-seq)) 

qui est extrêmement performant car il tire juste o ut le champ final public CharSequence de la classe clojure StringSeq.

Exemple:

(type (seq "foo")) 
=> clojure.lang.StringSeq 

(.s (seq "foo")) 
=> "foo" 

(type (.s (seq "foo"))) 
=> java.lang.String 

un exemple des implications de synchronisation (et noter la différence en utilisant un indicateur de type):

(time 
    (let [q (seq "xxxxxxxxxxxxxxxxxxxx")] 
    (dotimes [_ 1000000] 
     (apply str q)))) 
"Elapsed time: 620.943971 msecs" 
=> nil 

(time 
    (let [q (seq "xxxxxxxxxxxxxxxxxxxx")] 
    (dotimes [_ 1000000] 
     (.s q)))) 
"Elapsed time: 1232.119319 msecs" 
=> nil 

(time 
    (let [^StringSeq q (seq "xxxxxxxxxxxxxxxxxxxx")] 
    (dotimes [_ 1000000] 
     (.s q)))) 
"Elapsed time: 3.339613 msecs" 
=> nil 
Questions connexes