【问题标题】:Python multiline regex + multi entries reading a file in one goPython多行正则表达式+多条目一次性读取文件
【发布时间】:2011-08-06 20:59:04
【问题描述】:
//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 或 EOF。

使用 re.MULTILINE 一次性获取所有信息的最佳方式是什么?

【问题讨论】:

    标签: python regex file match multiline


    【解决方案1】:

    您可以使用regexp positive lookahead 进行分组:

    (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(";")
    

    找到后

    【讨论】:

    • 谢谢 - 我喜欢这种方法。有什么办法可以把它读进字典吗? {'a_SET': [lines], 'b_SET':[nextlines]} 等等?
    • 如果 RE 中没有 '^' 也没有 '&' 的话,放标志 re.MULTILINE 是没用的
    • @eyquem: "显式优于隐式" ;)
    • 当某些东西是“隐含的”时,这意味着尽管它是不可见的,但它是有用的。 “显式”是否意味着虽然可见但可能没用?
    【解决方案2】:

    我知道了:

    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" 之前的第一个字符串"..." 和最后一个字符串"..."。所以可以出现几个"...",不只是3个。你没问这个条件,但我想可能恰好需要它。

    我还设法使字符串中出现换行符以捕获 "....\n......" ,而不仅仅是在它们周围。为此,我不得不为我发明一些新的东西:(?:\n(?! *setAttr)|[^"\n]) 这意味着:除了'"' 和常见的newlines \n 之外的所有字符都被接受,并且只有那些后面没有以@987654333 开头的行的换行符@

    对于(?:\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'}
    

    【讨论】:

    • 我喜欢这种方法——它运作良好。我已经在下面发布了另一个选项 - 你将如何解决这种可能性(当行在字符串的开头用 '\n' 断开时?谢谢!
    【解决方案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)
    

    【讨论】:

    • @eyquem 另外可能还有一个 /t 制表符分隔符,因此键 "test1" 的值将变为 "hmm blablabla" 但现在它与行 setAttr -l on -k on ".test1" -type "string" 由 @987654326 分隔@ 可能还有一两个 \t 标签
    • @eyquem 感谢您的快速回复!欣赏!我已经尝试过了,它在上面的示例中效果很好,但在下面发布的示例中失败了 - 你知道我在这里还缺少什么吗?此刻有点失落。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多