为什么使用Combine(...)
保留空白,而使用Keyword(...)
删除空白?
我需要在匹配的令牌后保留空白。
测试如下:
from pyparsing import *
def parse(string, refpattern):
print refpattern.searchString(string)
pattern = StringStart() \
+ SkipTo(refpattern)('previous') \
+ refpattern('ref') \
+ SkipTo(StringEnd())('rest')
print pattern.parseString(string)
string = "With @ref to_something"
identifier = Combine(Word(alphas + '_', alphanums + '_') + Optional('.' + Word(alphas)))
pattern_without_space = (CaselessKeyword('@ref') | CaselessKeyword(r'\ref')).setParseAction(lambda s, l, t: ['ref']) \
+ White().suppress() + identifier
pattern_with_space = Combine((Literal('@') | Literal('\\')).suppress() + 'ref') + White().suppress() + identifier
parse(string, pattern_without_space)
parse(string, pattern_with_space)
将输出:
[['ref', 'to_something']]
['With', 'ref', 'to_something', '']
[['ref', 'to_something']]
['With ', 'ref', 'to_something', '']
# ^ space i need is preserved here
最佳答案
与|
交替使用(CaselessKeyword
运算符)时,会发生此问题。请参阅以下示例:
from pyparsing import *
theString = 'This is @Foo Bar'
identifier = Combine(Word(alphas + '_', alphanums + '_') + Optional('.' + Word(alphas)))
def testParser(p):
q = StringStart() + SkipTo(p)("previous") + p("body") + SkipTo(StringEnd())("rest")
return q.parseString(theString)
def test7():
p0 = (CaselessKeyword('@Foo') | Literal('@qwe')) + White().suppress() + identifier
p1 = (CaselessKeyword('@Foo') | CaselessKeyword('@qwe')) + White().suppress() + identifier
p2 = (Literal('@qwe') | CaselessKeyword('@Foo')) + White().suppress() + identifier
p3 = (CaselessKeyword('@Foo')) + White().suppress() + identifier
p4 = Combine((Literal('@') | Literal('\\')).suppress() + 'Foo') + White().suppress() + identifier
print "p0:", testParser(p0)
print "p1:", testParser(p1)
print "p2:", testParser(p2)
print "p3:", testParser(p3)
print "p4:", testParser(p4)
test7()
输出为:
p0: ['This is', '@Foo', 'Bar', '']
p1: ['This is', '@Foo', 'Bar', '']
p2: ['This is', '@Foo', 'Bar', '']
p3: ['This is ', '@Foo', 'Bar', '']
p4: ['This is ', 'Foo', 'Bar', '']
也许这是一个错误?
更新:这是您可以定义自己的解析器以匹配
@Foo
或\Foo
作为关键字的方式:from pyparsing import *
import string
class FooKeyWord(Token):
alphas = string.ascii_lowercase + string.ascii_uppercase
nums = "0123456789"
alphanums = alphas + nums
def __init__(self):
super(FooKeyWord,self).__init__()
self.identChars = alphanums+"_$"
self.name = "@Foo"
def parseImpl(self, instring, loc, doActions = True):
if (instring[loc] in ['@', '\\'] and
instring.startswith('Foo', loc+1) and
(loc+4 >= len(instring) or instring[loc+4] not in self.identChars) and
(loc == 0 or instring[loc-1].upper() not in self.identChars)):
return loc+4, instring[loc] + 'Foo'
raise ParseException(instring, loc, self.errmsg, self)
def test8():
p = FooKeyWord() + White().suppress() + identifier
q = StringStart() + SkipTo(p)("previous") + p("body") + SkipTo(StringEnd())("rest")
print "with @Foo:", q.parseString("This is @Foo Bar")
print "with \\Foo:", q.parseString("This is \\Foo Bar")
并输出:
with @Foo: ['This is ', '@Foo', 'Bar', '']
with \Foo: ['This is ', '\\Foo', 'Bar', '']