9

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

我只想要文本,所以有什么办法可以删除这个转义序列。我做了这样的事情

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

但这不会删除转义序列

提前致谢。

4

3 回答 3

9

问题是这\xXX只是控制字符的表示,而不是字符本身。\x因此,除非您使用的repr是字符串,否则您无法真正匹配。

您可以使用字符类删除不可打印的字符:

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{|}~'
于 2013-02-18T22:20:23.970 回答
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)

这打印:Result: '+@1+'

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

于 2013-02-18T22:06:42.393 回答
1

如果您正在使用 8 位 char 值,则可以通过预先构建一些简单的表来放弃正则表达式,然后将它们与方法结合使用以非常快速轻松地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)
于 2013-02-18T23:14:12.600 回答