首页 > 解决方案 > 从文本文件python中读取字符串

问题描述

我正在从文本文件中读取单词并将它们与一组单词进行比较,以查看它们在示例文档中出现的次数。例如,我有一个文本文件,我想看看“工程师”这个词出现了多少次。

问题是对于我的示例数据,字符串比较不起作用。我看到程序确实在读一个<type 'str'>看起来像“工程师”的词;但是,没有匹配项。当使用 打印出单词中每个字符的 ASCII 时,每个字符ord(character)之间似乎都有 0。字符串“engineer”的输出如下所示:

0 101 0 110 0 103 0 105 0 110 0 101 0 101 0 114 0

使用strip()删除开头和结尾的 0,但不删除中间的。关于这些字符串的格式以及如何修复它有什么想法吗?

我正在使用 Python 2.7。

标签: python

解决方案


这是字符串的UTF-16-BE编码engineer1

UTF-16 对 BMP 字符(包括 ASCII 字符)使用两个字节,因此,例如,字符e,它是 Unicode(和 ASCII)字符编号 101(0x65 十六进制),显示为 16 位代码单元 101。 big-endian(这就是这-BE部分的意思),第一个字节是 0,第二个字节是 101。所以,如果你的文本是纯 ASCII,你的 UTF-16 最终看起来像 ASCII,\0每个字符前都有一个额外的字节。


解决此问题的最简洁方法是将文件作为 Unicode 文件打开。作为一般规则,如果您将所有内容解码unicode为读取它的一部分,仅在最后编码回字节作为写入它的一部分,并在中间完成所有工作,那么unicode一切都会更简单。

在 Python 2.7 中,有两种方法可以做到这一点,codecs.open或者io.open. Usingcodecs使您的代码更容易移植到 Python 2.5,usingio使移植到 3.x 更容易一些,但在像这样的简单情况下并没有什么不同。

请注意,您的line字符串现在将unicode代替str,因此理想情况下,您希望您的搜索字符串集也是unicode值。

d = {u'engineer': 0, u'conductor': 0, u'transit cop': 0}
with io.open(path, encoding='utf-16-be') as f:
    for line in f:
        try:
            d[line.strip()] += 1
        except KeyError:
            pass

另一种选择是将文件作为二进制 UTF-16-BE 读取,并将搜索字符串设为 UTF-16-BE 编码str值:

d = {u'engineer': 0, u'conductor': 0, u'transit cop': 0}
d = {key.encode('utf-16-be'): count for key, count in d.items()}
with open(path) as f:
    for line in f:
        try:
            d[line.rstrip('\n\0')] += 1
        except KeyError:
            pass

请注意,我必须小心剥离,以确保\0\n在末尾删除整个两个字节而不是仅删除\n字节,并且不要\0在开始时删除字节。这只是处理编码字节比处理 Unicode 更痛苦的众多方式之一。而且,如果您的最终输出涉及将这些字符串打印到控制台或将它们写入 UTF-8 文件,那将变得更加痛苦。如果最终输出将是另一个 UTF-16-BE 文件,并且如果节省一点 CPU 真的很重要,那么这样做可能是值得的。但除此之外,我会选择第一个。


1. 实际上,最后你有一个额外\0的。但大概在你的真实数据中,这实际上是下一个字符的第一个字节——可能是\n,在 UTF-16-BE 中,它当然看起来像\0\n


推荐阅读