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'] Nur wenn du dann in deinen Zuweisungen zum Beispiel einen String mit einem '=' zuweist, wird's ein Problem.
 Nur wenn du dann in deinen Zuweisungen zum Beispiel einen String mit einem '=' zuweist, wird's ein Problem. Dann hab ich das Problem wohl unterschätzt
 Dann hab ich das Problem wohl unterschätzt 
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 resultCode: 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) ]])