Python 如何从文件中删除所有非标准字符?

Python 如何从文件中删除所有非标准字符?,python,Python,我几周前在bash中就有了这个功能,但现在我想要一个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

我几周前在bash中就有了这个功能,但现在我想要一个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
会产生相同的结果。

如果您要做的是删除回车(
^M
,或Python术语中的
'\r'
)并完成,则在
字符串上进行过滤。可打印的
不会完成您想要的操作。(正如所解释的那样,您也做得不对-
过滤器
不会在适当的位置修改字符串,它会返回一个新字符串,并对其进行了一些过度复杂化,但如果它不是正确的逻辑,谁在乎呢?)


如果查看
string.printable
,您将看到它包含回车:

>>> '\r' in string.printable
True
因此,剥离不可打印字符不会删除回车符


如果你看一下你的控制序列是什么样子的,比如
^[[A
'\x1b[A'
,在Python术语中),它们以转义字符开始,然后是一系列可打印字符:

>>> [c.isprintable() for c in '\x1b[A']
[False, True, True]
因此,当您去掉不可打印的字符时,这将远程调用转义字符,留下
[
A

因此,您需要编写或找到一些解析控制序列的代码,以便能够检测并删除它们。这意味着您需要知道要检测并删除的控制序列类型

IIRC,VT100和过时的ANSI X3.64的规则非常简单,如下所示:

^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
  • 转义(
    ^[/code>,也称为
    \x1b
  • (可选)
    [
    ,后跟一系列“私有”字符,后跟一系列零个或多个分号分隔的整数,后跟零个或多个“中间”字节(来自ASCII 32-47)…我认为这可能更容易匹配为
    [
    后跟ASCII 32-63中除58以外的任何字符串,以尝试获得完全正确的结果
  • “命令”(来自ASCII 64-126)
所以,像
r'\x1b\[[-9;-?]*[@-~]'
这样的正则表达式应该可以处理这个问题。但是因为我不知道您的数据是VT100、ANSI X3.64还是“在我运行某个程序时出现在termcaps中的任何东西”,我不能告诉你这条规则是否适合你。我只能告诉你,这条规则适用于你给出的一个例子,
^[[A

你必须在变量中获取结果

无论如何,我会使用一个简单的正则表达式方法

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)

如果您实际上不想删除所有控制序列,只想从特定输入中删除特定的
^M
^A
序列,您可以用两种更简单的方法来完成

首先,只需替换这些序列:

text = text.replace('\r', '').replace('\x1b[A', '')
或者,第二个看起来更复杂,但它可以让你处理你尚未处理的其他部分(删除前两个
^M
s之间的所有可打印内容)-你可以在“获救”之前删除所有内容,然后在“完成”之前删除角色:

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

(saved.*?
匹配从
saved
到下一个
\r
的所有内容,然后
(Finished.*.
匹配从
Finished
到结尾的所有内容(我不确定这是什么,还是换行);将这两个捕获组连接在一起,你就得到了你想要的。

另请参见:你的问题中应该包含足够的信息来解释你想做什么;仅仅链接到不同的问题是不够的。我已对你的问题进行了编辑,以便它(希望如此)与您实际询问的内容相匹配;如果我错了,请拒绝我的编辑并自己进行。在您的更新版本中,您希望如何删除“复制未尝试的块…传递1(转发)”部分?这显然是所有可打印的字符。您是否试图实际模拟终端,以便在以后检测到初始行被覆盖,从而将其删除?我计划在其他字符之后处理该字符串。我想我可以一次性处理所有字符。@p014k:如果您只是想做一些这样的事情狭隘的特殊用途,为什么不在“获救”之前删除所有内容,在“完成”之前删除字符,并完成它呢?对不起,我删除了我的答案。它没有回答真正的问题。我不打算使用
过滤器
,我只想要一个在python中工作的解决方案,它可以摆脱e from.
filter
方法只是我尝试过的一种我认为有效的方法,但在使用
cat-v
时,那些字符仍然存在。我在Warren删除的答案中提到,我想删除
^M复制未尝试过的块…传递1(向前)^M^[[A^[[A]^[[A
部分。@p014k:为什么你对一个不相关的脚注而不是答案的要点做出回应?如果你有错误的逻辑,不管你如何实现该逻辑,它都不会起作用。但是如果这太分散注意力,我会删除该部分。同时,你为什么要否决我的答案?这肯定是你的问题,而且有限的解决方法。它不包含完整的代码,因为问题没有完全指定,但这应该足以让您编写自己的代码以匹配实际数据。我没有否决您的答案,其他人否决了。您的连续编辑是唯一令人困惑的部分。我将尝试通过
re
module删除\x1b。是否python中的
^M
\r
等价物?这与Warren删除的答案相同,但没有回答问题。好的。如果有