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!