Como escrever a gramática para isso em pyparsing: combinar um conjunto de palavras mas não contém um determinado padrão

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

  •  05-07-2019
  •  | 
  •  

Pergunta

Eu sou novo para Python e pyparsing. Eu preciso para realizar o seguinte.

A minha linha de amostra do texto é assim:

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

Eu preciso extrair a descrição do item, 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

Como fazer isso?

Foi útil?

Solução

Eu sugeriria olhar skipTo como a classe pyparsing que é mais apropriado, uma vez que você tem uma definição bem da indesejado texto, mas vai aceitar praticamente qualquer coisa antes disso. Aqui estão algumas maneiras 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 os laços for imprimir o seguinte:

12 items - Ironing Service    
Washing service (3 Shirt) 

Outras dicas

M K Saravanan, este problema de análise em particular não é tão difícil de fazer com um bom 're ole:

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

rendimentos

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

A principal cavalo de batalha aqui é, naturalmente, o padrão de re. Vamos dividi-la em pedaços:

\d{1,2}\s+[a-zA-Z]{3}\s+\d{4} é a expressão regular para uma data, o equivalente a tok_date_in_ddmmmyyyy. \d{1,2} corresponde a um ou dois dígitos, \s+ corresponde a um ou mais espaços em branco, [a-zA-Z]{3} corresponde 3 letras, etc.

(?:\s+to\s+\d{1,2}\s+[a-zA-Z]{3}\s+\d{4})? é um regexp cercado por (?:...). Isto indica uma expressão regular não-agrupamento. Usando este, nenhum grupo (por exemplo match.group (2)) é atribuída a esta expressão regular. Isto é importante porque date_pat.split () retorna uma lista com cada grupo sendo um membro da lista. Ao suprimir o agrupamento, mantemos todo o conjunto período 11 Mar 2009 to 10 Apr 2009. O ponto de interrogação no final indica que este padrão pode ocorrer zero ou uma vez. Isso permite que o regexp para corresponder tanto 23 Mar 2009 e 11 Mar 2009 to 10 Apr 2009.

texto text.splitlines() splits em \n.

date_pat.split('12 items - Ironing Service 11 Mar 2009 to 10 Apr 2009')

divide a corda no regexp date_pat. A partida está incluído na lista retornada. Assim temos:

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

map(string.strip,date_pat.split(line)[:2]) prettifies o resultado.

Se line não corresponde date_pat, em seguida, retorna date_pat.split(line) [line,], assim

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

levanta uma ValueError porque não pode descompactar uma lista com apenas um elemento em um 2-tupla. Nós pegar essa exceção, mas simplesmente passar para a próxima linha.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top