1

I need to do a sort of reverse .format() to a string like

a = "01AA12345AB12345AABBCCDDEE".reverseformat({id:2d}{type:2s}{a:3d}{b:4s}{c:5d}{d:2s})
print a

>>>> {'id':1, 'type':'aa', 'a':'123', 'b':'45AB', 'c':'12345', 'd':'AA'} 

I found this lib that makes almost what i need, the problem is that it gives me this result

msg = parse.parse("{id:2d}{type:3S}{n:5S}", "01D1dddffffffff")

print msg.named

>>>>{'type': 'D1dddfffffff', 'id': 1, 'n': 'f'}

and not

{'id':1, 'type':'D1d', 'n':'ddfffff'}

Does another lib/method/wathever that can "unpack" a string to a dict exists?

EDIT: Just for clarify, i already tryed the w and D format specification for string

0

2 Answers 2

4

Is there any reason you can't just slice it like a normal string if your format is always the same?

s = "01D1dddffffffff"
id = s[:2]
type = s[2:5]
n = s[5:]

Which gives id, type, and n as:

01
D1d
ddffffffff

And it's trivial to convert this into a dictionary from there if that's your need. If your parsing doesn't need to be dynamic (which it doesn't seem to be from your question in it's current state) then it's easy enough to wrap the slicing in a function which will extract all of the values.

This also has the advantage that from the slice it's clear how many characters and what position in the string you're extracting, but in the parse formatter the positions are all relative (i.e. finding which characters n extracts means counting how many characters id and type consume).

Sign up to request clarification or add additional context in comments.

2 Comments

I know, before the parse lib it was like that, but it would have been more readable with that string format
I've responded to you as an extra edit to my answer. I personally think that the slice is clearer than the format specifier.
2

You can use regular expressions to do what you want here.

import re

a = "01AA12345AB12345AABBCCDDEE"
expr = re.compile(r"""
    (?P<id>.{2})          # id:2d
    (?P<type>.{2})        # type:2s
    (?P<a>.{3})           # a:3d
    (?P<b>.{4})           # b:4s
    (?P<c>.{5})           # c:5d
    (?P<d>.{2})           # d:2s""", re.X)

expr.match(a).groupdict()
# {'id': '01', 'b': '45AB', 'c': '12345', 'd': 'AA', 'a': '123', 'type': 'AA'}

You could even make a function that does this.

def unformat(s, formatting_str):
    typingdict = {'s': str, 'f': float, 'd':int}  # are there any more?
    name_to_type = {}
    groups = re.findall(r"{([^}]*)}", formatting_str)
    expr_str = ""
    for group in groups:
        name, formatspec = group.split(":")
        length, type_ = formatspec[:-1], typingdict.get(formatspec[-1], str)
        expr_str += "(?P<{name}>.{{{length}}})".format(name=name, length=length)
        name_to_type[name] = type_
    g = re.match(expr_str, s).groupdict()
    for k,v in g.items():
        g[k] = name_to_type[k](v)

    return g

Then calling like...

>>> a
'01AA12345AB12345AABBCCDDEE'
>>> result = unformat(a, "{id:2d}{type:2s}{a:3d}{b:4s}{c:5d}{d:2s}")
>>> result
{'id': 1, 'b': '45AB', 'c': 12345, 'd': 'AA', 'a': 123, 'type': 'AA'}

However I hope you can see how incredibly ugly this is. Don't do this -- just use string slicing.

3 Comments

Upvoted just for doing a regex version. Regex always makes me cringe slightly though.
@MattTaylor yeah it's a terrible solution, but it was fun to bite into. Building dynamic regexes seems like a task better suited for the damned or the mad, however! :)
Yay, exactly what i needed, i know that it's quite ugly, but it's easier to implement in my program since it's easier than the abnormous string slicing that i should have done

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.