Элегантный разбор этого?«А, б, в», д, «д, е» - PullRequest
2 голосов
/ 09 июля 2010

Я хочу разобрать эти строки в списках в Python:

"a,b,c",d,"e,f"        =>  ['a','b','c'] , ['d'] , ['e','f']
"a,b,c",d,e            =>  ['a','b','c'] , ['d'] , ['e']
a,b,"c,d,e,f"          =>  ['a'],['b'],['c','d','e','f']
a,"b,c,d",{x(a,b,c-d)} =>  ['a'],['b','c','d'],[('x',['a'],['b'],['c-d'])]

Это гнездо, поэтому я подозреваю, что регулярные выражения отсутствуют. Все, что я могу придумать, это начать считать кавычки и скобки, чтобы разобрать его, но это кажется ужасно не элегантным. Или, возможно, сначала сопоставить кавычки и заменить запятые между ними на somechar, затем разделить на запятые, пока не будет выполнено все вложение, и, наконец, снова разделить на somechar.

Есть мысли?

Ответы [ 4 ]

2 голосов
/ 09 июля 2010

Итак, вот ваш "честный парсер python".Кодирую для вас, а не отвечаю на вопрос, но я буду в порядке, если вы включите его :-)

QUOTE = '"'
SEP = ',(){}"'
S_BRACKET = '{'
E_BRACKET = '}'
S_PAREN = '('

def parse_plain(string):
    counter = 0
    token = ""
    while counter<len(string):
        if string[counter] in SEP:
            counter += 1
            break
        token += string[counter]
        counter += 1
    return counter, token

def parse_bracket(string):
    counter = 1
    fwd, token = parse_plain(string[counter:])
    output = [token]
    counter += fwd
    fwd, token = parse_(string[counter:])
    output += token
    counter += fwd
    output = [tuple(output)]
    return counter, output

def parse_quote(string):
    counter = 1
    output = []
    while counter<len(string):
        if counter > 1 and string[counter - 1] == QUOTE:
            counter += 1
            break
        fwd, token = parse_plain(string[counter:])
        output.append(token)
        counter += fwd
    return counter, output

def parse_(string):
    output = []
    counter = 0
    while counter < len(string):
        if string[counter].isalpha():
            fwd, token = parse_plain(string[counter:])
            token = [token]
        elif string[counter] == QUOTE:
            fwd, token = parse_quote(string[counter:])
        elif string[counter] == S_BRACKET:
            fwd, token = parse_bracket(string[counter:])
        elif string[counter] == E_BRACKET:
            counter += 1
            break
        else:
            counter += 1
            continue
        output.append(token)
        counter += fwd
    return counter, output

def parse(string):
    return parse_(string)[1]

И протестируете вывод:

>>> print parse('''"a,b,c",d,"e,f"''')
[['a', 'b', 'c'], ['d'], ['e', 'f']]
>>> print parse('''"a,b,c",d,e ''')
[['a', 'b', 'c'], ['d'], ['e ']]
>>> print parse('''a,b,"c,d,e,f"''')
[['a'], ['b'], ['c', 'd', 'e', 'f']]
>>> print parse('''a,"b,c,d",{x(a,b,c-d)}''')
[['a'], ['b', 'c', 'd'], [('x', ['a'], ['b'], ['c-d'])]]
>>> print parse('''{x(a,{y("b,c,d",e)})},z''')
[[('x', ['a'], [('y', ['b', 'c', 'd'], ['e'], ['z'])])]]
>>>
0 голосов
/ 09 июля 2010

Для первых трех случаев вы можете просто рекурсивно применить читатель CSV:

import csv

def expand( st ):
    if "," not in st:
        return st
    return [ expand( col ) for col in csv.reader( [ st ] ).next() ]

print expand( '"a,b,c",d,"e,f"' )
print expand( '"a,b,c",d,e' )
print expand( 'a,b,"c,d,e,f"' )
0 голосов
/ 09 июля 2010

Один метод, который я использую в PHP для подобных вещей, - это заменить самую глубокую точку вложенного выражения (в данном случае, "{x (a, b, cd)}") символом, таким как '¶1', затем сохраните его проанализированное значение (будучи [('x', ['a'], ['b'], ['c-d'])]) в переменную $ nest1.

Вы сейчасиметь исходную строку 'a, "b, c, d", {x (a, b, cd)}', похожую на 'a, "b, c, d", ¶1', которая анализируется так же, как первые три,Затем просто найдите в результирующем массиве все, что начинается с '¶', и замените его соответствующей переменной.

Этот метод поддерживает столько уровней, сколько вы хотите, просто продолжайте циклически повторяться до тех пор, пока все символы не исчезнут.Например,

'a,"b,c,d",{x(a,b,{y(j,k,l-m)},c-d)}'
'a,"b,c,d",{x(a,b,¶1,c-d)}' and $nest1=[('y',['j'],['k'],['l-m'])]
'a,"b,c,d",¶2' and $nest2=[('x',['a'],['b'],['¶1'],['c-d'])]
['a'],['b','c','d'],['¶2']
['a'],['b','c','d'],[('x',['a'],['b'],['¶1'],['c-d'])]
['a'],['b','c','d'],[('x',['a'],['b'],[('y',['j'],['k'],['l-m'])],['c-d'])]

В целях безопасности вы можете даже избежать любого экземпляра ¶, который мог произойти в строке, прежде чем вносить изменения, а затем удалить их как последний шаг, если считаете, что это необходимо.

Я не знаю Python, поэтому он может работать не так, как PHP.Возможно, вам придется использовать массив вместо динамических переменных.

0 голосов
/ 09 июля 2010

у вас есть кавычки в строках?

Если нет - просто замените управляющие символы, чтобы сделать его совместимым с JSON, и используйте анализатор JSON

...