Skip to content

Instantly share code, notes, and snippets.

@dsoprea
Created July 20, 2024 09:24
Show Gist options
  • Save dsoprea/f0a5007b250c5005abbb6efa6d045c2a to your computer and use it in GitHub Desktop.
Save dsoprea/f0a5007b250c5005abbb6efa6d045c2a to your computer and use it in GitHub Desktop.
Tools to convert between dictionaries and strings with proper escaping
_ENCODED_ESCAPE_TRANSLATION = str.maketrans({
'\\': r'\\',
',': r'\,',
'=': r'\=',
})
def dictionary_to_string(d):
components = [
'{}={}'.format(
str(key).translate(_ENCODED_ESCAPE_TRANSLATION),
str(value).translate(_ENCODED_ESCAPE_TRANSLATION))
for key, value
in d.items()
]
encoded = ','.join(components)
return encoded
def _split_by_unescaped_character(s, separator):
last = 0
for i, c in enumerate(s):
if c != separator:
continue
elif i > 0 and s[i - 1] == '\\':
continue
value = s[last:i]
yield value
last = i + 1
value = s[last:]
yield value
def _unescape(s):
# Process the string in reverse, because we'll need to 'lookahead' in order
# to skip the preceding slashes
chars = []
len_ = len(s)
i = 0
r = list(reversed(s))
while i < len_:
c = r[i]
chars.append(c)
i += 1
# If it was escaped, remove the slash and step another position
if i < len_ and r[i] == '\\':
i += 1
return ''.join(reversed(chars))
def string_to_dictionary(s):
components = _split_by_unescaped_character(s, ',')
components = list(components)
d = {}
for component in components:
couplet = _split_by_unescaped_character(component, '=')
couplet = list(couplet)
assert \
len(couplet) == 2, \
"Name-value couplet does not have two parts: {}".format(couplet)
escaped_key, escaped_value = couplet
key = _unescape(escaped_key)
value = _unescape(escaped_value)
d[key] = value
return d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment