Écrire du code fonctionnel idiomatique, à Clojure [1], comment on écrirait une fonction qui scindre une chaîne par blancheur mais garde des phrases citées intactes? Une solution rapide est bien sûr d'utiliser des expressions régulières, mais cela devrait être possible sans eux. À un coup d'œil rapide, il semble assez difficile! J'ai écrit une langue similaire dans des langues impératives, mais j'aimerais voir comment fonctionne une approche fonctionnelle et récursive.
Une commande rapide de ce que notre fonction doit faire: P>
"'lots of spacing' there" -> ["lots of spacing", "there"] ;is ok to me
7 Réponses :
Utilisez REGEX:
(defn my-split [string] (let [criterion " +(?=([^']*'[^']*')*[^']*$)"] (for [s (into [] (.split string criterion))] (.replace s "'" ""))))
C'est bon. C'est quand même Néater que ma réégalité actuelle :)
Vous ne passez pas le test avec ceci. Vous ["'A B'" "" C D '"] et il devrait être [" A B "," C D "].
En effet. Je viens de le changer pour inclure une solution rapide pour cela.
Il y a par exemple fnparse qui vous permet d'écrire un analyseur de manière fonctionnelle. p>
Cette solution est dans HASKELLL, mais l'idée principale doit également être applicable dans le clojure.
Deux états d'analyseur (intérieur ou extérieur de citations) sont représentés par deux fonctions mutuellement récursives.
splitq = outside [] . (' ':)
add c res = if null res then [[c]] else map (++[c]) res
outside res xs = case xs of
' ' : ' ' : ys -> outside res $ ' ' : ys
' ' : '\'' : ys -> res ++ inside [] ys
' ' : ys -> res ++ outside [] ys
c : ys -> outside (add c res) ys
_ -> res
inside res xs = case xs of
' ' : ' ' : ys -> inside res $ ' ' : ys
'\'' : ' ' : ys -> res ++ outside [] (' ' : ys)
'\'' : [] -> res
c : ys -> inside (add c res) ys
_ -> res
C'est beaucoup à ce que j'ai esquissé! Aussi, très cool qu'il évite la division initiale!
Voici une version de clojure. Cela souffle probablement de la pile pour de très grandes intrants. Une regex ou un réel analyseur-générateur serait beaucoup plus concis.
user> (doseq [x ["Hello there!"
"'A quoted phrase'"
"'a' 'b' c d"
"'a b' 'c d'"
"Mid'dle 'quotes do not concern me'"
"'lots of spacing' there"]]
(prn (parse x)))
["Hello" "there!"]
["A quoted phrase"]
["a" "b" "c" "d"]
["a b" "c d"]
["Mid'dle" "quotes do not concern me"]
["lots of spacing" "there"]
nil
Il est assez facile de faire une version de ceci qui ne souffle pas la pile en utilisant trampoline code>. Je ne parviens pas à éditer cela, donc j'ai copié le vôtre et j'ai légèrement changé et ajouté un exemple qui a soufflé la pile sur ma machine avant le changement.
a été capable de modifier Brian's pour utiliser le trampoline pour lui permettre de ne pas manquer d'espace de pile. Fondamentalement faire slurp-word code> et parse * code> retourne fonctionner au lieu de les exécuter, puis modifier parse code> pour utiliser trampoline code> < Pré> xxx pré> p>
Voici une version renvoyant un SEQ paresseux de mots / cordes citées: un test de test: p> si célibataire L'entrée ne correspond pas correctement, tout de la citation unique d'ouverture finale est prise pour constituer un "mot": p> mise à jour: EM> Une autre version en réponse au commentaire d'Edbond, avec une meilleure manipulation de caractères de devis à l'intérieur des mots: p> un test de test: p>
Tellement bon ... Je ne suis pas très bon aux séquences paresseuses de Clojure ... si cette séparatrice va avec recur code> ou donc? Mais l'exécution a l'air très idiomatique et cela sauve l'espacement! Excellent :)
utilisateur => (séparateur "Middle 'citations ne me concerne pas'") ("Middle" "" citations ne "" T "" "est-elle" "moi" ") Je quitterais la citation si elle entourée deux caractères.
@Progo: heureux d'entendre ça. :-) Comme pour recur code>, non, les SEQ paresseux ne doivent pas être mélangés avec la récursion de la queue. Voir Cette question de sorte pour plus de détails (les réponses peuvent être utiles comme une introduction générale aux SEQ paresseux, et comme pour les SEQS paresseux vs. Récursion de la queue, j'ai essayé de résoudre ce problème dans ma réponse). @edbond: Ouais, j'étais trop paresseux avec ça. La version éditée dans juste maintenant devrait gérer ce genre de cas mieux.
Il y a quelque chose qui se passe ... Le dernier personnage peut être mangé, en "Bonjour là-bas!" Code> et "'Beaucoup d'espacement" là " code>.
Oh mon, les réponses données semblent être la mine debat maintenant que j'ai eu les tests réussir. Quoi qu'il en soit, je le pose ici pour prier quelques commentaires sur l'idiomatisation du code.
J'ai esquissé d'un pseudo haskellish: p> ok, mal nommé. Il p> J'ai traduit le pseudo de cette façon: p> pas très clojuresque, les détails. De plus, je dépends de Regexp dans la division et en décapant les citations afin que je souhaite mériter des bowvotes en raison de cela. P> p>
pl code> traite les mots PLI code> (i comme en intérieur) traite les phrases citées li>
p code> est l'information déjà traitée (terminée) li>
w: ws code> est des informations à traiter li>
ul>
Dans l'exemple avec des "citations moyennes", j'ai remarqué qu'une seule citation a été complètement laissée complètement. Était-ce intentionnel?
Intentionnel. Mon point de vue de ce problème est que seul le début et la fin d'un mot estime. Je ne sais pas si c'est pratique si ...
Je suppose qu'une approche correcte de ce serait d'abord simplement diviser les cordes des espaces similaires à ceux de Python
Split code>. Cela devrait être presque trivial. Ensuite, vous pourriez probablement regarder la liste pour n'importe quel mot qui commence par une apostrophe et si on se trouve, continuez à chercher un mot qui se termine avec un, puis fusionner les éléments que vous avez déplacés. Type de...Deniz: Mon approche impérative a utilisé cette méthode. Je dessine une solution récursive mais je ne sais pas si cela va travailler ...