Python多行正则表达式+一次读取多个文件条目
//Last modified: Sat, Apr 16, 2011 09:55:04 AM
//Codeset: ISO-8859-1
fileInfo "version" "20x64";
createNode newnode -n "a_SET";
addAttr -ci true -k true -sn "connections" -ln "connections" -dt "string";
setAttr -l on -k off ".tx";
setAttr -l on -k off ".ty";
setAttr -l on -k off ".sz";
setAttr -l on -k on ".test1" -type "string" "blabla";
setAttr -l on -k on ".test2" -type "string" "blablabla";
createNode newnode -n "b_SET";
addAttr -ci true -k true -sn "connections" -ln "connections" -dt "string";
setAttr -l on -k off ".tx";
setAttr -l on -k off ".ty";
setAttr -l on -k off ".sz";
setAttr -l on -k on ".test1" -type "string" "hmm";
setAttr -l on -k on ".test2" -type "string" "ehmehm";
在Python中:
我需要读取一些新的节点名称,比如“a_SET”和“b_SET”,以及它们对应的属性值,比如{"a_SET": {"test1":"blabla", "test2":"blablabla"},b_SET也是类似的 - 可能会有不确定数量的集合,比如c_SET、d_SET等等。
我尝试过通过逐行循环来匹配这些内容:
for line in fileopened:
setmatch = re.match( r'^(createNode set -n ")(.*)(_SET)(.*)' , line)
if setmatch:
sets.append(setmatch.group(2))
一旦我在这里找到匹配的内容,我就会继续循环下一行,以获取该集合的属性(test1、test2),直到我找到一个新的集合,比如c_SET,或者到达文件的结束。
有什么好的方法可以一次性抓取所有这些信息,使用re.MULTILINE吗?
3 个回答
还有一个可能的选项:
createNode newnode -n "b_SET";
addAttr -ci true -k true -sn "connections" -ln "connections" -dt "string";
setAttr -l on -k off ".tx";
setAttr -l on -k off ".ty";
setAttr -l on -k off ".sz";
setAttr -l on -k on ".test1" -type "string" (
"hmm blablabla" );
setAttr -l on -k on ".test2" -type "string" "ehmehm";
所以你可以看到".test1"的值现在是用/n换行符分开的。你会如何用eyquem的方法来解决这个问题呢?
pit = re.compile('^ *setAttr.+?("[^"\n]+").+("[^"\n]+");(?:\n|\Z)',re.MULTILINE)
你可以使用正则表达式中的正向前瞻来分割这些组:
(yourGroupSeparator)(.*?)(?=yourGroupSeparator|\Z)
在你的例子中:
import re
lines = open("e:/temp/test.txt").read()
matches = re.findall(r'createNode newnode \-n (\"._SET\");(.*?)(?=createNode|\Z)', lines, re.MULTILINE + re.DOTALL);
for m in matches:
print "%s:" % m[0], m[1]
"""
Result:
>>>
"a_SET":
addAttr -ci true -k true -sn "connections" -ln "connections" -dt "string";
setAttr -l on -k off ".tx";
setAttr -l on -k off ".ty";
setAttr -l on -k off ".sz";
setAttr -l on -k on ".test1" -type "string" "blabla";
setAttr -l on -k on ".test2" -type "string" "blablabla";
"b_SET":
addAttr -ci true -k true -sn "connections" -ln "connections" -dt "string";
setAttr -l on -k off ".tx";
setAttr -l on -k off ".ty";
setAttr -l on -k off ".sz";
setAttr -l on -k on ".test1" -type "string" "hmm";
setAttr -l on -k on ".test2" -type "string" "ehmehm";
"""
如果你想把结果放到一个字典里,可以使用:
result = {}
for k, v in matches:
result[k] = v # or maybe v.split() or v.split(";")
在使用findall之后
我得到了这个:
import re
filename = 'tr.txt'
with open(filename,'r') as f:
ch = f.read()
pat = re.compile('createNode newnode -n ("\w+?_SET");(.*?)(?=createNode|\Z)',re.DOTALL)
pit = re.compile('^ *setAttr.+?("[^"\n]+").+("[^"\n]+");(?:\n|\Z)',re.MULTILINE)
dic = dict( (mat.group(1),dict(pit.findall(mat.group(2)))) for mat in pat.finditer(ch))
print dic
结果
{'"b_SET"': {'".test2"': '"ehmehm"', '".test1"': '"hmm"'}, '"a_SET"': {'".test2"': '"blablabla"', '".test1"': '"blabla"'}}
.
问题:
如果字符串中必须包含字符 '"'
,那它是怎么表示的呢?
.
编辑
我在寻找解决方案时遇到了一些困难,因为我没有选择合适的工具。
这里有一个新的模式,它可以捕捉到第一个字符串 "..."
和最后一个字符串 "..."
,这些字符串出现在 " setAttr"
之后,并且在下一个 " setAttr"
之前。所以可能会有多个 "..."
,不仅仅是三个。你没有问这个条件,但我觉得可能会需要。
我还成功地让字符串中可以包含换行符,以便捕捉到 "....\n......"
,而不仅仅是它们周围的内容。为此,我不得不为自己发明一些新东西:(?:\n(?! *setAttr)|[^"\n])
,这意味着:所有字符都可以接受,除了 '"'
和常见的 newlines \n
,同时也只接受那些不跟在以 ' *setAttr'
开头的行后的换行符。
对于 (?:\n(?! *setAttr)|.)
,它的意思是:换行符后面不跟以 ' *setAttr'
开头的行,以及所有其他非换行字符。
因此,任何其他特殊序列,比如制表符或其他字符,都会自动被接受到匹配中。
ch = '''//Last modified: Sat, Apr 16, 2011 09:55:04 AM
//Codeset: ISO-8859-1
fileInfo "version" "20x64";
createNode newnode -n "a_SET";
addAttr -ci true -k true -sn "connections" -ln "connections" -dt "string";
setAttr -l on -k off ".tx";
setAttr -l on -k off ".ty";
setAttr -l on -k off ".sz";
setAttr -l on -k on ".test1" -type "string" "blabla";
setAttr -l on -k on ".test2" -type "string" "blablabla";
createNode newnode -n "b_SET";
addAttr -ci true -k true -sn "connections" -ln "connections" -dt "string";
setAttr -l on -k off ".tx";
setAttr -l on -k off ".ty";
setAttr -l on -k off ".sz";
setAttr -l on -k on ".test1" -type "string" (
"hmm bl
abla\tbla" );
setAttr -l on -k on ".tes\nt\t2" -type "string" "ehm\tehm";
setAttr -l on -k on ".test3" -type "string" "too
much" "pff" """ "feretini" "gol\nolo";
'''
import re
pat = re.compile('createNode newnode -n ("\w+?_SET");(.*?)(?=createNode|\Z)',re.DOTALL)
pot = re.compile('^ *setAttr.+?'
'"((?:\n(?! *setAttr)|[^"\n])+)"'
'(?:\n(?! *setAttr)|.)+'
'"((?:\n(?! *setAttr)|[^"\n])+)"'
'.*;(?:\n|\Z)',re.MULTILINE)
dic = dict( (mat.group(1),dict(pot.findall(mat.group(2)))) for mat in pat.finditer(ch))
for x in dic:
print x,'\n',dic[x],'\n'
结果
"b_SET"
{'.test3': 'gol\nolo', '.test1': 'hmm bl\n abla\tbla', '.tes\nt\t2': 'ehm\tehm'}
"a_SET"
{'.test1': 'blabla', '.test2': 'blablabla'}