python randomizer - получить случайный текст между фигурными скобками с двойным уровнем вложенности

эй, мне нужно создать простой рандомизатор Python. пример ввода:

{{hey|hello|hi}|{privet|zdravstvuy|kak dela}|{bonjour|salut}}, can {you|u} give me advice?

и вывод должен быть:

hello, can you give me advice

у меня есть скрипт, который может это сделать, но только на одном вложенном уровне

with open('text.txt', 'r') as text:
    matches = re.findall('([^{}]+)', text.read())
words = []
for match in matches:
    parts = match.split('|')
    if parts[0]:
        words.append(parts[random.randint(0, len(parts)-1)])
message = ''.join(words)

мне этого мало)


person Alice Polansky    schedule 21.01.2015    source источник
comment
Мне кажется, что ваш ввод следует грамматике, которая слишком сложна для простых регулярных выражений. Я бы сказал, создайте правильный лексический анализатор, который вызывается синтаксическим анализатором для получения вашего вывода. Если вы не знакомы с этой концепцией, я предлагаю вам сначала прочитать теорию :)   -  person Karel Kubat    schedule 21.01.2015
comment
Вы ищете рекурсивное сопоставление регулярных выражений. См.: stackoverflow.com/questions/1656859/   -  person jean-loup    schedule 21.01.2015
comment
@KarelKubat о нет, мне это не нужно. я просто хочу получить случайный текст из фигурных скобок, которые содержат еще одну фигурную скобку   -  person Alice Polansky    schedule 21.01.2015
comment
И что вы будете делать с большей вложенностью, как в {{a|{c|d}|e}|f}?   -  person Karel Kubat    schedule 21.01.2015
comment
Так как есть только один оператор, вам не нужны дополнительные фигурные скобки. {a | {b | c}} по сути то же самое, что и {a | b | c}.   -  person georg    schedule 21.01.2015
comment
@georg Это вероятностно неверно для примера в посте.   -  person jean-loup    schedule 21.01.2015
comment
@jean-loup: теоретически да, но я не знаю, важна ли для ОП разница между вероятностями 0,15 и 0,125.   -  person georg    schedule 21.01.2015


Ответы (2)


Регулярное выражение Python не поддерживает вложенные структуры, поэтому вам придется найти другой способ анализа строки.

Вот мой быстрый кладж:

def randomize(text):
    start= text.find('{')
    if start==-1: #if there are no curly braces, there's nothing to randomize
        return text

    # parse the choices we have
    end= start
    word_start= start+1
    nesting_level= 0
    choices= [] # list of |-separated values
    while True:
        end+= 1
        try:
            char= text[end]
        except IndexError:
            break # if there's no matching closing brace, we'll pretend there is.
        if char=='{':
            nesting_level+= 1
        elif char=='}':
            if nesting_level==0: # matching closing brace found - stop parsing.
                break
            nesting_level-= 1
        elif char=='|' and nesting_level==0:
            # put all text up to this pipe into the list
            choices.append(text[word_start:end])
            word_start= end+1
    # there's no pipe character after the last choice, so we have to add it to the list now
    choices.append(text[word_start:end])
    # recursively call this function on each choice
    choices= [randomize(t) for t in choices]
    # return the text up to the opening brace, a randomly chosen string, and
    # don't forget to randomize the text after the closing brace 
    return text[:start] + random.choice(choices) + randomize(text[end+1:])
person Aran-Fey    schedule 21.01.2015

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

import re, random

msg = '{{hey|hello|hi}|{privet|zdravstvuy|kak dela}|{bonjour|salut}}, can {you|u} give me advice?'


while re.search(r'{.*}', msg):
    msg = re.sub(
        r'{([^{}]*)}', 
        lambda m: random.choice(m.group(1).split('|')), 
        msg)

print msg
# zdravstvuy, can u give me advice?
person georg    schedule 21.01.2015