使用 pyparsing 的自定义分隔符

Custom Delimiter using pyparsing

我正在尝试为一些文本编写解析器。我究竟做错了什么? 考虑以下 pyparsing 代码

from pyparsing import CaselessLiteral,StringEnd,Suppress,alphanums,alphas,alphas,
Word,ParseException,ParseResults,nums,Group,ZeroOrMore,ParseElement,restOfline,Combine,Optional,Literal,LineEnd
ParseElement.enablePackrat()
import lxml.etree

#define common syntax
delimiter=Supress("->")|Suppress(">")
line_ending=";"
cust_seperator="_"
cust_code=Word(alphanums)
description=Word(alphanums+"~#!@£$%^&*()'-+/{}[]=. ")
limit_state=CaselessLiteral("REACHED")|CaselessLiteral("NOT_REACHED")|CaselessLiteral("RETIRED")


#define grammar for user comment
StringStart=CaselessLiteral("COMMENT")
comment_text=Word(alphanums+"#!@£$%^&*()<>'/{}[]=. ")
usercomment_syntax=(StringStart+delimiter+comment_text+line_ending).setResultsNmae('user_comment')

#define grammar for upperlimit
StringStart=CaselessLiteral("CUSTOMER_LIMIT_REACHED")
cust_code_prefix=Word(alphanums,max=6)
customer_identifier=Combine(cust_code_prefix+Optional(cust_seperator)+cust_code+Optional(description))
customerupperlimit=(StringStart+delimiter+customer_identifier+delimiter+limit_state+line_ending).setResultsNmae('customer_upper_limit')

所以考虑以下

COMMENT->Welcome to bank one;

这通过了,令牌是 ['COMMENT','Welcome to bank one',';']

CUSTOMER_LIMIT_REACHED->1234_A0001 [Harry mop]->NOT_REACHED;

这通过了,令牌是

['CUSTOMER_LIMIT_REACHED','1234_A0001 [Harry mop]','NOT_REACHED',';']

但是当 > 在 "wrong" 位置时会发生什么?

CUSTOMER_LIMIT_REACHED->1234_A0001 [Sally >12 top]->NOT_REACHED;

这对我来说似乎不起作用,描述中出现 > 会导致错误。所以像这样重新定义描述

description=Word(alphanums+"~#!@£$%^&*()'-+/{}[]=.> ")

应该可以,但它会破坏注释语法。 我只想让定界符->被视为一个

想想我不觉得

delimiter=Suppress("->")| Suppress(">") 

肯定是对的我只需要

delimiter=Suppress("->")

谢谢,@Paul。我试过你的建议。

description = Combine(OneOrMore(Word(alphanums+"~#!@£$%^&*()'+/{}[]=. >") + ('-' + ~FollowedBy('>'))))

我不知道我是不是打错了,但打破连字符有点棘手

CUSTOMER_LIMIT_REACHED->1234_A0001 [Harry-mop]->NOT_REACHED;

现在失败了,如果我是对的我相信

  • ('-' + ~FollowedBy('>') will expect a hyphen (-) to appear after the word, as in it MUST, so

    CUSTOMER_LIMIT_REACHED->1234_A0001 [Harry-mop]->NOT_REACHED; failed but CUSTOMER_LIMIT_REACHED->1234_A0001 [Harry-mop]-->NOT_REACHED; passes.

经过一些实验后,我将答案稍微调整为

description = Combine(OneOrMore(Word(alphanums+"~#!@£$%^&*()'+/{}[]=. >") + Optional('-' + ~FollowedBy('>'))))

谢谢你让我走上了正确的道路

是的,问题出在

description=Word(alphanums+"~#!@£$%^&*()'-+/{}[]=. ")

如果您将“>”添加到 description 中的这组允许的字符,pyparsing 将无法区分描述中的“->”与描述中的“->”是分隔符(因为“-”和“>”都包含在允许的字符集中)。

您将需要实施否定前瞻,以便“-”或“>”单独成为可接受的描述内容。然而,在 Word 的令牌构建中,没有办法做到这一点。您需要将“-”(作为“->”中的主导字符)单独分开。

description = (OneOrMore(Word(alphanums+"~#!@£$%^&*()'+/{}[]=. >") + 
                  ('-' + ~FollowedBy('>'))))

将整个内容包装在一个 Combine 中,这样 pyparsing 就不会为这个描述的各个位提供单独的字符串:

description = Combine(OneOrMore(Word(alphanums+"~#!@£$%^&*()'+/{}[]=. >") + 
                  ('-' + ~FollowedBy('>'))))

此时,delimiter = Suppress('->')应该足够了。