Обратные помеченные подстроки в строке
У меня есть строка, в которой каждая отмеченная подстрока в <
а также >
должен быть перевернут (скобки не гнездятся). Например,
"hello <wolfrevokcats>, how <t uoy era>oday?"
должен стать
"hello stackru, how are you today?"
Моя текущая идея состоит в том, чтобы перебрать строку и найти пары индексов, где <
а также >
являются. Затем просто нарежьте строку и снова соедините кусочки со всем, что было между маркерами в обратном порядке. Это правильный подход? Есть ли очевидное / лучшее решение?
4 ответа
Это довольно просто с регулярными выражениями. re.sub
принимает функцию в качестве аргумента, которому передается объект сопоставления.
>>> import re
>>> s = 'hello <wolfrevokcats>, how <t uoy era>oday?'
>>> re.sub('<(.*?)>', lambda m: m.group(1)[::-1], s)
'hello stackru, how are you today?'
Объяснение регулярного выражения:
<(.*?)>
будет соответствовать всем между <
а также >
в соответствующей группе 1. Чтобы убедиться, что двигатель регулярного выражения остановится на первом >
вхождение символа, ленивый квантификатор *?
используется.
Функция lambda m: m.group(1)[::-1]
это передается re.sub
берет объект соответствия, извлекает группу 1 и переворачивает строку. в заключение re.sub
вставляет это возвращаемое значение.
Или используйте re.sub()
и заменяющая функция:
>>> import re
s = 'hello <wolfrevokcats>, how <t uoy era>oday?'
>>> re.sub(r"<(.*?)>", lambda match: match.group(1)[::-1], s)
'hello stackru, how are you today?'
где .*?
будет соответствовать любым символам любое количество раз без жадного способа. Скобки вокруг него помогут нам зафиксировать его в группе, к которой мы затем будем обращаться в замещающей функции - match.group(1)
, [::-1]
запись среза переворачивает строку.
Я собираюсь предположить, что это задание курсовой работы и использование регулярных выражений не допускается. Поэтому я собираюсь предложить решение, которое не использует его.
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))
Суть кода состоит в том, чтобы иметь только один проход в строке по одному символу за раз. Когда вы выходите за скобки, просто добавьте символ в конец строки результата. Внутри скобок вставьте символ в положение открывающей скобки (то есть предварительно вставьте символ).
Я согласен с тем, что регулярные выражения являются подходящим инструментом для решения этой проблемы, и мне нравится суть ответа Дмитрия Б.. Тем не менее, я использовал этот вопрос на практике в отношении генераторов и функционального программирования, и я публикую свое решение только для того, чтобы поделиться им.
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 stackru, how are you today?
Вот еще один без использования регулярных выражений:
def reverse_marked(str0):
separators = ['<', '>']
reverse = 0
str1 = ['', str0]
res = ''
while len(str1) == 2:
str1 = str1[1].split(separators[reverse], maxsplit=1)
res = ''.join((res, str1[0][::-1] if reverse else str1[0]))
reverse = 1 - reverse # toggle 0 - 1 - 0 ...
return res
print(reverse_marked('hello <wolfrevokcats>, how <t uoy era>oday?'))
Вывод:
hello stackru, how are you today?