将格式控制字符(退格和回车)应用于字符串,无需递归

时间:2014-09-16 20:52:31

标签: python regex backspace control-characters

在字符串中“解释”格式控制字符的最简单方法是什么,以便将结果显示为打印结果。为简单起见,我假设字符串中没有换行符。

例如,

>>> sys.stdout.write('foo\br')

显示for,因此

interpret('foo\br')应为'for'

>>>sys.sdtout.write('foo\rbar')

显示bar,因此

interpret('foo\rbar')应为'bar'


我可以在这里写一个正则表达式替换,但是,在'\b'替换的情况下,它必须递归地应用,直到不再出现。如果没有递归就完成了。

有更简单的方法吗?

3 个答案:

答案 0 :(得分:1)

如果效率无关紧要,一个简单的堆栈就可以正常工作:

string = "foo\rbar\rbash\rboo\b\bba\br"

res = []
for char in string:
    if char == "\r":
        res.clear()
    elif char == "\b":
        if res: del res[-1]
    else:
        res.append(char)

"".join(res)
#>>> 'bbr'

否则,我认为在复杂的情况下,这个速度和你希望的一样快:

string = "foo\rbar\rbash\rboo\b\bba\br"

try:
    string = string[string.rindex("\r")+1:]
except ValueError:
    pass

split_iter = iter(string.split("\b"))
res = list(next(split_iter, ''))
for part in split_iter:
    if res: del res[-1]
    res.extend(part)

"".join(res)
#>>> 'bbr'

请注意,我还没有计时。

答案 1 :(得分:1)

Python没有任何内置或标准库模块来执行此操作。 但是,如果您只关心简单的控制字符,例如\r\b\n,您可以编写一个简单的函数来处理此问题:

def interpret(text):
    lines = []
    current_line = []
    for char in text:
        if char == '\n':
            lines.append(''.join(current_line))
            current_line = []
        elif char == '\r':
            current_line.clear()
            # del current_line[:]  # in old python versions
        elif char == '\b':
            del current_line[-1:]
        else:
            current_line.append(char)
    if current_line:
        lines.append(current_line)
    return '\n'.join(lines)

您可以扩展处理所需控制字符的功能。例如,您可能想要忽略一些未在终端中实际显示的控制字符(例如,响铃\a

答案 2 :(得分:0)

更新:在要求澄清和示例字符串30分钟后,我们发现问题实际上完全不同:"如何 重复应用格式控制字符(退格) 到Python字符串?" 在这种情况下,你显然需要反复应用正则表达式/ fn,直到你停止获得匹配。 解决方案:

import re

def repeated_re_sub(pattern, sub, s, flags=re.U):
    """Match-and-replace repeatedly until we run out of matches..."""
    patc = re.compile(pattern, flags)

    sold = ''
    while sold != s:
        sold = s
        print "patc=>%s<    sold=>%s<   s=>%s<" % (patc,sold,s)
        s = patc.sub(sub, sold)
        #print help(patc.sub)

    return s

print repeated_re_sub('[^\b]\b', '', 'abc\b\x08de\b\bfg')
#print repeated_re_sub('.\b', '', 'abcd\b\x08e\b\bfg')

[以前的多个答案,要求澄清并指出 re.sub(...) string.replace(...)都可用于解决问题,非递归。]