PyParsing:使用反斜杠的shell样式空间转义

时间:2015-04-18 04:10:16

标签: python escaping backslash pyparsing

我需要以

的形式解析以空格分隔的键值对的文本
<key>=<value> <key>=<value> ... 

这是非常直接的pyparsing ..除非值中可以有空格 例如

dog=blue cat="orange tangerine" mouse=a\ small\ grey\ mouse

最后一对的pyparsing语法会是什么样子 pyparsing在空间上贪婪.. 线条跨越文本可能看起来像

,这进一步复杂化了
dog=blue cat="orange tangerine" mouse=a\ small\ grey\ mouse \
   lion=nonexistent

我在http://pyparsing.wikispaces.com/share/view/7002417处查看了一些示例 和Python/Pyparsing - Multiline quotes有助于多行文本,但不支持反斜杠转义空间

1 个答案:

答案 0 :(得分:2)

假设您的输入字符串位于名为“input.py”的文件中,以下内容适用于您的示例:

import pyparsing
from pyparsing import ZeroOrMore, Group


OP_EQ   = pyparsing.Literal('=').suppress()
DQUOTE  = pyparsing.Literal('"').suppress()
ESPACE  = pyparsing.Literal('\\ ').suppress().leaveWhitespace()
BSLASH  = pyparsing.Literal('\\')

S       = pyparsing.Word(" \t\r\n").suppress().leaveWhitespace()

DELIM   = ZeroOrMore(S ^ BSLASH).suppress()

KEY     = pyparsing.Word(pyparsing.alphanums)("KEY")

VALTOK  = pyparsing.Word(pyparsing.printables, excludeChars='="\\')

QVALUE  = ( DQUOTE +
            Group(VALTOK + ZeroOrMore(S + VALTOK)) +
            DQUOTE
            )
NQVALUE = Group(VALTOK + ZeroOrMore(ESPACE + VALTOK))
VALUE   = (NQVALUE ^ QVALUE)("VALUE")

PAIR    = Group(KEY + OP_EQ + VALUE)("PAIR")

PAIRS   = (PAIR + ZeroOrMore(DELIM + PAIR))

with open('input.txt') as f:
    lines = f.read()

res = PAIRS.parseString(lines, parseAll=True)

for (k,v) in res:
    print('{} = "{}"'.format(k, ' '.join(v)))

输出:

dog = "blue"
cat = "orange tangerine"
mouse = "a small grey mouse"
dog = "blue"
cat = "orange tangerine"
mouse = "a small grey mouse"
lion = "nonexistent"

作为XML,供参考:

<PAIRS>
  <PAIR>
    <KEY>dog</KEY>
    <VALUE>
      <ITEM>blue</ITEM>
    </VALUE>
  </PAIR>
  <PAIR>
    <KEY>cat</KEY>
    <VALUE>
      <ITEM>orange</ITEM>
      <ITEM>tangerine</ITEM>
    </VALUE>
  </PAIR>
  <PAIR>
    <KEY>mouse</KEY>
    <VALUE>
      <ITEM>a</ITEM>
      <ITEM>small</ITEM>
      <ITEM>grey</ITEM>
      <ITEM>mouse</ITEM>
    </VALUE>
  </PAIR>
  <PAIR>
    <KEY>dog</KEY>
    <VALUE>
      <ITEM>blue</ITEM>
    </VALUE>
  </PAIR>
  <PAIR>
    <KEY>cat</KEY>
    <VALUE>
      <ITEM>orange</ITEM>
      <ITEM>tangerine</ITEM>
    </VALUE>
  </PAIR>
  <PAIR>
    <KEY>mouse</KEY>
    <VALUE>
      <ITEM>a</ITEM>
      <ITEM>small</ITEM>
      <ITEM>grey</ITEM>
      <ITEM>mouse</ITEM>
    </VALUE>
  </PAIR>
  <PAIR>
    <KEY>lion</KEY>
    <VALUE>
      <ITEM>nonexistent</ITEM>
    </VALUE>
  </PAIR>
</PAIRS>

编辑:FWIW,您可以在正则表达式中执行此操作:

import re

with open('input.txt') as f:
    lines = f.read()

mat = re.sub(r'=([^"]\w*(?:(?:\\ )\w*)*)', r'="\1"', lines)  # Quote unquoted values
mat = mat.replace("\\ "," ").replace("\\\n","")              # Replace escaped spaces
mat = re.findall(r'(\w*)="(.*?)"', mat)                      # Extract pairs
for (k,v) in mat:                                            # Print pairs
    print('{} = "{}"'.format(k, v))

输出:

dog = "blue"
cat = "orange tangerine"
mouse = "a small grey mouse"
dog = "blue"
cat = "orange tangerine"
mouse = "a small grey mouse"
lion = "nonexistent"