pyparsing问题
-
19-09-2019 - |
题
此代码的工作:
from pyparsing import *
zipRE = "\d{5}(?:[-\s]\d{4})?"
fooRE = "^\!\s+.*"
zipcode = Regex( zipRE )
foo = Regex( fooRE )
query = ( zipcode | foo )
tests = [ "80517", "C6H5OH", "90001-3234", "! sfs" ]
for t in tests:
try:
results = query.parseString( t )
print t,"->", results
except ParseException, pe:
print pe
我卡在两个问题:
1 - 如何使用自定义函数来解析的令牌。举例来说,如果我想用一些自定义的逻辑,而不是一个正则表达式,以确定是否一个数是邮编。 代替:
zipcode = Regex( zipRE )
也许:
zipcode = MyFunc()
2 - 如何确定哪些解析字符串TO。 “80001”解析为“邮政编码”但我要如何确定这个使用pyparsing?我不解析其内容的字符串,而只是以确定它是什么样的查询。
解决方案
您的第二个问题是容易的,所以我会回答,第一。改变查询分配结果的名称不同的表达式:
query = ( zipcode("zip") | foo("foo") )
现在可以在返回的结果调用的getName():
print t,"->", results, results.getName()
,并提供:
80517 -> ['80517'] zip
Expected Re:('\\d{5}(?:[-\\s]\\d{4})?') (at char 0), (line:1, col:1)
90001-3234 -> ['90001-3234'] zip
! sfs -> ['! sfs'] foo
如果您要使用结果的fooness或zipness调用另一个函数,那么你可以在分析时通过附加解析动作的foo和邮政编码表达式做到这一点:
# enclose zipcodes in '*'s, foos in '#'s
zipcode.setParseAction(lambda t: '*' + t[0] + '*')
foo.setParseAction(lambda t: '#' + t[0] + '#')
query = ( zipcode("zip") | foo("foo") )
现在给出:
80517 -> ['*80517*'] zip
Expected Re:('\\d{5}(?:[-\\s]\\d{4})?') (at char 0), (line:1, col:1)
90001-3234 -> ['*90001-3234*'] zip
! sfs -> ['#! sfs#'] foo
有关你的第一个问题,我完全不知道你在说什么样的功能。 Pyparsing提供更多的解析类的不仅仅是正则表达式(如Word,关键字,文字,CaselessLiteral),你通过与“+”,结合撰写解析器“|”,“^”,“〜”,“@”和'*' 运算符。举例来说,如果你想解析了美国的社会安全号码,但不能使用正则表达式,你可以使用:
ssn = Combine(Word(nums,exact=3) + '-' +
Word(nums,exact=2) + '-' + Word(nums,exact=4))
Word为由在其构造给定字符的连续“字”相匹配,联合地连接了匹配令牌到单个令牌。
如果你想解析此类数量的潜在名单,由“/的分隔,使用:
delimitedList(ssn, '/')
或者如果有1个3这样的数字之间,没有delimters,使用:
ssn * (1,3)
和任何表达式可以具有结果的名称或解析附连到他们的动作,在分析过程中进一步丰富了解析的结果,或功能。甚至可以建立递归解析器,如使用正向类括号的嵌套的列表,算术表达式等。
我时写pyparsing意图是从基本构建块解析器该组合物将是创建解析器的主要形式。它只是在我添加正则表达式为(我虽然是)最终逃脱阀以后的版本 - 如果人们不能建立自己的解析器,他们可以依傍的正则表达式的格式,这无疑证明了它的力量随着时间的推移。
或者,就像一个其他的海报建议,您可以打开pyparsing源,和子类的现有类的一个,或写自己的,以下的结构。下面是将匹配用于配对字符的类:
class PairOf(Token):
"""Token for matching words composed of a pair
of characters in a given set.
"""
def __init__( self, chars ):
super(PairOf,self).__init__()
self.pair_chars = set(chars)
def parseImpl( self, instring, loc, doActions=True ):
if (loc < len(instring)-1 and
instring[loc] in self.pair_chars and
instring[loc+1] == instring[loc]):
return loc+2, instring[loc:loc+2]
else:
raise ParseException(instring, loc, "Not at a pair of characters")
这样:
punc = r"~!@#$%^&*_-+=|\?/"
parser = OneOrMore(Word(alphas) | PairOf(punc))
print parser.parseString("Does ** this match @@@@ %% the parser?")
给出:
['Does', '**', 'this', 'match', '@@', '@@', '%%', 'the', 'parser']
(注意的省略的后单 '?')
其他提示
您可以单独使用邮政编码和Foo,让你知道字符串匹配其中之一。
zipresults = zipcode.parseString( t )
fooresults = foo.parseString( t )
我没有pyparsing
模块,但Regex
必须是类,不是一个函数。
你能做的是从它和重写方法的子类根据需要定制行为,然后用你的子类来代替。