2010-03-31 17 views
6

Ce que je voudrais faire (en Clojure):Comment supprimer la liste des mots à partir de chaînes

Par exemple, j'ai un vecteur de mots qui doivent être enlevés:

(def forbidden-words [":)" "the" "." "," " " ...many more...]) 

.. . et un vecteur de chaînes:

(def strings ["the movie list" "this.is.a.string" "haha :)" ...many more...]) 

Ainsi, chaque mot interdit doit être retiré de chaque chaîne, et le résultat, dans ce cas, serait: [ « liste de films » de « thisisastring » « haha ​​»].

Comment faire?

+0

Est-ce que ce lien vous aide: http://github.com/richhickey/clojure-contrib/blob/bacf49256673242bb7ce09b9f5983c27163e5bfc/src/main/clojure/clojure/contrib/string.clj#L162 –

Répondre

7
(def forbidden-words [":)" "the" "." ","]) 
(def strings ["the movie list" "this.is.a.string" "haha :)"]) 
(let [pattern (->> forbidden-words (map #(java.util.regex.Pattern/quote %)) 
       (interpose \|) (apply str))] 
    (map #(.replaceAll % pattern "") strings)) 
+0

J'aime mieux cela car il ne fait qu'un seul passage sur la chaîne d'entrée. –

+0

En ce qui concerne votre commentaire ci-dessous, avez-vous essayé votre propre réponse avec ["th:) e"]? Cela ne fonctionne pas correctement lorsque je l'essaie. –

+0

@ ALevy Pour moi, il fonctionne comme prévu: pour ["th:) e" ": le)"] il sort ("the" ":)") en supprimant seulement les mots interdits qui apparaissent dans la chaîne d'entrée - et mots non interdits qui apparaissent lorsque vous avez déjà supprimé d'autres mots interdits. Ma solution est la seule dont les valeurs de retour ne dépendent pas de l'ordre du vecteur des mots interdits. – cgrand

1
(use 'clojure.contrib.str-utils) 
(import 'java.util.regex.Pattern) 
(def forbidden-words [":)" "the" "." "," " "]) 
(def strings ["the movie list" "this.is.a.string" "haha :)"]) 
(def regexes (map #(Pattern/compile % Pattern/LITERAL) forbidden-words)) 
(for [s strings] (reduce #(re-gsub %2 "" %1) s regexes)) 
+0

+1, depuis cela marche. Pour ceux qui voudraient tester ceci sur le bord, notez que 'clojure.contrib.str-utils' a été renommé' clojure.contrib.string' dans les sources actuelles et 're-gsub' est devenu' remplacer-re'. Notez également que si vous supprimez un mot entre deux autres mots, vous devez supprimer exactement l'un des espaces qui l'entourent (plutôt que aucun, comme avec le code ci-dessus) * et * les mots au début et à la fin de la chaîne doivent être traités correctement , alors une magie regex un peu plus impliquée serait nécessaire. –

+0

Votre appel à 'Pattern/compile' peut être remplacé par' re-pattern'. –

+0

@Brian: 're-pattern' n'accepte pas l'argument' Pattern/LITERAL' qui est nécessaire ici. –

0

Utilisation de la composition de la fonction et la macro -> cela peut être agréable et simple:

(for [s strings] 
    (-> s ((apply comp 
      (for [s forbidden-words] #(.replace %1 s "")))))) 

Si vous voulez être plus idiomatique, vous pouvez utiliser replace-str de clojure.contrib.string, au lieu de #(.replace %1 s "").

Pas besoin d'utiliser les regex ici.

+1

Toutes les réponses multipass sont intrinsèquement brisées: (def forbidden-words [":)" "the" ". ","]) (pour [s [": le)"]] (-> s ((appliquer la commande (pour [s mots interdits] # ​​(. Remplacer% 1 s ""))))) ;; cela retourne ("") – cgrand