Многострочное регулярное выражение Python + множественные записи, читающие файл за один раз - PullRequest
0 голосов
/ 16 апреля 2011
//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?

Ответы [ 3 ]

3 голосов
/ 16 апреля 2011

Вы можете использовать регулярное выражение с положительным прогнозом , чтобы разделить группы:

(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

0 голосов
/ 19 апреля 2011

Другая возможная опция:

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 разделителем строк.Как бы вы обошли это, используя подход эйкема?

pit = re.compile('^ *setAttr.+?("[^"\n]+").+("[^"\n]+");(?:\n|\Z)',re.MULTILINE)
0 голосов
/ 16 апреля 2011

Я получил это:

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"'}}

.

Вопрос:

что если в строках должен быть символ '"'? Как это представлено?

.

EDIT

Мне было трудно найти решение, потому что я не выбрал учреждение.

Вот новый шаблон, который ловит первую строку "..." и последнюю строку "...", представленную после строки " setAttr" и перед следующей " setAttr". Таким образом, может присутствовать несколько "...", не только 3. Вы не задавали это условие, но я подумал, что оно может понадобиться.

Мне также удалось сделать возможным присутствие новых строк в строках, чтобы ловить "....\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'}
...