Ich brauche das ganze als dict:a=1 b="X Y Z" c=True d=None
Code: Alles auswählen
{"a": 1, "b":"X Y Z", "c": True, "d": None}
Ich brauche das ganze als dict:a=1 b="X Y Z" c=True d=None
Code: Alles auswählen
{"a": 1, "b":"X Y Z", "c": True, "d": None}
Code: Alles auswählen
['a', '1 b', '"X Y Z" c', 'True d', 'None']
Kennt Python evaluierende RegExes wie bei perl mit dem e-Modifier also s/Pattern/Replacement/e?jens hat geschrieben:Ich habe eine String, der könnte so aussehen:Ich brauche das ganze als dict:a=1 b="X Y Z" c=True d=NoneIrgendeine Idee wie man das Umformen könnte? Evtl. mit RE?Code: Alles auswählen
{"a": 1, "b":"X Y Z", "c": True, "d": None}
Code: Alles auswählen
>>> s = '''a=1 b="X Y Z" c=True d='test' e=None'''
>>> cre = re.compile(r'''(?P<name>\w+)=(?P<quote>["']?)(?P<value>.+?)(?P=quote)(?=\s|$)''')
>>> cre.findall(s)
[('a', '', '1'), ('b', '"', 'X Y Z'), ('c', '', 'True'), ('d', "'", 'test'), ('e', '', 'None')]
>>> cre.search(s).groupdict()
{'name': 'a', 'value': '1', 'quote': ''}
murks pasiert! : )DasIch hat geschrieben:Wenn man auf Leerzeichen splitet und einer der Werte ist ein String passiert was?
Code: Alles auswählen
import re
splitRE = re.compile('(\w*="[\w\s=]*"|\w=\w*)')
PAIR_SEP = '='
NAT_TYPE_MAP = {
'True' : True,
'False' : False,
'None' : None,
}
def str2type(basestr):
"""Converts a string into matching type"""
assert isinstance(basestr, (str, unicode))
if NAT_TYPE_MAP.has_key(basestr):
return NAT_TYPE_MAP[basestr]
try:
return int(basestr)
except ValueError:
pass
return basestr
def str2dict(basestr):
"""Converts a string configuration into a dictionary"""
assert isinstance(basestr, (str, unicode))
result = {}
for hit in splitRE.findall(basestr):
key, value = hit.split(PAIR_SEP, 1)
if result.has_key(key):
raise KeyError('Duplicated key', key)
result[key] = str2type(value)
return result
Code: Alles auswählen
>>> for key, value in str2dict('a=1 b="X Y Z" c=True d=None').iteritems():
... print key, value, type(value)
a 1 <type 'int'>
c True <type 'bool'>
b "X Y Z" <type 'str'>
d None <type 'NoneType'>
Code: Alles auswählen
In [84]: shlex.split('''a=1 b="X Y Z" c=True d='test' e=None''')
Out[84]: ['a=1', 'b=X Y Z', 'c=True', 'd=test', 'e=None']
shlex muss ich mir merkenBlackJack hat geschrieben:Vielleicht hilft das Modul `shlex` aus der Standardbibliothek einen Schritt weiter?
An das Ergebnis kann man dann mit `split('=', 1)` gehen um die Bezeichner von den Werten zu trennen.Code: Alles auswählen
In [84]: shlex.split('''a=1 b="X Y Z" c=True d='test' e=None''') Out[84]: ['a=1', 'b=X Y Z', 'c=True', 'd=test', 'e=None']
Ansonsten würde ich zu Pyparsing greifen, bevor ich anfangen würde unlesbare regex-Monster zu basteln.
Code: Alles auswählen
ts = u'a=1 b="X Y Z" c=True d=None'
dd = {}
keys = [k for k in ts if ts[ts.index(k)+1]=='=']
for i, item in enumerate(ts):
if item == '=':
key = ts[i-1]
last_key = keys[-1] == key
if last_key:
value = ts[i+1:]
else:
value = ts[i+1:ts.index(keys[keys.index(key)+1])-1]
dd[key] = eval(value)
Code: Alles auswählen
In [196]: dict((k, v) for k,v in [x.split('=') for x in shlex.split(ts)])
Out[196]: {'a': '1', 'b': 'X Y Z', 'c': 'True', 'd': 'None'}
Code: Alles auswählen
>>> import re
>>> splitRE = re.compile('(\w*=".*"|\w*=\w*)')
>>> for hit in splitRE.findall(u'a=1 b="X=Y=Z" c=True d=None'):
... key, value = hit.split('=',1)
... value = eval(value)
... print key, value, type(value)
...
a 1 <type 'int'>
b X=Y=Z <type 'str'>
c True <type 'bool'>
d None <type 'NoneType'>
Stimmt, das hier geht aber:Karl hat geschrieben:EnTeQuAk: Deine Lösung kann aber zum Beispiel nicht mit einem = in einem String umgehen, weil dann ein SyntaxError kommen müsste.
Außerdem wird ja immer gegen eval gepredigt
Code: Alles auswählen
def split(s):
keys = [k for k in s if s[s.index(k)+1]=='=']
for i, item in enumerate(s):
if item == '=':
key = s[i-1]
if not key in keys:
continue
last_key = keys[-1] == key
if last_key:
value = s[i+1:]
else:
value = s[i+1:s.index(keys[keys.index(key)+1])-1]
yield key, value
def main():
ts = u'a=1 b="X =Y Z" c=True d=None'
print dict((k, eval(v)) for k,v in split(ts))
if __name__ == '__main__':
main()
Und was ist mit nicht-\w-Zeichen wie [.,;:], Klammern, usw.?Masaru hat geschrieben:@Karl: Hier wäre dann das Problem mit einem '=' im String wieder ausgehebelt .
Code: Alles auswählen
import re
s = u'a=1 b="X=Y=Z" c=True d=None'
r = dict([ (t[0], eval(t[1])) for t in [ h.split('=', 1) for h in re.findall('(\w*=".*"|\w*=\w*)', s) ]])