Python 在nestedExpr中保留换行符
Python 在nestedExpr中保留换行符,python,newline,pyparsing,Python,Newline,Pyparsing,nestedExpr是否可以保留换行符 下面是一个简单的例子: import pyparsing as pp # Parse expressions like: \name{body} name = pp.Word( pp.alphas ) body = pp.nestedExpr( '{', '}' ) expr = '\\' + name('name') + body('body') # Example text to parse txt = ''' This \works{fine},
nestedExpr
是否可以保留换行符
下面是一个简单的例子:
import pyparsing as pp
# Parse expressions like: \name{body}
name = pp.Word( pp.alphas )
body = pp.nestedExpr( '{', '}' )
expr = '\\' + name('name') + body('body')
# Example text to parse
txt = '''
This \works{fine}, but \it{
does not
preserve newlines
}
'''
# Show results
for e in expr.searchString(txt):
print 'name: ' + e.name
print 'body: ' + str(e.body) + '\n'
输出:
name: works
body: [['fine']]
name: it
body: [['does', 'not', 'preserve', 'newlines']]
如您所见,第二个表达式(\it{…
)的主体被解析,尽管主体中有换行符,但我希望结果将每一行存储在单独的子数组中。这一结果使得无法区分单行与多行的主体内容。此扩展(基于nestedExpr
version 2.1.10的代码)的行为更接近于我所期望的“嵌套表达式”返回:
import string
from pyparsing import *
defaultWhitechars = string.whitespace
ParserElement.setDefaultWhitespaceChars(defaultWhitechars)
def fencedExpr( opener="(", closer=")", content=None, ignoreExpr=None, stripchars=defaultWhitechars ):
if content is None:
if isinstance(opener,basestring) and isinstance(closer,basestring):
if len(opener) == 1 and len(closer)==1:
if ignoreExpr is not None:
content = Combine(OneOrMore( ~ignoreExpr + CharsNotIn(opener+closer,exact=1)))
else:
content = empty.copy() + CharsNotIn(opener+closer)
else:
if ignoreExpr is not None:
content = OneOrMore( ~ignoreExpr + ~Literal(opener) + ~Literal(closer))
else:
content = OneOrMore( ~Literal(opener) + ~Literal(closer) )
else:
raise ValueError("opening and closing arguments must be strings if no content expression is given")
if stripchars is not None:
content.setParseAction(lambda t:t[0].strip(stripchars))
ret = Forward()
if ignoreExpr is not None:
ret <<= Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) )
else:
ret <<= Group( Suppress(opener) + ZeroOrMore( ret | content ) + Suppress(closer) )
ret.setName('nested %s%s expression' % (opener,closer))
return ret
导入字符串
从pyparsing导入*
defaultWhitechars=string.whitespace
setDefaultWhitespaceChars(defaultWhitechars)
def fencedExpr(opener=“(”,closer=“)”,content=None,ignoreExpr=None,stripchars=defaultWhitechars):
如果内容为无:
如果isinstance(开始,基串)和isinstance(结束,基串):
如果len(开启器)==1且len(关闭器)==1:
如果ignoreExpr不是无:
content=Combine(一个或多个(~ignorexpr+CharsNotIn(开瓶器+闭合器,精确值=1)))
其他:
content=empty.copy()+CharsNotIn(打开器+关闭器)
其他:
如果ignoreExpr不是无:
内容=一个或多个(~ignoreExpr+~Literal(开始者)+~Literal(结束者))
其他:
内容=一个或多个(~Literal(开始者)+~Literal(结束者))
其他:
raise VALUERROR(“如果未提供内容表达式,则开始参数和结束参数必须为字符串”)
如果stripchars不是None:
content.setParseAction(lambda t:t[0].strip(stripchars))
ret=前进()
如果ignoreExpr不是无:
ret我直到几分钟前才看到你的答案,我已经想出了这个方法:
body = pp.nestedExpr( '{', '}', content = (pp.LineEnd() | name.setWhitespaceChars(' ')))
将body
更改为此定义将得到以下结果:
name: works
body: [['fine']]
name: it
body: [['\n', 'does', 'not', '\n', 'preserve', 'newlines', '\n']]
编辑:
等等,如果您想要的是单独的行,那么这可能更符合您的要求:
single_line = pp.OneOrMore(name.setWhitespaceChars(' ')).setParseAction(' '.join)
multi_line = pp.OneOrMore(pp.Optional(single_line) + pp.LineEnd().suppress())
body = pp.nestedExpr( '{', '}', content = multi_line | single_line )
其中:
name: works
body: [['fine']]
name: it
body: [['does not', 'preserve newlines']]
感谢您为编写一些可用的补丁代码所做的努力-我通常会收到关于我应该对pyparsing进行更改的建议,但很少得到具体的代码补丁/实现。我认为您对nestedExpr
的解释与我的略有不同,我试图通过支持content
参数,默认值为0个或多个空格分隔的单词。我可能需要删除该auto-strip()如果给定了content
表达式,则解析操作,并让调用方在给定的arg上设置必要的strip或join或任何解析操作。我不认为这比来自包作者本人的答案更好!:)如果我的建议有点笨拙,很抱歉,但我可以在这一条中提问;为什么在主体
的定义中使用名称
?我承认我的问题并不完全清楚,但我真正想要的是括号之间的原始内容,理想情况下不受任何解析规则或标记器的影响,因此我可以单独解析它们稍后(可能会使用不同的解析规则,具体取决于父对象的内容)。要匹配任何内容,您可能会使用类似pp.Word(pp.printables,excludeChars=“{}”)的内容来代替name
。您可能还需要使用pp.originalTextFor
进行包装才能获得原始字符串内容。欢迎使用pyparsing!