几个星期前我在bash中遇到了这个same problem,但现在我想在python中找到解决方案。
我的输入如下:
^MCopying non-tried blocks... Pass 1 (forwards)^M^[[A^[[A^[[Arescued: 0 B, errsize: 0 B, current rate: 0 B/s
ipos: 0 B, errors: 0, average rate: 0 B/s
opos: 0 B, run time: 1 s, successful read: 1 s ago
^MFinished
我想删除每个^M
控制字符和每个^[[A
序列,以实现以下所需的输出;
rescued: 0 B, errsize: 0 B, current rate: 0 B/s
ipos: 0 B, errors: 0, average rate: 0 B/s
opos: 0 B, run time: 1 s, successful read: 1 s ago
Finished
到目前为止,我已尝试过:
def main(input=None):
f = open(os.path.abspath(input),'r')
file = f.read()
f.close()
filter(lambda x: x in string.printable, file)
open('output', 'w').write(file)
但执行cat -v
仍会显示所有非标准字符。
使用itertools.ifilter
会产生相同的结果。
答案 0 :(得分:1)
如果你要做的是删除回车(^M
或'\r'
用Python术语)并完成ANSI or VT100 or whatever-you-have control sequences,过滤string.printable
不会做你想要什么。 (你也做错了,正如Warren Weckesser's answer解释的那样 - filter
不会就地修改字符串,它会返回一个新的字符串 - 并且会使它过度复杂化,但鉴于它不是正确的逻辑,谁在乎?)
如果查看string.printable
,您会看到它包含回车符:
>>> '\r' in string.printable
True
因此,剥离不可打印的字符不会删除回车。
如果你看一下你的控制序列是什么样的,比如^[[A
(在Python术语中是'\x1b[A'
),它们以Escape字符开头,然后是一系列可打印的字符:
>>> [c.isprintable() for c in '\x1b[A']
[False, True, True]
因此,当您删除不可打印的字符时,将会远离转义字符,留下[
和A
。
因此,您需要编写或查找一些解析控制序列的代码,以便您可以检测它们并将其删除。这意味着您需要知道您尝试检测和删除的控制序列类型。
IIRC,VT100和过时的ANSI X3.64的规则非常简单,如下所示:
^[
,又名\x1b
)[
,后跟一系列“私有”字符,后跟零个或多个以分号分隔的整数序列,后跟零个或多个“中间”字节(来自ASCII 32-47)...我认为可能更容易匹配为[
后跟ASCII 32-63中的任何字符串,除了58,而不是试图完全正确。因此,像r'\x1b\[[ -9;-?]*[@-~]'
这样的正则表达式应该处理它。但是,由于我不知道您的数据是VT100,ANSI X3.64,还是“当我运行某些程序时发生在术语中的任何事情”,我无法告诉您这是否适合您。我可以告诉你的是,这条规则适用于你给出的一个例子,^[[A
。
答案 1 :(得分:1)
如果您实际上并未尝试删除所有控制序列,只是来自该特定输入的特定^M
和^[[A
序列,您可以通过两种更简单的方式执行此操作。
首先,只需替换这些序列:
text = text.replace('\r', '').replace('\x1b[A', '')
或者,第二个 - 这似乎更复杂,但它可以让你照顾你还没有达到的另一部分(删除前两个^M
之间的所有可打印的东西) - 你可以只是在“获救”之前移除所有内容,然后在“完成”之前删除角色:
# partition on the first 'rescued', drop the prefix, re-join the rest
text = ''.join(text.partition('rescued')[1:])
# partition on the last 'Finished', drop the last char of the prefix, re-join
bits = text.partition('Finished')
text = ''.join(bits[0][:-1], bits[1], bits[2])
或者,使用正则表达式:
text = ''.join(re.search(r'(rescued.*?)\r(Finished.*)', text, re.DOTALL).groups())
(rescued.*?)
匹配从rescued
到最后但不包括下一个\r
的所有内容,然后(Finished.*)
匹配从Finished
到结尾的所有内容(我不确定这是什么,或者换行);将这两个捕获组合在一起,你就得到了你想要的东西。
答案 2 :(得分:-1)
您必须在变量中获取filter结果。
无论如何,我会使用简单的RegEx方法。
import re, os
with open(os.path.abspath(input), 'r') as f:
match = re.search("rescued:.*Finished", f.read(), re.MULTILINE|re.DOTALL)
if match:
data = match.group(0).replace("^M","")
open('output', 'w').write(data)