此代码有效:
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”解析为“zipcode”,但如何使用pyparsing确定?我没有为其内容解析字符串,只是确定它是什么类型的查询。
答案 0 :(得分:3)
你可以单独使用zipcode和foo,这样你就知道字符串匹配哪一个。
zipresults = zipcode.parseString( t )
fooresults = foo.parseString( t )
答案 1 :(得分:2)
我没有pyparsing
模块,但Regex
必须是类,而不是函数。
您可以做的是从中进行子类化并根据需要覆盖方法来自定义行为,然后使用您的子类。
答案 2 :(得分:2)
你的第二个问题很简单,所以我先回答一下。更改查询以将结果名称分配给不同的表达式:
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和zipcode表达式来在解析时执行此操作:
# 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提供了比Regex更多的解析类(例如Word,Keyword,Literal,CaselessLiteral),并且通过将它们与'+','|','^','〜','@'组合来组成解析器。 '*'运营商。例如,如果您想解析美国社会安全号码,但不使用正则表达式,则可以使用:
ssn = Combine(Word(nums,exact=3) + '-' +
Word(nums,exact=2) + '-' + Word(nums,exact=4))
Word匹配构造函数中由给定字符组成的连续“单词”,Combine将匹配的标记连接成一个标记。
如果你想解析这些数字的潜在列表,用'/'分隔,请使用:
delimitedList(ssn, '/')
或者如果有1到3个这样的数字,没有分隔符,请使用:
ssn * (1,3)
任何表达式都可以附加结果名称或解析操作,以进一步丰富解析后的结果或解析过程中的功能。您甚至可以使用Forward类构建递归解析器,例如括号的嵌套列表,算术表达式等。
我写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']
(注意遗漏单尾'?')