J'ai une chaîne qui ressemble à ceci:
this is "a test"
J'essaie d'écrire quelque chose en Python pour le diviser par espace tout en ignorant les espaces entre guillemets. Le résultat que je recherche est:
['this','is','a test']
PS. Je sais que vous allez demander "ce qui se passe s'il y a des guillemets dans les guillemets, eh bien, dans mon application, cela n'arrivera jamais.
Réponses:
Vous voulez
split
, à partir dushlex
module intégré.Cela devrait faire exactement ce que vous voulez.
la source
shlex.split('this is "a test"', posix=False)
retours['this', 'is', '"a test"']
shlex.split()
déclenchera uneUnicodeEncodeError
exception.Jetez un œil au
shlex
module, en particuliershlex.split
.la source
Je vois ici des approches regex qui semblent complexes et / ou erronées. Cela me surprend, car la syntaxe des regex peut facilement décrire "des espaces ou des choses entourées de guillemets", et la plupart des moteurs de regex (y compris Python) peuvent se diviser sur une regex. Donc, si vous allez utiliser des expressions rationnelles, pourquoi ne pas simplement dire exactement ce que vous voulez dire?:
Explication:
shlex fournit probablement plus de fonctionnalités, cependant.
la source
Selon votre cas d'utilisation, vous pouvez également consulter le
csv
module:Production:
la source
""
) pour représenter un guillemet double"
, donc transformeront deux guillemets doubles en un guillemet simple'this is "a string""'
et'this is "a string"""'
seront tous deux mappés à['this', 'is', 'a string"']
J'utilise shlex.split pour traiter 70 000 000 lignes de journal de calmar, c'est tellement lent. Je suis donc passé à re.
Veuillez essayer ceci, si vous avez un problème de performances avec shlex.
la source
Puisque cette question est étiquetée avec regex, j'ai décidé d'essayer une approche regex. Je remplace d'abord tous les espaces dans les parties de guillemets par \ x00, puis je les divise en espaces, puis je remplace le \ x00 par des espaces dans chaque partie.
Les deux versions font la même chose, mais splitter est un peu plus lisible que splitter2.
la source
Il semble que pour des raisons de performances,
re
c'est plus rapide. Voici ma solution en utilisant un opérateur le moins gourmand qui préserve les guillemets externes:Résultat:
Il laisse des constructions comme
aaa"bla blub"bbb
ensemble car ces jetons ne sont pas séparés par des espaces. Si la chaîne contient des caractères d'échappement, vous pouvez faire correspondre comme ça:Veuillez noter que cela correspond également à la chaîne vide
""
au moyen de la\S
partie du motif.la source
,
via'(?:".*?"|[^,])+'
). Il en va de même pour le (s) caractère (s) (entre guillemets).Le principal problème avec l'acceptation
shlex
approche est qu'elle n'ignore pas les caractères d'échappement en dehors des sous-chaînes entre guillemets et donne des résultats légèrement inattendus dans certains cas de coin.J'ai le cas d'utilisation suivant, où j'ai besoin d'une fonction de fractionnement qui fractionne les chaînes d'entrée de telle sorte que les sous-chaînes entre guillemets simples ou doubles sont préservées, avec la possibilité d'échapper les guillemets dans une telle sous-chaîne. Les guillemets dans une chaîne sans guillemets ne doivent pas être traités différemment de tout autre caractère. Quelques exemples de cas de test avec la sortie attendue:
Je me suis retrouvé avec la fonction suivante pour diviser une chaîne de sorte que les résultats de sortie attendus pour toutes les chaînes d'entrée:
L'application de test suivante vérifie les résultats d'autres approches (
shlex
etcsv
pour l'instant) et l'implémentation du fractionnement personnalisé:Production:
Ainsi, les performances sont bien meilleures que
shlex
, et peuvent être encore améliorées en précompilant l'expression régulière, auquel cas elle surpassera l'csv
approche.la source
shlex
ne se comporte pas comme prévu pour mes cas d'utilisation.Pour conserver les guillemets, utilisez cette fonction:
la source
Test de vitesse des différentes réponses:
la source
Hmm, ne semble pas trouver le bouton "Répondre" ... de toute façon, cette réponse est basée sur l'approche de Kate, mais divise correctement les chaînes avec des sous-chaînes contenant des guillemets échappés et supprime également les guillemets de début et de fin des sous-chaînes:
Cela fonctionne sur des chaînes comme
'This is " a \\\"test\\\"\\\'s substring"'
(le balisage fou est malheureusement nécessaire pour empêcher Python de supprimer les échappements).Si les échappements résultants dans les chaînes de la liste retournée ne sont pas souhaités, vous pouvez utiliser cette version légèrement modifiée de la fonction:
la source
Pour contourner les problèmes Unicode dans certaines versions de Python 2, je suggère:
la source
split = lambda a: [b.decode('utf-8') for b in _split(a)]
sinon vous obtenez:UnicodeDecodeError: 'ascii' codec can't decode byte ... in position ...: ordinal not in range(128)
En option, essayez tssplit:
la source
Je suggère:
chaîne de test:
pour capturer aussi "" et '':
résultat:
ignorer "" et '' vides:
résultat:
la source
re.findall("(?:\".*?\"|'.*?'|[^\s'\"]+)", s)
.Si vous ne vous souciez pas des sous-chaînes qu'un simple
Performance:
Ou module de chaîne
Performances: le module String semble fonctionner mieux que les méthodes String
Ou vous pouvez utiliser le moteur RE
Performance
Pour les chaînes très longues, vous ne devez pas charger la chaîne entière en mémoire et au lieu de cela diviser les lignes ou utiliser une boucle itérative
la source
Essaye ça:
Quelques chaînes de test:
la source
adamsplit("This is 'a test'")
→['This', 'is', "'a", "test'"]