Analizar una cadena para patrones nesteds

Cuál sería la mejor forma de hacer esto.

La cadena de entrada es

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. 

la salida esperada es

 {'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] } 

Eso parece una búsqueda de expresiones regulares recursiva, pero no puedo entender cómo exactamente.

Puedo pensar en una función recursiva tediosa a partir de ahora, pero tengo la sensación de que debería haber una mejor manera.

Pregunta relacionada: ¿Se pueden usar expresiones regulares para hacer coincidir patrones nesteds?

Utilice expat u otro analizador XML; Es más explícito que cualquier otra cosa, teniendo en cuenta que, de todos modos, se trata de datos XML.

Sin embargo, tenga en cuenta que los nombres de elementos XML no pueden comenzar con un número, ya que su ejemplo los tiene.

Aquí hay un analizador que hará lo que necesites, aunque necesitarás modificarlo para combinar elementos duplicados en una sola tecla de dictado:

 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 got some good images <_137_3>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.', 1) print result_dict 

Tome un analizador XML, haga que genere un DOM (Modelo de Objeto de Documento) y luego genere un algoritmo recursivo que atraviese todos los nodos, llama “texto ()” en cada nodo (que debería darle el texto en el nodo actual y todos los hijos) ) y lo pone como clave en el diccionario.

 from cStringIO import StringIO from collections import defaultdict ####from xml.etree import cElementTree as etree from lxml import etree xml = "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. " 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())) 

Salida:

 {'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]} 

Creo que una gramática sería la mejor opción aquí. Encontré un enlace con información: http://www.onlamp.com/pub/a/python/2006/01/26/pyparsing.html

Tenga en cuenta que en realidad no puede resolver esto con una expresión regular, ya que no tienen el poder expresivo para imponer el anidamiento adecuado.

Toma el siguiente mini-lenguaje:

Un cierto número de “(” seguido del mismo número de “)”, sin importar cuál sea el número.

Podría hacer una expresión regular muy fácilmente para representar un súper lenguaje de este mini-lenguaje (donde no hace cumplir la igualdad del número de paréntesis de inicio y paréntesis de final). También puede hacer que una expresión regular sea muy fácil de representar cualquier sublenguaje finito (donde se limita a cierta profundidad máxima de anidación). Pero nunca puedes representar este lenguaje exacto en una expresión regular.

Así que tendrías que usar una gramática, sí.

Aquí hay una solución de regexp recursiva ineficiente poco confiable:

 import re re_tag = re.compile(r'<(?P[^>]+)>(?P.*?)', 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 got some good images <137_3>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. " d = {} for tag, text in iterparse(txt): d.setdefault(strip_tags(text), []).append(int(tag[:-2])) print(d) 

Salida:

 {'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]}