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

2024-10-01 00:17:23 发布

您现在位置:Python中文网/ 问答频道 /正文

几周前我在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序列,以实现以下所需的输出

^{pr2}$

到目前为止,我已经尝试过:

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会产生相同的结果。在


Tags: bashreadinputratepassopen解决方案file
3条回答

必须在变量中获取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)

如果您想做的是删除回车符(^M,或者在Python术语中是'\r')并完成ANSI or VT100 or whatever-you-have control sequences,那么对{}进行过滤将不会达到您想要的效果。(正如Warren Weckesser's answer所解释的那样,Warren Weckesser's answer并没有适当地修改字符串,它返回一个新字符串并使其过于复杂,但考虑到它不是正确的逻辑,谁在乎呢?)在


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

>>> '\r' in string.printable
True

因此,剥离不可打印字符不会删除回车符。在


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

^{pr2}$

因此,当您去掉不可打印字符时,这将远程处理转义字符,留下[和{}。在

因此,您需要编写或找到一些解析控制序列的代码,以便检测并删除它们。这意味着你需要知道你要检测和移除的是哪种控制序列。在

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

  • 转义(^[,又名\x1b
  • 可选地[,后跟一个“private”字符序列,后跟一个零个或多个以分号分隔的整数序列,然后是零个或多个“中间”字节(来自ASCII 32-47)…我认为,与ascii32-63中除58外的任何字符串匹配起来可能更简单完全正确。在
  • “命令”(来自ASCII 64-126)。在

所以,像r'\x1b\[[ -9;-?]*[@-~]'这样的regex应该可以处理这个问题。但是,由于我不知道你的数据是VT100、ansix3.64,还是“在我运行某个程序时碰巧出现在术语caps中的任何东西”,我无法告诉你这是否适合你。我只能告诉你,这个规则适用于你给出的一个例子,^[[A。在

如果实际上不是要删除所有的控制序列,只删除特定输入中的^M和{}序列,可以用两种更简单的方法来完成。在

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

text = text.replace('\r', '').replace('\x1b[A', '')

或者,第二个看起来更复杂,但它可以让你处理你还没有得到的另一部分(删除前两个^M之间的所有可打印的内容)-你可以只删除“解救”之前的所有内容,然后在“完成”之前删除字符:

^{pr2}$

或者,使用正则表达式:

text = ''.join(re.search(r'(rescued.*?)\r(Finished.*)', text, re.DOTALL).groups())

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

相关问题 更多 >