Python 将Combine(文字(';@';)+;';spec';)更改为关键字(';@spec';)将删除空白

Python 将Combine(文字(';@';)+;';spec';)更改为关键字(';@spec';)将删除空白,python,pyparsing,Python,Pyparsing,为什么使用Combine(…)保留空格,而关键字(…)删除空格 我需要保留匹配标记后的空格 测试如下: 从pyparsing导入* def解析(字符串,参照模式): 打印refpattern.searchString(字符串) pattern=StringStart()\ +SkipTo(参考模式)(“上一个”)\ +refpattern('ref')\ +SkipTo(StringEnd())(“rest”) 打印模式.parseString(字符串) string=“带@ref to_某物”

为什么使用
Combine(…)
保留空格,而
关键字(…)
删除空格

我需要保留匹配标记后的空格

测试如下:

从pyparsing导入*
def解析(字符串,参照模式):
打印refpattern.searchString(字符串)
pattern=StringStart()\
+SkipTo(参考模式)(“上一个”)\
+refpattern('ref')\
+SkipTo(StringEnd())(“rest”)
打印模式.parseString(字符串)
string=“带@ref to_某物”
标识符=组合(单词(alphas+''''''''''''''''''''''''''''''''''')+可选('.''.+单词(alphas)))
不带空格的模式=(CaselessKeyword('@ref')| CaselessKeyword(r'\ref')).setParseAction(lambda s,l,t:['ref']))\
+白色().suppress()+标识符
模式_with_space=Combine((Literal('@'))| Literal('\\')).suppress()+'ref')+White().suppress()+标识符
解析(字符串、无空格的模式)
解析(字符串、带空格的模式)
将输出:

[['ref', 'to_something']]
['With', 'ref', 'to_something', '']
[['ref', 'to_something']]
['With ', 'ref', 'to_something', '']
#     ^ space i need is preserved here

当对
caselesskyword
使用alternation(
|
操作符)时,会出现问题。参见以下示例:

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', '']