Je sais qu'il y a beaucoup d'autres postes sur l'analyse de valeurs séparées par des virgules, mais je ne pouvais pas en trouver un qui divise des paires de clés et des poignées de virgules citées.
J'ai des cordes comme ceci: p> et je veux obtenir ceci: p> J'ai essayé d'utiliser shlex code> comme ceci: p >
lexer = shlex.shlex('''age=12,name=bob,hobbies="games,reading",phrase="I'm cool!"''')
lexer.whitespace_split = True
lexer.whitespace = ','
props = dict(pair.split('=', 1) for pair in lexer)
5 Réponses :
OK, je pensais en fait une jolie façon de rien, qui est à scinder à la fois sur des virgules et un signe égal, puis prendre 2 jetons à la fois.
{ 'age': '12', 'name': 'bob', 'hobbies': 'games,reading', 'phrase': "I'm cool!", }
Il gère également clé = "valeur = valeur" code>
Ne gère pas les cordes cotées simples.
Si vous avez name = "bob" code> plutôt que
nom = bob code>, vous pouvez également lire avec
exécuté () code>.
Il est possible de faire avec une expression régulière. Dans ce cas, il pourrait en réalité être la meilleure option. Je pense que cela fonctionnera avec la plupart des entrées, même échappé aux citations telles que celle-ci: avec le drapeau verbeux, il est possible de faire des expressions régulières compliquées assez lisibles . P> phrase = 'i \' m cool ' code>
import re
text = '''age=12,name=bob,hobbies="games,reading",phrase="I'm cool!"'''
regex = re.compile(
r'''
(?P<key>\w+)= # Key consists of only alphanumerics
(?P<quote>["']?) # Optional quote character.
(?P<value>.*?) # Value is a non greedy match
(?P=quote) # Closing quote equals the first.
($|,) # Entry ends with comma or end of string
''',
re.VERBOSE
)
d = {match.group('key'): match.group('value') for match in regex.finditer(text)}
print(d) # {'name': 'bob', 'phrase': "I'm cool!", 'age': '12', 'hobbies': 'games,reading'}
Joli! Ceci est beaucoup plus propre et plus compréhensible que d'utiliser shlex code>.
Oui. Si cela correspond à une entrée réelle possible, alors évanouis devraient être désinfectés d'une manière ou d'une autre avant d'exécuter la recherche Regex. Un autre exemple, qui est presque plausible est: phrase = "Je suis \" cool \ ", je pense ..." code>
@ Håkenlid: Je n'enstricultions que cela parce que vous l'avez mentionné dans votre réponse. OP n'a rien dit sur l'échappement de citations à l'intérieur des chaînes. BTW, Solution FSM à partir de ma réponse fonctionne dans ce cas
C'est quelque chose qui pourrait être pertinent, en fonction du type d'intrant à attendre.
Python semble offrir de nombreuses façons de résoudre la tâche. Voici un peu plus C tel que la voie mise en œuvre, traiter chaque caractère. Serait intéressant de connaître des temps d'exécution différents.
str = 'age=12,name=bob,hobbies="games,reading",phrase="I\'m cool!"' key = "" val = "" dict = {} parse_string = False parse_key = True # parse_val = False for c in str: print(c) if c == '"' and not parse_string: parse_string = True continue elif c == '"' and parse_string: parse_string = False continue if parse_string: val += c continue if c == ',': # terminate entry dict[key] = val #add to dict key = "" val = "" parse_key = True continue elif c == '=' and parse_key: parse_key = False elif parse_key: key += c else: val+=c dict[key] = val print(dict.items()) # {'phrase': "I'm cool!", 'age': '12', 'name': 'bob', 'hobbies': 'games,reading'}
MH J'ai des résultats corrects, peut-être que cela ne ressemble pas à Python, mais pourquoi le bowvote?
Vous pouvez abuser du tokenizer Python pour analyser la liste de valeurs de clé: Vous pouvez utiliser un Machine à états fini (FSM) pour mettre en œuvre un analyseur plus strict. L'analyseur utilise uniquement l'état actuel et le jeton suivant pour analyser l'entrée: P> sortie h3>
#!/usr/bin/env python
from tokenize import generate_tokens, NAME, NUMBER, OP, STRING, ENDMARKER
def parse_key_value_list(text):
def check(condition):
if not condition:
raise ValueError((state, token))
KEY, EQ, VALUE, SEP = range(4)
state = KEY
for token in generate_tokens(lambda it=iter([text]): next(it)):
type, string = token[:2]
if state == KEY:
check(type == NAME)
key = string
state = EQ
elif state == EQ:
check(type == OP and string == '=')
state = VALUE
elif state == VALUE:
check(type in {NAME, NUMBER, STRING})
value = {
NAME: lambda x: x,
NUMBER: int,
STRING: lambda x: x[1:-1]
}[type](string)
state = SEP
elif state == SEP:
check(type == OP and string == ',' or type == ENDMARKER)
yield key, value
state = KEY
text = '''age=12,name=bob,hobbies="games,reading",phrase="I'm cool!"'''
print(dict(parse_key_value_list(text)))
Vous devez simplement utiliser votre Ajouter (voir Les règles de analyse SHLEX ) p> sorties: p> ps: expressions régulières ne sera pas en mesure d'analyser les paires de la valeur clé aussi longue Comme l'entrée peut contenir citer shlex code> lexer en mode POSIX.
posix = true code> lors de la création du LXER. P>
= code> ou
, code> caractères. Même le prétraitement de la chaîne ne serait pas en mesure de faire une analyse d'une expression régulière, car ce type d'entrée ne peut pas être formellement défini comme une langue régulière. p> p>
Je pense que celui-ci est le meilleur, car il gère tous les cas et utilise la bibliothèque shlex code> au lieu de réinventer la roue.
Une meilleure stratégie pourrait être comme celle-ci: première division par des signes égaux puis divisée par la dernière virgule de chaque chaîne.
Le moyen le plus simple de le faire est d'utiliser une regex.
@ Seçkinsavaşçı: Sauf s'il ya des signes égaux entre guillemets ...
Si vous insistez sur l'utilisation d'un REGEXP et que des devis doubles seront toujours utilisés pour les chaînes et n'apparaissent jamais dans elles, vous pouvez diviser la chaîne sur
" code> afin que vous puissiez identifier les chaînes citées et les contourner .
@Scotthunter est tout à fait d'accord avec vous, c'est pourquoi ma suggestion n'est pas qualifiée de réponse valide.
Le poste sur la scission sur les semi-couches ne semble pas aborder le type de citation que j'ai.
@Scotthunter Je pense que le module
csv code> pourrait être utilisé avec un fichier
= code> délimiter, et cela va protéger contre le scission sur
= code> dans les guillemets.
@Alex Martelli: C'est pas i> un duplicata. L'adaptation de la réponse acceptée de La question liée ne fonctionne pas i> pour l'entrée du courant Question:
[suivant (csv.reader ([élément], délimiter = '=')) Pour l'élément dans Suivant (CSV.Reader ([S]))] CODE>
"jeux, lecture" code>). Les questions sont similaires, mais cette question nécessite i> un tel soutien.