我注意到pyparsing有一种奇怪的副作用:
在解析器的超集上使用.ignore()时,parseString(...,parseAll = True)会停止检查注释符号处的整个字符串。下面的代码更好地解释了。
如何在不使用stringEnd的情况下解决这个问题?
示例:
def test():
import pyparsing as p
unquoted_exclude = "\\\"" + "':/|<>,;#"
unquoted_chars = ''.join(set(p.printables) - set(unquoted_exclude))
unquotedkey = p.Word(unquoted_chars)
more = p.OneOrMore(unquotedkey)
more.ignore("#" + p.restOfLine)
# ^^ "more" should ignore comments, but not "unquotedkey" !!
def parse(parser, input_, parseAll=True):
try:
print input_
print parser.parseString(input_, parseAll).asList()
except Exception as err:
print err
parse(unquotedkey, "abc#d")
parse(unquotedkey, "abc|d")
withstringend = unquotedkey + p.stringEnd
parse(withstringend, "abc#d", False)
parse(withstringend, "abc|d", False)
输出:
abc#d ['abc'] <--- should throw an exception but does not abc|d Expected end of text (at char 3), (line:1, col:4) abc#d Expected stringEnd (at char 3), (line:1, col:4) abc|d Expected stringEnd (at char 3), (line:1, col:4)
答案 0 :(得分:3)
要比较苹果和苹果,您还应在定义withstringend
后添加此行:
withstringend.ignore('#' + p.restOfLine)
我认为您会发现它与使用unquotedKey
解析的测试具有相同的行为。
ignore
的目的是在解析的输入文本中忽略 where 中的构造,而不仅仅是在最顶层。例如,在C程序中,您不必忽略语句之间的注释:
/* add one to x */
x ++;
您还必须忽略可能出现在任何地方的评论:
x /* this is a post-increment
so it really won't add 1 to x until after the
statement executes */ ++
/* and this is the trailing semicolon
for the previous statement -> */;
或者可能有点做作:
for (x = ptr; /* start at ptr */
*x; /* keep going as long as we point to non-zero */
x++ /* add one to x */ )
因此,为了支持这一点,实现了ignore()
来递归整个定义的解析器并更新整个解析器中每个子解析器上的可忽略表达式列表,以便在整个解析器的每个级别都跳过可忽略的表达式解析器。另一种方法是在解析器定义中调用ignore
,并不断尝试追逐那些意外跳过的内容。
所以在你的第一个案例中,当你这样做时:
more = p.OneOrMore(unquotedKey)
more.ignore('#' + p.restOfline)
您还更新了unquotedKey
的无知。如果您要隔离unquotedKey
以使其不会产生此副作用,请使用以下内容定义more
:
more = p.OneOrMore(unquotedKey.copy())
另一点 - 通过将键定义为&#34;除了这些特殊字符&#34;之外的所有内容,您对未引用键的定义。当excludeChars
参数添加到Word类时,您使用的技术在版本1.5.6之前很好。现在你不必乱搞构建只允许字符的列表,你可以让Word完成工作。尝试:
unquotedKey = p.Word(p.printables,
excludeChars = r'\"' + "':/|<>,;#")