反转字符串中标记的子字符串

Reverse marked substrings in a string

我有一个字符串,其中 <> 中的每个标记子字符串 必须颠倒(括号不嵌套)。例如,

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

应该变成

 "hello Whosebug, how are you today?"

我目前的想法是遍历字符串并找到索引对 <> 在哪里。然后只需将字符串切片并放入切片 再次与标记之间的所有内容一起反转。 这是正确的方法吗?有obvious/better解决方案吗?

或者,使用 re.sub() 替换函数:

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

其中 .*? 将在 non-greedy fashion. The parenthesis around it would help us to capture it in a group which we then refer to in the replacing function - match.group(1). [::-1] slice notation reverses a string.

中匹配任何字符任意次数

使用正则表达式非常简单。 re.sub 将函数作为匹配对象传递给的参数。

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

正则表达式的解释:

<(.*?)> 将匹配匹配组 1 中 <> 之间的所有内容。为确保正则表达式引擎将在第一个 > 符号出现时停止,使用惰性量词 *?

传递给 re.sub 的函数 lambda m: m.group(1)[::-1] 获取匹配对象,提取第 1 组,并反转字符串。最后 re.sub 插入这个 return 值。

我假设这是一项课程作业,不允许使用正则表达式。所以我将提供一个不使用它的解决方案。

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))

代码的要点是一次只对字符串传递一个字符。在括号外时,只需将字符附加到结果字符串的末尾。在括号内时,在左括号的位置插入字符(即前置字符)。

我同意正则表达式是解决这个问题的合适工具,我喜欢 Dmitry B. 回答的要点。但是,我用这个问题来练习生成器和函数式编程,我post我的解决方案只是为了分享它。

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 Whosebug, 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 Whosebug, how are you today?