2015-04-18 2 views
1

у меня есть необходимость синтаксического анализа текста, пространство, ограниченное пару ключей значение в виде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, которые помогли с многострочным текстом, но не с обратным слэшем-экранированным пространством

+0

Таким образом, можно не только значения имеют пробелы, но они могут или не могут быть окружены двойные кавычки? – jedwards

+0

Правильно, если они окружены кавычками, это легко обрабатывается QuotesString от pyparsing() – lapax

ответ

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> 

Edit: 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" 
+1

:) да, Regex будет намного короче .. однако это часть более крупного анализатора. Это решение работает хорошо. Я опустил parseAll = True для случаев с несколькими линиями. Я не понимал, что вы можете использовать «\\» как анализируемый фрагмент. Оглядываясь назад, это имеет смысл. Большое спасибо, это избавит меня от времени исследований. – lapax