如何将随机字符串(包含各种字符)解析为连贯的内容?
例如,string = '{"letters" : '321"}{}"'}{'{}{{}"': "stack{}}{"}'
我想分开:
{"letters" : '321"}{}"'}
和{'{}{{}"': "stack{}}{"}
我已尝试遍历string
并计算每个左括号{
,并在显示近距离}
时减去。但是,这不起作用,因为有些情况下括号位于""
或''
内
我的代码是:
list1 = [] # list1 is where we build up the first string
list2 = [] # list2 is where we keep the strings after building
for c in string:
list1.append(c)
if c == "{":
bracket_counter += 1
elif c == "}":
bracket_counter -= 1
if bracket_counter == 0:
list2.append("".join(item))
list1 = []
使用此代码,第一个被认为是"完成"是{"letters" : '321"}
,即使它应该是{"letters" : '321"}{}"'}
我对正则表达式很不熟悉,所以我不确定这是否应该用于它。任何帮助表示赞赏。
谢谢!
答案 0 :(得分:2)
您使用正则表达式标记化您的字符串,然后您将迭代这些标记。例如:
SQ = r"'[^']*'" # single-quoted string
DQ = r'"[^"]*"' # double-quoted string
OPS = r'[{}:]' # operators
WS = r'\s+' # whitespace
# add more types as needed...
tokens = '(?:' + '|'.join([OPS, SQ, DQ, WS]) + ')'
pattern = re.compile(tokens, re.DOTALL)
def tokenize(source):
start = 0
end = len(source)
while start < end:
match = pattern.match(source, start)
if match:
yield match.group(0)
else:
raise ValueError('Invalid syntax at character %d' % start)
start = match.end()
然后您可以在这些令牌上运行for
循环:
for token in tokenize(string):
...
示例输入时的标记为:
>>> for token in tokenize(string):
... print(token)
'{'
'"letters"'
' '
':'
' '
'\'321"}{}"\''
'}'
'{'
'\'{}{{}"\''
':'
' '
'"stack{}}{"'
'}'
正如您所看到的,您可以从中正确计算'{'
和'}'
。
请注意,上面的正则表达式没有转义字符串中'
或"
的概念;如果您希望\
转义结束字母并正确标记,则可以将SQ
和DQ
正则表达式更改为
SQ = r"'(?:[^\\']|\\.)*'"
DQ = r'"(?:[^\\"]|\\.)*"'
此外,如果您还希望允许任何其他字符但未特别处理,则可以添加
NON_SPECIAL = r'[^\'"]'
作为正则表达式的最后一个分支:
tokens = '(?:' + '|'.join([OPS, SQ, DQ, WS, NON_SPECIAL]) + ')'
答案 1 :(得分:0)
您还必须检查您是否在字符串中。一个简单的方法是创建另一个变量并跳过循环,如果你在一个字符串中并且它不是结束字符。
bracket_counter = 0
quote = ""
list1 = [] # list1 is where we build up the first string
list2 = [] # list2 is where we keep the strings after building
for c in string:
list1.append(c)
if not quote or c == quote: # If quote is blank or found the closing quote
quote = ""
if c == "{":
bracket_counter += 1
elif c == "}":
bracket_counter -= 1
if bracket_counter == 0:
list2.append("".join(item))
list1 = []
elif c in "'\"": # If the character is a quote character
quote = c # Will skip loops until quote is found
如果你想要一个正则表达式,你首先会效仿:
{.*?}
但是你想忽略引号,所以你会这样做:
{((".*?")|('.*?')|.)*?}
基本上,这利用了懒惰的量词。它试图找到引用的东西为&#34; ...&#34;,然后&#39; ...&#39;然后最终挑选任何角色。
如果您不想使用延迟量词,请使用正则表达式:
{("[^"]*"|'[^']*'|[^{}])*}
这给出了代码:
import re
def parse(s):
return [group[0] for group in re.findall("({((\".*?\")|('.*?')|.)*?})", s)]
用法:
>>> string = """{"letters" : '321"}{}"'}{'{}{{}"': "stack{}}{"}"""
>>> parse(string)
['{"letters" : \'321"}{}"\'}', '{\'{}{{}"\': "stack{}}{"}']
>>> print(", ".join(parse(string)))
{"letters" : '321"}{}"'}, {'{}{{}"': "stack{}}{"}
答案 2 :(得分:0)
这是一个 Python 问题,但您可以移植 javascript 包 dqtokenizer https://www.npmjs.com/package/dqtokenizer 代码以更轻松地执行此操作。
testTokenize(`{"letters" : '321"}{}"'}{'{}{{}"': "stack{}}{"}`, {
additionalBoundaryChars: [],
singleCharTokens: ['(', ')', '{', '}', '[', ']', ':'],
});
输出:
tokens:
0: {
1: "letters"
2: :
3: '321"}{}"'
4: }
5: {
6: '{}{{}"'
7: :
8: "stack{}}{"
9: }