2016-03-18 4 views
1

У меня есть строка, в которой каждая помеченная подстрока в пределах < и > должна быть отменена (скобки не гнездятся). Например,Обратные помеченные подстроки в строке

"hello <wolfrevokcats>, how <t uoy era>oday?" 

должен стать

"hello stackoverflow, how are you today?" 

Моя текущая идея заключается в том, чтобы петля над строкой и найти пары индексов где < и > являются. Затем просто нарежьте строку и снова нанесите кусочки со всем, что было между маркерами. Правильно ли это? Есть ли очевидное/лучшее решение?

ответ

8

Это довольно просто с регулярными выражениями. re.sub принимает функцию как аргумент, которому передается объект соответствия.

>>> import re 
>>> s = 'hello <wolfrevokcats>, how <t uoy era>oday?' 
>>> re.sub('<(.*?)>', lambda m: m.group(1)[::-1], s) 
'hello stackoverflow, how are you today?' 

Объяснения регулярного выражения:

<(.*?)> будет соответствовать все между < и > в соответствии группы 1. Для того, чтобы гарантировать, что регулярное выражение двигатель остановится на первый > появления символа, ленивый квантификатор *? используется ,

Функция lambda m: m.group(1)[::-1], которая передается в re.sub, принимает объект соответствия, извлекает группу 1 и отменяет строку. Наконец re.sub вставляет это возвращаемое значение.

4

Или используйте re.sub() и функцию заменяющую:

>>> import re 
s = 'hello <wolfrevokcats>, how <t uoy era>oday?' 
>>> re.sub(r"<(.*?)>", lambda match: match.group(1)[::-1], s) 
'hello stackoverflow, how are you today?' 

где .*? бы любые символы любое количество раз в non-greedy моды. Скобки вокруг него помогут нам захватить его в group, о котором мы говорим в заменяющей функции - match.group(1). [::-1] ломтик обозначение reverses a string.

3

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

content = "hello <wolfrevokcats>, how <t uoy era>oday?" 

insert_pos = -1 
result = [] 
placeholder_count = 0 

for pos, ch in enumerate(content): 
    if ch == '<': 
     insert_pos = pos 
    elif ch == '>': 
     insert_pos = -1 
     placeholder_count += 1 
    elif insert_pos >= 0: 
     result.insert(insert_pos - (placeholder_count * 2), ch) 
    else: 
     result.append(ch) 

print("".join(result)) 

Суть кода состоит в том, чтобы иметь только один проход в строке по одному символу за раз. Когда вне скобок просто добавьте символ в конце строки результата. Когда внутри кронштейнов вставьте символ в положение открывающей скобки (т. Е. Предварительно отложите символ).

0

Я согласен с тем, что регулярные выражения являются правильным инструментом для решения этой проблемы, и мне нравится суть ответа Дмитрия Б. Тем не менее, я использовал этот вопрос, чтобы практиковать генераторы и функциональное программирование, и я отправляю свое решение только для его совместного использования.

msg = "<,woN> hello <wolfrevokcats>, how <t uoy era>oday?" 

def traverse(s, d=">"): 
    for c in s: 
     if c in "<>": d = c 
     else: yield c, d 

def group(tt, dc=None): 
    for c, d in tt: 
     if d != dc: 
      if dc is not None: 
       yield dc, l 
      l = [c] 
      dc = d 
     else: 
      l.append(c) 
    else: yield dc, l 

def direct(groups): 
    func = lambda d: list if d == ">" else reversed 
    fst = lambda t: t[0] 
    snd = lambda t: t[1] 
    for gr in groups: 
     yield func(fst(gr))(snd(gr)) 

def concat(groups): 
    return "".join("".join(gr) for gr in groups) 

print(concat(direct(group(traverse(msg))))) 

#Now, hello stackoverflow, how are you today?