Разбор строки для вложенных шаблонов - PullRequest
3 голосов
/ 01 декабря 2008

Какой лучший способ сделать это.

Строка ввода

<133_3><135_3><116_2>The other system worked for about 1 month</116_2> got some good images <137_3>on it then it started doing the same thing as the first one</137_3> so then I quit using either camera now they are just sitting and collecting dust.</135_3></133_3>

ожидаемый результат

{'The other system worked for about 1 month got some good images on it then it started doing the same thing as the first one so then I quit \
using either camera now they are just sitting and collecting dust.':[133, 135],

'The other system worked for about 1 month': [116],

'on it then it started doing the same thing as the first one':[137]

}

это похоже на рекурсивный поиск регулярных выражений, но я не могу понять, как именно.

Сейчас я могу думать об утомительной рекурсивной функции, но чувствую, что должен быть лучший способ.

Смежный вопрос: Можно ли использовать регулярные выражения для сопоставления с вложенными шаблонами?

Ответы [ 6 ]

4 голосов
/ 01 декабря 2008

Использовать expat или другой XML-парсер; это более явно, чем что-либо еще, учитывая, что вы все равно имеете дело с данными XML.

Однако обратите внимание, что имена элементов XML не могут начинаться с цифры, поскольку в вашем примере они есть.

Вот парсер, который будет делать то, что вам нужно, хотя вам нужно настроить его так, чтобы объединить дублирующиеся элементы в один ключ dict:

from xml.parsers.expat import ParserCreate

open_elements = {}
result_dict = {}

def start_element(name, attrs):
    open_elements[name] = True

def end_element(name):
    del open_elements[name]

def char_data(data):
    for element in open_elements:
        cur = result_dict.setdefault(element, '')
        result_dict[element] = cur + data

if __name__ == '__main__':
    p = ParserCreate()

    p.StartElementHandler = start_element
    p.EndElementHandler = end_element
    p.CharacterDataHandler = char_data

    p.Parse(u'<_133_3><_135_3><_116_2>The other system worked for about 1 month</_116_2> got some good images <_137_3>on it then it started doing the same thing as the first one</_137_3> so then I quit using either camera now they are just sitting and collecting dust.</_135_3></_133_3>', 1)

    print result_dict
4 голосов
/ 01 декабря 2008

Возьмите анализатор XML, заставьте его сгенерировать DOM (объектную модель документа), а затем создайте рекурсивный алгоритм, который пересекает все узлы, вызывает «text ()» в каждом узле (который должен дать вам текст в текущем узле). и все дети) и помещает это в качестве ключа в словаре.

2 голосов
/ 01 декабря 2008
from cStringIO   import StringIO
from collections import defaultdict
####from xml.etree   import cElementTree as etree
from lxml import etree

xml = "<e133_3><e135_3><e116_2>The other system worked for about 1 month</e116_2> got some good images <e137_3>on it then it started doing the same thing as the first one</e137_3> so then I quit using either camera now they are just sitting and collecting dust. </e135_3></e133_3>"

d = defaultdict(list)
for event, elem in etree.iterparse(StringIO(xml)):
    d[''.join(elem.itertext())].append(int(elem.tag[1:-2]))

print(dict(d.items()))

Выход:

{'on it then it started doing the same thing as the first one': [137], 
'The other system worked for about 1 month': [116], 
'The other system worked for about 1 month got some good images on it then it started doing the same thing as the first one so then I quit using \
either camera now they are just sitting and collecting dust. ': [133, 135]}
1 голос
/ 01 декабря 2008

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

Возьмите следующий мини-язык:

Определенное число "(", за которым следует то же число ")", независимо от того, какое число.

Вы могли бы очень легко сделать регулярное выражение для представления супер-языка этого мини-языка (где вы не применяете равенство количества начальных скобок и конечных скобок). Вы также можете легко создать регулярное выражение для представления любого конечного подъязыка (где вы ограничиваете себя до максимальной глубины вложенности). Но вы никогда не сможете представить этот точный язык в регулярном выражении.

Так что вам придется использовать грамматику, да.

1 голос
/ 01 декабря 2008

Я думаю, что грамматика будет лучшим вариантом здесь. Я нашел ссылку с некоторой информацией: http://www.onlamp.com/pub/a/python/2006/01/26/pyparsing.html

0 голосов
/ 01 декабря 2008

Вот ненадежное неэффективное рекурсивное решение регулярных выражений:

import re

re_tag = re.compile(r'<(?P<tag>[^>]+)>(?P<content>.*?)</(?P=tag)>', re.S)

def iterparse(text, tag=None):
    if tag is not None: yield tag, text
    for m in re_tag.finditer(text):
        for tag, text in iterparse(m.group('content'), m.group('tag')):
            yield tag, text

def strip_tags(content):
    nested = lambda m: re_tag.sub(nested, m.group('content'))
    return re_tag.sub(nested, content)


txt = "<133_3><135_3><116_2>The other system worked for about 1 month</116_2> got some good images <137_3>on it then it started doing the same thing as the first one</137_3> so then I quit using either camera now they are just sitting and collecting dust. </135_3></133_3>"
d = {}
for tag, text in iterparse(txt):
    d.setdefault(strip_tags(text), []).append(int(tag[:-2]))

print(d)

Выход:

{'on it then it started doing the same thing as the first one': [137], 
 'The other system worked for about 1 month': [116], 
 'The other system worked for about 1 month got some good images on it then it started doing the same thing as the first one so then I quit using \
 either camera now they are just sitting and collecting dust. ': [133, 135]}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...