2012-01-06 2 views
1

Рассмотрим этот текст:Python - множественный выбор разметки разборе

Хотели бы вы иметь ответы на ваши вопросы, присланные вам по электронной почте?

Я собираюсь предложить несколько вариантов для нескольких слов, разметить их так:

Вы бы хотели [получить] | [имея] | г [иметь] ответы на ваши вопросы отправлены [до] | g [to] | [on] вам по электронной почте?

Выбор являются bracketted и отделены друг от труб
Хороший выбор предшествует г

Я хотел бы разобрать эту фразу, чтобы получить текст, отформатированный как это:

Вы хотите, чтобы __ ответы на ваши вопросы отправили __ вас по электронной почте?

Со списком как:

[ 
    [ 
    {"to get":0}, 
    {"having":0}, 
    {"to have":1}, 
    ], 
    [ 
    {"up to":0}, 
    {"to":1}, 
    {"on":0}, 
    ], 
] 

Является ли мой дизайн Разметка нормально?
Как повторно выставить предложение, чтобы получить нужный результат и сгенерировать список?

редактировать: Пользователь ориентированного язык разметки требуется

+0

Я не хотел идти на громкие слова здесь, но .. XML довольно хорошо. В нем даже есть язык разметки. И, его расширяемость. То же и в названии. Если ваш запрос - мысленный эксперимент, то да, я думаю, это «работает», но .. гах. Это 2011 год, написание парсеров JSON для проприетарных форматов идет в неправильном направлении. XML потрясающий, мне все равно, что кто-то говорит. lalalala Я тебя не слышу! – synthesizerpatel

+0

Я тоже не хочу говорить, но это больше похоже на тех, кто ищет ответы на домашнюю проблему, чем мысленный эксперимент. Если это так, добавьте тег 'homework', пожалуйста. И независимо от того, является ли это оригинальной мыслью или назначением, напишите свой код регулярного выражения, то, что вы уже пробовали, и какие проблемы вы столкнулись. – Dave

+0

Это не вопрос домашней работы. Все инструменты разметки, такие как TinyMCE или Markdown, имеют свой формат разметки, и они не используют хороший XML __old__ из-за его многословия. Спасибо за ваше предложение @synthesizerpatel, но я не создаю парсер JSON. Я просто пытаюсь разобрать текст с разметкой, чтобы получить некоторые переменные, не более того. –

ответ

2

Я предлагаю мое решение тоже:

Вы хотите {получить | имеющие | + для} ответов на ваши вопросы отправлены {до | + to | on} по электронной почте?

def extract_choices(text): 
    choices = [] 

    def callback(match): 
     variants = match.group().strip('{}') 
     choices.append(dict(
      (v.lstrip('+'), v.startswith('+')) 
      for v in variants.split('|') 
     )) 
     return '___' 

    text = re.sub('{.*?}', callback, text) 

    return text, choices 

Давайте попробуем:

>>> t = 'Would you like {to get|having|+to have} responses to your questions sent {up to|+to|on} you via email?' 
>>> pprint.pprint(extract_choices(t)) 
... ('Would you like ___ responses to your questions sent ___ you via email?', 
... [{'having': False, 'to get': False, 'to have': True}, 
... {'on': False, 'to': True, 'up to': False}]) 
+0

Мне это нравится. Компактная разметка и компактный код. – reclosedev

+0

Очень хорошее решение, спасибо. –

+0

кредитов для этой разметки идет на @reclosedev, я взял его идею о '{}' и раздели ненужные вещи :) – Ski

1

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

Во всяком случае, если вы решите использовать свой проект, я бы что-то вроде этого:

import re 

question_str = ("Would you like [to get]|[having]|g[to have] " 
       "responses to your questions sent " 
       "[up to]|g[to]|[on] you via email ?") 

def option_to_dict(option_str): 
    if option_str.startswith('g'): 
      name = option_str.lstrip('g') 
      value = 1 
    else: 
      name = option_str 
      value = 0 
    name = name.strip('[]') 
    return {name: value} 

regex = re.compile('g?\[[^]]+\](\|g?\[[^]]+\])*') 

options = [[option_to_dict(option_str) 
      for option_str in match.group(0).split('|')] 
      for match in regex.finditer(question_str)] 
print options 

question = regex.sub('___', question_str) 
print question 

Пример вывода:

[[{'to get': 0}, {'having': 0}, {'to have': 1}], [{'up to': 0}, {'to': 1}, {'on': 0}]] 
Would you like ___ responses to your questions sent ___ you via email ? 

Примечание: Что касается дизайна, я думаю, что было бы лучше иметь отметку, чтобы установить начало/конец всего набора параметров (а не только один для одиночных опций).

+2

Могу ли я предложить заменить 'name = option_str [2: -1]' и 'name = option_str [1: -1]' с помощью одного простого 'option_str.strip ('g []')'? –

+0

@ DK Конечно, это делает код более удобочитаемым. Спасибо за ваше предложение. – jcollado

+0

@DK Наконец, я не добавил 'g' в' strip', потому что это приведет к потере символов из самой опции, если она начнется/закончится с 'g'. – jcollado

2

Грубый реализация синтаксического анализа с использованием регулярных выражений:

import re 
s = "Would you like [to get]|[having]|g[to have] responses to your questions sent [up to]|g[to]|[on] you via email ?" # pattern string 

choice_groups = re.compile(r"((?:g?\[[^\]]+\]\|?)+)") # regex to get choice groups 
choices = re.compile(r"(g?)\[([^\]]+)\]") # regex to extract choices within each group 

# now, use the regexes to parse the string: 
groups = choice_groups.findall(s) 
# returns: ['[to get]|[having]|g[to have]', '[up to]|g[to]|[on]'] 

# parse each group to extract possible choices, along with if they are good 
group_choices = [choices.findall(group) for group in groups] 
# will contain [[('', 'to get'), ('', 'having'), ('g', 'to have')], [('', 'up to'), ('g', 'to'), ('', 'on')]] 

# finally, substitute each choice group to form a template 
template = choice_groups.sub('___', s) 
# template is "Would you like ___ responses to your questions sent ___ you via email ?" 

Синтаксический это в соответствии с вашим формат должен быть довольно легко теперь. Удачи :)

+0

+1 очень простое решение. –

3

Я бы добавил некоторые скобки для группировки {} и вывел не список списка dicts, а список dicts.

Код:

import re 

s = 'Would you like {[to get]|[having]|g[to have]} responses to your questions sent {[up to]|g[to]|[on]} you via email ?' 

def variants_to_dict(variants): 
    dct = {} 
    for is_good, s in variants: 
     dct[s] = 1 if is_good == 'g' else 0 
    return dct 

def question_to_choices(s): 
    choices_re = re.compile(r'{[^}]+}') 
    variants_re = re.compile(r'''\|?(g?) 
           \[ 
            ([^\]]+) 
           \] 
           ''', re.VERBOSE) 
    choices_list = [] 
    for choices in choices_re.findall(s): 
     choices_list.append(variants_to_dict(variants_re.findall(choices))) 

    return choices_re.sub('___', s), choices_list 

question, choices = question_to_choices(s) 
print question 
print choices 

Выход:

Would you like ___ responses to your questions sent ___ you via email ? 
[{'to have': 1, 'to get': 0, 'having': 0}, {'to': 1, 'up to': 0, 'on': 0}] 
+0

Это кажется мне наиболее эффективным. –

+0

@ Поверните, хотя вы уже приняли мой ответ, взгляните на решение * Skirmantas *. Он имеет компактную разметку и код. – reclosedev

+0

Я только что видел это, спасибо, я оставлю вас хотя бы мой +1 :) –