如何在Python中去除类似于'\xe2'或'\x0c'的转义序列

9

我正在进行一个项目(基于内容的搜索),为此我在Ubuntu中使用“pdftotext”命令行实用程序将pdf中的所有文本写入某个文本文件。但它也会写入项目符号,现在当我读取文件以索引每个单词时,它还会获取一些转义序列的索引(如'\x01')。我知道这是由于项目符号(•)造成的。

我只想要文本,那么有没有办法去除这个转义序列。我已经做了类似于以下的事情

escape_char = re.compile('\+x[0123456789abcdef]*')
re.sub(escape_char, " ", string)

但这并不会移除转义序列。

先行感谢。

4个回答

13
问题在于\xXX仅仅代表一个控制字符,而不是这个字符本身。因此,除非你使用字符串的repr,否则你不能字面上匹配\x
你可以使用一个字符类来删除非可打印字符:
re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\xff]', '', text)

示例:

>>> re.sub(r'[\x00-\x1f\x7f-\xff]', '', ''.join(map(chr, range(256))))
' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'

4
你唯一的问题在于反斜杠很棘手。在字符串中,反斜杠可能会被特殊处理;例如\t将变成一个制表符。由于在字符串中\+不是特殊的,所以该字符串实际上就是你期望的那样。然后正则表达式编译器查看它,正则表达式中的\+只是一个普通的+字符。通常,+具有特殊含义("前面模式的1个或多个实例"),而反斜杠对其进行转义。
解决方法是将反斜杠加倍,这样可以匹配单个反斜杠。
我将该模式放入r''中,使其成为Python保留反斜杠的“原始字符串”。如果不这样做,Python的字符串解析器将把两个反斜杠转换为一个反斜杠,并且与\t变成制表符一样,\\将变成单个反斜杠。因此,请使用原始字符串并确切地输入正则表达式编译器要查看的内容。
此外,更好的模式是:反斜杠,然后是x,然后是匹配十六进制字符的字符类的1个或多个实例。我重写了模式以达到这个目的。
import re

s = r'+\x01+'
escape_char = re.compile(r'\\x[0123456789abcdef]+')
s = re.sub(escape_char, " ", s)

与其使用普通字符串,你可以使用原始字符串并小心处理反斜杠。在这种情况下,我们必须输入四个反斜杠!字符串解析器会将每个双倍反斜杠转换为单个反斜杠,而我们希望正则表达式编译器看到两个反斜杠。使用原始字符串更容易!

此外,您最初的模式将删除零个或多个十六进制数字。我的模式删除一个或多个。但我认为很可能恰好有两个十六进制数字,或者也许有四个Unicode。您应该确定有多少个,并放置一个确保这一点的模式。以下是匹配2、3或4个十六进制数字的模式:

escape_char = re.compile(r'\\x[0123456789abcdef]{2,4}')

这是一个精确匹配两个或四个的正则表达式。我们需要使用竖线来表示两个选项,还需要用括号创建一个组。这里我使用了非捕获组,使用(?:pattern)而不是(pattern)(其中pattern表示模式,而不是字面意义上的单词“pattern”)。
escape_char = re.compile(r'\\x(?:[0123456789abcdef]{2,2}|[0123456789abcdef]{4,4})')

以下是示例代码。点序列紧随着1字符,这个模式会保留它不变。

import re

s = r'+\x011+'
pat = re.compile(r'\\x(?:[0123456789abcdef]{2,2}|[0123456789abcdef]{4,4})')
s = pat.sub("@", s)
print("Result: '%s'" % s)

这将打印出:结果:'+@1+'

注意:这一切都是假设您实际上正在尝试匹配一个反斜杠字符后跟十六进制字符。 如果您实际上正在尝试匹配可能是“可打印”字符的字符字节值,则请使用@nneonneo提供的答案而不是此答案。


1
如果您正在使用8位字符值,则可以通过事先构建一些简单的表格,并与 str.translate() 方法结合使用,非常快速和轻松地删除字符串中不需要的字符,从而避免使用正则表达式:
import random
import string

allords = [i for i in xrange(256)]
allchars = ''.join(chr(i) for i in allords)
printableords = [ord(ch) for ch in string.printable]
deletechars = ''.join(chr(i) for i in xrange(256) if i not in printableords)

test = ''.join(chr(random.choice(allords)) for _ in xrange(10, 40)) # random string
print test.translate(allchars, deletechars)

0

声望不足,无法发表评论,但是被接受的答案也会删除可打印字符。

s = "pörféct änßwer"
re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\xff]', '', s)
'prfct nwer'

针对非英语字符串,请使用答案 https://dev59.com/1XVD5IYBdhLWcg3wGHeu#62530464

import unicodedata
''.join(c for c in s if not unicodedata.category(c).startswith('C'))
'pörféct änßwer'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接