Come scrivere la grammatica per questo in pyparsing: abbina un insieme di parole ma non contiene un dato schema

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

  •  05-07-2019
  •  | 
  •  

Domanda

Sono nuovo di Python e pyparsing. Devo realizzare quanto segue.

La mia riga di testo di esempio è così:

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

Devo estrarre la descrizione dell'oggetto, punto

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

Come farlo?

È stato utile?

Soluzione

Suggerirei di considerare SkipTo come la classe di pyparsing più appropriata, dato che hai una buona definizione del testo indesiderato , ma accetterò praticamente qualsiasi cosa prima. Ecco un paio di modi per usare 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

Entrambi i cicli per stampano quanto segue:

12 items - Ironing Service    
Washing service (3 Shirt) 

Altri suggerimenti

M K Saravanan, questo particolare problema di analisi non è così difficile da fare con un buon '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

rendimenti

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

Il cavallo di battaglia principale qui è ovviamente il modello di riferimento. Dividiamolo:

\ d {1,2} \ s + [a-zA-Z] {3} \ s + \ d {4} è la regexp per una data, l'equivalente di tok_date_in_ddmmmyyyy . \ d {1,2} corrisponde a una o due cifre, \ s + corrisponde a uno o più spazi bianchi, [a-zA-Z] {3} corrisponde a 3 lettere, ecc.

(?: \ s + to \ s + \ d {1,2} \ s + [a-zA-Z] {3} \ s + \ d {4})? è una regexp circondato da (?: ...) . Ciò indica una regexp non raggruppante. Usando questo, nessun gruppo (ad esempio match.group (2)) è assegnato a questo regexp. Ciò è importante perché date_pat.split () restituisce un elenco con ciascun gruppo come membro dell'elenco. Sopprimendo il raggruppamento, teniamo insieme l'intero periodo dall'11 marzo 2009 al 10 aprile 2009 . Il punto interrogativo alla fine indica che questo schema può verificarsi zero o una volta. Ciò consente a regexp di abbinare entrambi 23 mar 2009 e dall'11 mar 2009 al 10 aprile 2009 .

text.splitlines () divide il testo su \ n .

date_pat.split ('12 articoli - Servizio stiratura dall'11 marzo 2009 al 10 aprile 2009 ')

divide la stringa nel regexp date_pat. La partita è inclusa nell'elenco restituito. Quindi otteniamo:

['12 articoli - Servizio stireria ', '11 marzo 2009-10 aprile 2009', '']

map (string.strip, date_pat.split (line) [: 2]) imposta il risultato in modo predefinito.

Se line non corrisponde a date_pat , date_pat.split (line) restituisce [line,] , così

descrizione, periodo = map (string.strip, date_pat.split (linea) [: 2])

genera un ValueError perché non è possibile decomprimere un elenco con un solo elemento in una 2-tupla. Prendiamo questa eccezione ma passiamo semplicemente alla riga successiva.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top