Wie die Grammatik für diese in pyparsing schreiben: eine Reihe von Wörtern entsprechen, aber nicht auf ein bestimmtes Muster enthält,
Frage
Ich bin neu in Python und pyparsing. Ich brauche die folgenden zu erreichen.
Meine Probe Textzeile ist wie folgt:
12 items - Ironing Service 11 Mar 2009 to 10 Apr 2009
Washing service (3 Shirt) 23 Mar 2009
Ich brauche die Artikelbeschreibung zu extrahieren, Periode
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
Wie dies zu tun?
Lösung
Ich würde vorschlagen, bei skipto als pyparsing Klasse suchen, der am besten geeignet ist, da man eine gute Definition des unerwünschten Textes hat, aber so ziemlich alles, bevor das akzeptieren. Hier sind ein paar Möglichkeiten, skipto zu verwenden:
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
Beide for
Schleifen drucken wie folgt vor:
12 items - Ironing Service
Washing service (3 Shirt)
Andere Tipps
M K Saravanan, dieses besondere Parsing Problem ist nicht so schwer, mit gutem ‚ole re zu tun:
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
Ausbeuten
# ('12 items - Ironing Service', '11 Mar 2009 to 10 Apr 2009')
# ('Washing service (3 Shirt)', '23 Mar 2009')
Das Haupt Arbeitspferd hier ist natürlich das Wieder Muster. Lassen Sie uns brechen sie auseinander:
\d{1,2}\s+[a-zA-Z]{3}\s+\d{4}
ist die regexp für ein Datum, das Äquivalent von tok_date_in_ddmmmyyyy
. \d{1,2}
für eine oder zwei Ziffern, \s+
für ein oder mehr Leerzeichen, Streichhölzer [a-zA-Z]{3}
3 Buchstaben, etc.
(?:\s+to\s+\d{1,2}\s+[a-zA-Z]{3}\s+\d{4})?
ist ein regulärer Ausdruck von (?:...)
umgeben.
Dies deutet auf eine nicht-Gruppierung regexp. Unter Verwendung dieser, keine Gruppe (z.B. match.group (2)) ist diesem regexp zugeordnet. Dies ist wichtig, weil date_pat.split () gibt eine Liste mit jeder Gruppe ein Mitglied der Liste ist. Durch die Gruppierung unterdrücken, halten wir den gesamten Zeitraum 11 Mar 2009 to 10 Apr 2009
zusammen. Das Fragezeichen am Ende gibt an, dass dieses Muster null oder einmal auftreten kann. Dies ermöglicht es dem regexp beide übereinstimmen
23 Mar 2009
und 11 Mar 2009 to 10 Apr 2009
.
text.splitlines()
teilt Text auf \n
.
date_pat.split('12 items - Ironing Service 11 Mar 2009 to 10 Apr 2009')
teilt den String auf der date_pat regexp. Das Spiel wird in der zurückgegebenen Liste enthalten. So erhalten wir:
['12 items - Ironing Service ', '11 Mar 2009 to 10 Apr 2009', '']
map(string.strip,date_pat.split(line)[:2])
verschönert das Ergebnis.
Wenn line
nicht date_pat
überein, date_pat.split(line)
dann kehrt [line,]
,
so
description,period=map(string.strip,date_pat.split(line)[:2])
wirft ein Valueerror, weil wir mit einer Liste nur ein Element in ein 2-Tupel nicht entpacken kann. Wir fangen diese Ausnahme aber einfach in der nächsten Zeile weitergeben.