【问题标题】:Convert string which contains escape characters to a dict将包含转义字符的字符串转换为字典
【发布时间】:2019-09-19 13:04:24
【问题描述】:

我需要将表示字典的python 字符串转换为python 字典。该字符串可能包含任何有效的 dict 表示,包括 windows 样式路径(带有反斜杠),例如

mystring = u'{"baselocaldir":"c:\\tmp\\SrcTmp\\RepManager"}'

我需要一个通用的 str 来 dict 转换函数,所以这只是一个源字符串的示例,它不起作用。源字符串可能来自外部源。首选兼容 python 2/3 的解决方案。

我已经尝试了给定的答案:

json.loads 不起作用(即使我将字符串重新格式化为 json 语法):引发异常

ast.literal_eval 不起作用:在此示例中,它在结果中放置了一个制表符

eval:结果与 ast.literal_eval 相同

【问题讨论】:

  • 这个字符串是如何产生的?似乎无论做什么都没有使用适当的约定/方法
  • 字符串中有一个TAB字符:\t(来自"c:\tmp....).
  • 没有标签 "c:\tmp\.." 会有标签 "c:\\tmp\\..." 只是一个反斜杠

标签: python string dictionary escaping


【解决方案1】:

我会对字符串进行 hack 以将 'c:' 替换为原始字符串文字 r'c:'

mystring = u'{"baselocaldir": "c:\\tmp\\SrcTmp\\RepManager"}'.replace('"c:', 'r"c:') 
_dict = eval(mystring)
_dict

结果:

{'baselocaldir': 'c:\\tmp\\SrcTmp\\RepManager'}

【讨论】:

  • 不起作用,因为输入字符串是 mystring = u'{"baselocaldir":"c:\\tmp\\SrcTmp\\RepManager"}' 而不是 mystring = u'{"baselocaldir ":"c:\tmp\SrcTmp\RepManager"}' - 并且:它需要将所有其他特殊字符替换为 \n \a ....
  • 我编辑了我的答案。基本上,您可以将值字符串转换为原始文字,这样它将忽略特殊字符,例如 \t、\n \a 等。
  • 编辑:不是解决方案,这会损坏(转义)字符串的 unicode 部分
【解决方案2】:

Edit3:将示例字符串改为双反斜杠后,更简单,无需使用正则表达式:

mystring = u'{"baselocaldir":"c:\\tmp\\SrcTmp\\RepManager"}'
test = repr(mystring)[1:-1] 
print(test)

# convert to dictionary
my_dict = json.loads(test)
print('dict key "baselocaldir" = ', my_dict["baselocaldir"])

输出:

{"baselocaldir":"c:\\tmp\\SrcTmp\\RepManager"}
dict key "baselocaldir" =  c:\tmp\SrcTmp\RepManager

Edit2:显然仅使用 repr() 是不够的,这就是为什么我编辑我的答案以使用正则表达式并将所有 \ 替换为 \\,这是代码:

import re, json
mystring = u'{"baselocaldir":"c:\tmp\SrcTmp\RepManager"}'

test = re.sub(r'(?<=[^\\])\\(?=[^\\])', r'\\\\', repr(mystring)[1:-1])
print(test)

# convert to dictionary
my_dict = json.loads(test)
print('dict key "baselocaldir" = ', my_dict["baselocaldir"])

输出:

{"baselocaldir":"c:\\tmp\\SrcTmp\\RepManager"}
dict key "baselocaldir" =  c:\tmp\SrcTmp\RepManager

上一个答案,这还不够 编辑: 将字符串转换为原始字符串的简单方法是使用repr()"%r"

这是一个一步解决方案,归功于 9 年前的 Nishanth Amuluru and Jed Alexander

mystring = u'{"baselocaldir":"c:\tmp\SrcTmp\RepManager"}'

raw_str = "%r"%mystring
rep_str= repr(mystring)

print('original string = ', mystring)
print('Raw string = ', raw_str)
print('rep string = ', rep_str)

输出:

original string =  {"baselocaldir":"c:  mp\SrcTmp\RepManager"}
Raw string =  '{"baselocaldir":"c:\tmp\\SrcTmp\\RepManager"}'
rep string =  '{"baselocaldir":"c:\tmp\\SrcTmp\\RepManager"}'

【讨论】:

  • 两个答案都不起作用,因为输入字符串是 mystring = u'{"baselocaldir":"c:\\tmp\\SrcTmp\\RepManager"}' 而不是 mystring = u'{ "baselocaldir":"c:\tmp\SrcTmp\RepManager"}'
  • @CarstenThielepape,用你的新字符串更容易,我们可以跳过使用正则表达式,检查我编辑的答案,它适用于 python 3.6
  • 你是对的,它适用于 python 3.x,但在 python 2.x 上失败
【解决方案3】:

我的(也许不是最优雅的)解决方案:

但它适用于 python2 、 python3 和 unicode 字符串中的 unicode 字符:


text_type = None
if PY2:
    string_types = basestring
    text_type = unicode
else:
    string_types = text_type = str

def DictUnescaceBackslash(oDict):
    for key, value in iteritems(oDict):
        if isinstance(value, dict):
            DictUnescaceBackslash(value)
        elif isinstance(value, string_types):
            oDict[key]=oDict[key].replace("***BaCkSlAsH***","\\")
        elif isinstance(value, list):
           for elem in value:
                DictUnescaceBackslash(elem)

mystring = u'{"baselocaldir":"c:\\tmp\\SrcTmp\\RepManager"}'
uString2 = mystring.replace("\\","***BaCkSlAsH***")
dDict    = ast.literal_eval(uString2)
DictUnescaceBackslash(dDict)


【讨论】:

    猜你喜欢
    • 2012-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-25
    • 1970-01-01
    相关资源
    最近更新 更多