Расщепление строки C в Python - PullRequest
0 голосов
/ 30 сентября 2011

Я хотел бы разбить строку, похожую на

'abc "defg hijk \\"l; mn\\" opqrs"; tuv'

, на

(['abc', '"defg hijk \\"l; mn\\" opqrs"'], 33)

т.е. я не хочу разбивать точку с запятой внутри (вложенных) кавычек.Какой самый простой способ, токенизировать?Это не больно, если это быстро, но короткая лучше.

Редактировать: Я забыл еще одну деталь, которая делает его еще более хитрым.Мне нужна точка с запятой, которая обрезает строку, или -1, если ее нет.(Я делаю изменения в унаследованном коде, который раньше был рекурсивным, но переполнялся стеком, когда строка стала очень длинной.)

Ответы [ 3 ]

1 голос
/ 30 сентября 2011

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

Что-то вроде следующего должно быть хорошим руководством:

def parse(s):
    cur_s = []
    strings = []

    def flush_string():
        strings.push(''.join(cur_s))
        cur_s = []

    def handle_special_cases():
        # TODO: Fill this in

    for c in s:
        if c == ';':
            break
        elif c in ['\\' '"']:
            handle_special_cases()
        elif c == ' ':
            flush_string()
        else:
            cur_s.push(c)

    flush_string()
    return strings
0 голосов
/ 30 сентября 2011

Вот метод грубой силы, с которым я пошел. Бррр ...

def f(s):
    instr = False
    inescape = False
    a = ''
    rs = []
    cut_index = -1
    for idx,ch in enumerate(s):
        if instr:
            a += ch
            if inescape:
                inescape = False
            elif ch == '\\':
                inescape = True
            elif ch == '"':
                if a:
                    rs += [a]
                    a = ''
                instr = False
        elif ch == '"':
            if a:
                rs += [a]
            a = ch
            instr = True
        elif ch == ';':
            if a:
                rs += [a]
            cut_index = idx
            break
        elif ch == ' ' or ch == '\t' or ch == '\n':
            if a:
                rs += [a]
                a = ''
        else:
            a += ch
    return rs, cut_index

f('abc "defg hijk \\"l; mn\\" opqrs"; tuv')
0 голосов
/ 30 сентября 2011

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

#!/usr/bin/env python

inp="""abc "defg hijk \\"l; mn\\" opqrs"; tuv'`"""

def words_to_semi(inpstr):
    ret = ['']
    st8 = 1  # state: 1=reg, 2=in quotes, 3=escaped quote, 4=escaped reg, 0=end
    ops = { 1 : {' ': lambda c: (None,1),
                 '"': lambda c: (c,2),
                 ';': lambda c: ('',0),
                 '\\': lambda c: (c,4),
                 },
            2 : {'\\': lambda c: (c,3),
                 '"':  lambda c: (c,1),
                 },
            3 : {None: lambda c: (c,2)},
            4 : {None: lambda c: (c,1)},
            }
    pos = 0

    for C in inpstr:
        oc,st8 = ops[st8].get(C, ops[st8].get(None, lambda c:(c,st8)))(C)
        if not st8: break
        if oc is None:
            ret.append('')
        else:
            ret[-1] += oc
        pos = pos + 1
    return ret, pos

print str(words_to_semi(inp))

Просто измените параметр ops dict (и добавьте новые состояния) для обработки других случаев; все остальное - общий код.

...