python - Python:将复杂的类似列表的字符串转换为列表(没有用于混合字节和非字节文字的 SyntaxError)
问题描述
我有这个字符串:u'''[ "A", """B""",'C' , " D"]'''
我想得到一个类似的列表:["A","""B""",'C'," D"]
*edited as ""B"" 确实无效
有些使用“”“”或''来逃避'或“或两者兼而有之。
我尝试了各种解决方案: 将列表的字符串表示形式转换为列表
s= u'''[ "A", """B""",'C' , " D"]'''
1)
import numpy as np
List = np.array(s).tolist()
print(List)
print(type(List))
结果 :
[ "A", """B""",'C' , " D"]
<class 'str'>
所以不是一个列表,然后:
2)
import ast
List = ast.literal_eval(s)
print(List)
print(type(List))
结果
SyntaxError: cannot mix bytes and nonbytes literals
任何其他想法如何做到这一点?(我正在使用 Python 3.6)
我想到了正则表达式或简单的字符串替换,但是当我想到所有我们逃避替换列表元素中的“,”等字符的情况时,它变得非常复杂
解决方案
ast.literal_eval(s)
只要不存在未转义的引号,使用效果就很好。我们可以使用正则表达式来解决这个问题。不幸的是,这并不容易。但是,我为你找到了灵丹妙药。
首先,让我们识别所有具有相同类型内引号的带引号的子字符串:
(?<=[\[,])\s*(['\"])(?:(\1)|.)*?\1(?=\s*[,\]])
解释
(?<=[\[,])
使用lookbehind的前锚:列表或前一个列表元素的开头:[
或,
\s*
零个或多个空格(['\"])
捕获组中的开盘报价(?:(\1)|.)*?
$1
懒惰匹配任何字符,如果与放入相同的引号$2
\1
使用反向引用结束报价(?=\s*[,\]])
使用前瞻的后锚:,
或]
现在,真正的乐趣开始了。接下来,在具有相同类型的内引号的子字符串中搜索未转义的引号。
为此,我使用Skip_what_to_avoid方法和一些高级正则表达式技术,例如展开循环。
^"[^"\\]*(?:\\.[^\"\\]*)*"$|^'[^'\\]*(?:\\.[^'\\]*)*'$|^\s*["'][^"'\\]*|["']\s*$|\\.|(["'])[^"'\\\n]*
这里的关键思想是完全忽略正则表达式引擎返回的整体匹配:$0
是垃圾桶。相反,我们只需要检查 capture group $1
,它在设置时包含我们正在寻找的内容。基本上,所有这些未捕获的交替匹配用引号括起来的常规、正确转义的子字符串。我们只想要未转义的。
我决定重新组合原始字符串,并\
添加必要的内容以正确转义那些未转义的引号。当然还有其他方法。
最后,将完整的示例代码放在一起(在线演示):
import re
import ast
test = ("[ \"A\", \"\"B\"\",'C' , \" D\"]\n"
"[ \"A\", \"'B'\",'C' , \" D\"]\n"
"[ \"A\", ''B'','C' , \" D\"]\n"
"[ \"A\", '\"B\"','C' , \" D\"]\n"
"[ \"A\", '8 o'clock','C' , \" D\"]\n"
"[ \"A\", \"Ol' 8 o'clock\",'C' , \" D\"]\n"
"[\"Some Text\"]\n"
"[\"Some more Text\"]\n"
"[\"Even more text about \\\"this text\\\"\"]\n"
"[\"Ol' 8 o'clock\"]\n"
"['8 o'clock']\n"
"[ '8 o'clock']\n"
"['Ol' 8 o'clock']\n"
"[\"\"B\"]\n"
"[\"\\\"B\"]\n"
"[\"\\\\\"B\"]\n"
"[\"\\\\\\\"B\"]\n"
"[\"\\\\\\\\\"B\"]")
result = u''
last_index = 0
regex1 = r"(?<=[\[,])\s*(['\"])(?:(\1)|.)*?\1(?=\s*[,\]])" #nested quotes of the same type
regex2 = r'''^"[^"\\]*(?:\\.[^\"\\]*)*"$|^'[^'\\]*(?:\\.[^'\\]*)*'$|^\s*["'][^"'\\]*|["']\s*$|\\.|(["'])[^"'\\\n]*''' # unescaped quotes in $1
matches = re.finditer(regex1, test, re.MULTILINE)
for match in matches:
if match.groups()[1] is not None: #nested quotes of the same type present
print(match.group())
inner = re.finditer(regex2, match.group())
for m in inner:
if m.groups()[0] is not None: # unescaped quotes in $1 present
result += test[last_index:match.start() + m.start()] + '\\' + m.group()
last_index = match.start()+m.end()
result += test[last_index:len(test)]
print(result)
for test_str in result.split("\n"):
List = ast.literal_eval(test_str)
print(List)
print(type(List))
我们有一个测试字符串,其中包含多个列表作为具有各种特殊情况的字符串文字:不同和相同类型的引号、转义引号、转义转义序列等。使用上面概述的解决方案清除测试字符串split
,然后单独使用 转换为列表literal_eval
。
这可能是迄今为止我制作的最先进的正则表达式解决方案之一。
推荐阅读
- c++ - 使用带有仅标头库的 Find*.cmake 文件
- c++ - LLVM IR codegen segfaults during exit only when method declarations have parameters
- powershell - 在 powershell 中发送“tab”键击
- authentication - 在集群身份验证服务中存储 RSA 密钥
- python-3.x - 无法通过请求上传工作表
- visual-studio-code - Visual Studio Code 无法解析资源
- asp.net - 事件处理程序未在初始化时初始化
- javascript - 如何创建一个函数来告诉您栅栏的哪一部分保持未着色?
- ios - 导航栏,不在第二个 ViewController 上显示
- java - 在 Spring Boot 中对 exportcsv 进行 Junit 测试