Seite 1 von 1

pyparsing und Whitespace

Verfasst: Dienstag 2. September 2008, 02:52
von Leonidas
Hi,

Ich komme gerade nicht drauf - ich würde gerne Leerzeilen als Tokens haben, d.h. \n\n wäre eine Leerzeile, \n\n\n wären zwei etc. Aber irgendwie verschluckt trotz meines umstellen der Whitespacechars pyparsing \n dennoch generell. Das erste Problem wäre Pyparsing sagen, dass es \n\n matchen soll.

Code: Alles auswählen

from pyparsing import Word, Literal, Optional, Group, OneOrMore, nums

watchseries = Word(nums, exact=4)
watchrev = Word(nums, exact=1)

watchname = Group(watchseries + Optional('M') + '-' + watchrev)

leaveempty = Literal('EMPTY')
pagebreak = Literal('\n\n')
pagebreak.setWhitespaceChars(' \t\r')

all = OneOrMore(watchname ^ leaveempty ^ pagebreak)
all.setWhitespaceChars(' \t\r')

t1 = "2134M-2"
t2 = """3245-3
3456M-5"""
t3 = """3256-4

 4563-4"""
t4 = """4562M-6
 EMPTY
3246-5"""

print all.parseString(t3)
Wie man sieht habe ich hier einige kleine Testcases.

In Zukunft würde ich gerne aus \n+x*\n gerne x NEWLINE-Tokens haben, aber ich weiß gar nicht, ob so etwas überhaupt mit Pyparsing abbildbar ist. Ggf. werde ich wohl den Output durchfiltern und einzeln stehende NEWLINES löschen und NEWLINE-Gruppen einfach um ein Newline kürzen, das sollte wohl auch zum Ziel führen. Oder gibt es einen besseren Weg?

Nur eben wie kann man denn Pyparsing sagen, dass es Linebreaks nicht verschlucken soll?

Verfasst: Dienstag 2. September 2008, 16:03
von Leonidas
Hmm, bin jetzt etwas weitergekommen, aber so richtig toll funktioniert das noch nicht:

Code: Alles auswählen

from pyparsing import (Word, Literal, Optional, Group, OneOrMore, Regex,
        Combine, ParserElement, nums)

ParserElement.setDefaultWhitespaceChars(' \t\r')

watchseries = Word(nums, exact=4)
watchrev = Word(nums, exact=1)

watchname = Combine(watchseries + Optional('M') + '-' + watchrev)

leaveempty = Literal('EMPTY').setParseAction(
    lambda s, loc, tokens: ['<EMPTY>'])

def breaks(s, loc, tokens):
    tokens[0].pop()
    return ['<PAGEBREAK>' for token in tokens[0]]

pagebreak = Group(Literal('\n') + OneOrMore(Literal('\n'))).setParseAction(breaks)

all = OneOrMore(watchname ^ leaveempty ^ pagebreak)

tests = [
    "2134M-2",
    """3245-3
    3456M-5""",
    """3256-4

    4563-4""",
    """4562M-6
     EMPTY
    3246-5"""
]

for test in tests:
    print all.parseString(test)
Jetzt tut <EMPTY> nicht mehr, und die Leerzeilen funktionieren auch noch nicht so ganz wie ich das wollte.

Verfasst: Dienstag 2. September 2008, 16:21
von BlackJack
Hast Du schon in der englischsprachingen Python-Newsgroup gefragt? Der `pyparsing`-Autor liest da mit und beantwortet Fragen zum Modul in der Regel.

Verfasst: Dienstag 2. September 2008, 16:28
von Leonidas
BlackJack hat geschrieben:Hast Du schon in der englischsprachingen Python-Newsgroup gefragt?
Nein, noch nicht - werde ich wohl gleich nachholen.

Soweit bin ich gekommen (\n\n ist eine selten dämliche Idee, ich suche eigentlich Linestart, optionales Whitespace und Lineend aber das will irgendwie dennoch nicht).

Code: Alles auswählen

from pyparsing import (Word, Literal, Optional, Group, OneOrMore, Regex,
        Combine, ParserElement, nums, LineStart, LineEnd, White)

watchseries = Word(nums, exact=4)
watchrev = Word(nums, exact=1)

watchname = Combine(watchseries + Optional('M') + '-' + watchrev)

leaveempty = Literal('EMPTY')

def breaks(s, loc, tokens):
    print repr(tokens[0])
    #return ['<PAGEBREAK>' for token in tokens[0]]
    return ['<PAGEBREAK>']

#pagebreak = Regex('^\s*$').setParseAction(breaks)
pagebreak = LineStart() + Optional(White()) + LineEnd().setParseAction(breaks)

all = OneOrMore(watchname ^ leaveempty ^ pagebreak)

tests = [
    "2134M-2",
    """3245-3
    3456M-5""",
    """3256-4

    4563-4""",
    """4562M-6
     EMPTY
    3246-5"""
]

for test in tests:
    print all.parseString(test)