Cómo escribir la gramática para esto en pyparsing: empareja un conjunto de palabras pero no contiene un patrón dado

StackOverflow https://stackoverflow.com/questions/1805309

  •  05-07-2019
  •  | 
  •  

Pregunta

Soy nuevo en Python y pyparsing. Necesito lograr lo siguiente.

Mi línea de muestra de texto es así:

12 items - Ironing Service    11 Mar 2009 to 10 Apr 2009
Washing service (3 Shirt)  23 Mar 2009

Necesito extraer la descripción del artículo, el período

tok_date_in_ddmmmyyyy = Combine(Word(nums,min=1,max=2)+ " " + Word(alphas, exact=3) + " " + Word(nums,exact=4))
tok_period = Combine((tok_date_in_ddmmmyyyy + " to " + tok_date_in_ddmmmyyyy)|tok_date_in_ddmmmyyyy)

tok_desc =  Word(alphanums+"-()") but stop before tok_period

¿Cómo hacer esto?

¿Fue útil?

Solución

Sugeriría que consideres a SkipTo como la clase de reproducción más apropiada, ya que tienes una buena definición del texto no deseado , pero aceptarás casi cualquier cosa antes de eso. Aquí hay un par de maneras de usar SkipTo:

text = """\
12 items - Ironing Service    11 Mar 2009 to 10 Apr 2009
Washing service (3 Shirt)  23 Mar 2009"""

# using tok_period as defined in the OP

# parse each line separately
for tx in text.splitlines():
    print SkipTo(tok_period).parseString(tx)[0]

# or have pyparsing search through the whole input string using searchString
for [[td,_]] in SkipTo(tok_period,include=True).searchString(text):
    print td

Ambos para imprimen lo siguiente:

12 items - Ironing Service    
Washing service (3 Shirt) 

Otros consejos

M K Saravanan, este problema de análisis en particular no es tan difícil de hacer con un buen 'ole re:

import re
import string

text='''
12 items - Ironing Service    11 Mar 2009 to 10 Apr 2009
Washing service (3 Shirt)  23 Mar 2009
This line does not match
'''

date_pat=re.compile(
    r'(\d{1,2}\s+[a-zA-Z]{3}\s+\d{4}(?:\s+to\s+\d{1,2}\s+[a-zA-Z]{3}\s+\d{4})?)')
for line in text.splitlines():
    if line:
        try:
            description,period=map(string.strip,date_pat.split(line)[:2])
            print((description,period))
        except ValueError:
            # The line does not match
            pass

rendimientos

# ('12 items - Ironing Service', '11 Mar 2009 to 10 Apr 2009')
# ('Washing service (3 Shirt)', '23 Mar 2009')

El principal caballo de batalla aquí es, por supuesto, el patrón re. Vamos a separarlo:

\ d {1,2} \ s + [a-zA-Z] {3} \ s + \ d {4} es la expresión regular para una fecha, el equivalente de tok_date_in_ddmmmyyyy . \ d {1,2} coincide con uno o dos dígitos, \ s + coincide con uno o más espacios en blanco, [a-zA-Z] {3} coincide con 3 letras, etc.

(?: \ s + to \ s + \ d {1,2} \ s + [a-zA-Z] {3} \ s + \ d {4})? es una expresión regular Rodeado por (?: ...) . Esto indica una expresión regular no agrupada. Usando esto, no se asigna ningún grupo (por ejemplo, match.group (2)) a esta expresión regular. Esto es importante porque date_pat.split () devuelve una lista con cada grupo como miembro de la lista. Al suprimir la agrupación, mantenemos todo el período 11 marzo 2009 a 10 abril 2009 juntos. El signo de interrogación al final indica que este patrón puede ocurrir cero o una vez. Esto permite que la expresión regular coincida con ambas 23 de marzo de 2009 y 11 de marzo de 2009 al 10 de abril de 2009 .

text.splitlines () divide el texto en \ n .

date_pat.split ('12 artículos - Servicio de planchado del 11 de marzo de 2009 al 10 de abril de 2009 ')

divide la cadena en la regexp date_pat. La coincidencia se incluye en la lista devuelta. Así obtenemos:

['12 items - Ironing Service ', '11 Mar 2009 to 10 Apr 2009', '']

map (string.strip, date_pat.split (line) [: 2]) simula el resultado.

Si line no coincide con date_pat , date_pat.split (line) devuelve [line,] , tan

description,period=map(string.strip,date_pat.split(line)[:2?)

genera un ValueError porque no podemos desempaquetar una lista con solo un elemento en un 2-tuple. Capturamos esta excepción pero simplemente pasamos a la siguiente línea.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top