2009-10-29 8 views
1

je un fichier avec des lignes commemeilleure façon d'analyser une ligne en python à un dictionnaire

account = "TEST1" Qty=100 price = 20.11 subject="some value" values="3=this, 4=that" 

Il n'y a pas delimiter spécial et chaque clé a une valeur qui est entourée par des guillemets doubles si elle une chaîne, mais pas si c'est un nombre. Il n'y a pas de clé sans valeur bien qu'il puisse exister des chaînes vides qui sont représentées par "" et il n'y a pas de caractère d'échappement pour une citation car elle n'est pas nécessaire

Je veux savoir quelle est une bonne façon d'analyser ce genre de ligne avec python et stocker les valeurs comme paires clé-valeur dans un dictionnaire

Répondre

10

Nous allons avoir besoin d'une regex pour cela.

import re, decimal 
r= re.compile('([^ =]+) *= *("[^"]*"|[^ ]*)') 

d= {} 
for k, v in r.findall(line): 
    if v[:1]=='"': 
     d[k]= v[1:-1] 
    else: 
     d[k]= decimal.Decimal(v) 

>>> d 
{'account': 'TEST1', 'subject': 'some value', 'values': '3=this, 4=that', 'price': Decimal('20.11'), 'Qty': Decimal('100.0')} 

Vous pouvez utiliser float au lieu de décimal si vous préférez, mais c'est probablement une mauvaise idée si l'argent est impliqué.

+0

Pouvez-vous expliquer cette regex? – ash

0

Une variation récursive des valeurs de bobince parse avec intégré égal dictionnaires:

>>> import re 
>>> import pprint 
>>> 
>>> def parse_line(line): 
...  d = {} 
...  a = re.compile(r'\s*(\w+)\s*=\s*("[^"]*"|[^ ,]*),?') 
...  float_re = re.compile(r'^\d.+$') 
...  int_re = re.compile(r'^\d+$') 
...  for k,v in a.findall(line): 
...    if int_re.match(k): 
...      k = int(k) 
...    if v[-1] == '"': 
...      v = v[1:-1] 
...    if '=' in v: 
...      d[k] = parse_line(v) 
...    elif int_re.match(v): 
...      d[k] = int(v) 
...    elif float_re.match(v): 
...      d[k] = float(v) 
...    else: 
...      d[k] = v 
...  return d 
... 
>>> line = 'account = "TEST1" Qty=100 price = 20.11 subject="some value" values= 
"3=this, 4=that"' 
>>> pprint.pprint(parse_line(line)) 
{'Qty': 100, 
'account': 'TEST1', 
'price': 20.109999999999999, 
'subject': 'some value', 
'values': {3: 'this', 4: 'that'}} 
0

Si vous ne souhaitez pas utiliser une expression régulière, une autre option est juste de lire la chaîne d'un caractère à la fois:

string = 'account = "TEST1" Qty=100 price = 20.11 subject="some value" values="3=this, 4=that"' 

inside_quotes = False 
key = None 
value = "" 
dict = {} 

for c in string: 
    if c == '"': 
     inside_quotes = not inside_quotes 
    elif c == '=' and not inside_quotes: 
     key = value 
     value = '' 
    elif c == ' ': 
     if inside_quotes: 
      value += ' '; 
     elif key and value: 
      dict[key] = value 
      key = None 
      value = '' 
    else: 
     value += c 

dict[key] = value 
print dict 
5

Peut-être un peu plus simple à suivre est l'interprétation pyparsing:

from pyparsing import * 

# define basic elements - use re's for numerics, faster than easier than 
# composing from pyparsing objects 
integer = Regex(r'[+-]?\d+') 
real = Regex(r'[+-]?\d+\.\d*') 
ident = Word(alphanums) 
value = real | integer | quotedString.setParseAction(removeQuotes) 

# define a key-value pair, and a configline as one or more of these 
# wrap configline in a Dict so that results are accessible by given keys 
kvpair = Group(ident + Suppress('=') + value) 
configline = Dict(OneOrMore(kvpair)) 

src = 'account = "TEST1" Qty=100 price = 20.11 subject="some value" ' \ 
     'values="3=this, 4=that"' 

configitems = configline.parseString(src) 

Maintenant, vous pouvez accéder à vos pièces en utilisant l'objet ParseResults configitems retourné:

>>> print configitems.asList() 
[['account', 'TEST1'], ['Qty', '100'], ['price', '20.11'], 
['subject', 'some value'], ['values', '3=this, 4=that']] 

>>> print configitems.asDict() 
{'account': 'TEST1', 'Qty': '100', 'values': '3=this, 4=that', 
    'price': '20.11', 'subject': 'some value'} 

>>> print configitems.dump() 
[['account', 'TEST1'], ['Qty', '100'], ['price', '20.11'], 
['subject', 'some value'], ['values', '3=this, 4=that']] 
- Qty: 100 
- account: TEST1 
- price: 20.11 
- subject: some value 
- values: 3=this, 4=that 

>>> print configitems.keys() 
['account', 'subject', 'values', 'price', 'Qty'] 

>>> print configitems.subject 
some value 
Questions connexes