我正在阅读文本文件中的单词,并将它们与一组单词进行比较,以查看它们在样本文档中出现的次数。例如,我有一个文本文件,我想看看“工程师”这个词出现多少次。
问题是,对于我的示例数据,字符串比较不起作用。我看到该程序确实正在阅读看起来像“工程师”的<type 'str'>
的单词;然而,没有比赛。使用ord(character)
打印单词中每个字符的ASCII时,每个字符之间似乎都有0。字符串“engineer”的输出如下所示:
0 101 0 110 0 103 0 105 0 110 0 101 0 101 0 114 0
使用strip()
删除开头和结尾0,但不删除中间的0。有关这些字符串的格式以及如何解决这些问题的想法吗?
我正在使用Python 2.7。
答案 0 :(得分:2)
这是字符串engineer
的{{3}}编码。 1
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中,有两种方法可以执行此操作:UTF-16-BE或codecs.open
。使用codecs
使您的代码更容易移植到Python 2.5,使用io
使得移植到3.x更容易,但是在这样的简单情况下它没有区别
请注意,您的line
字符串现在为unicode
而不是str
,因此理想情况下,您希望您的搜索字符串集合也为unicode
值。< / p>
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
字节,并且不会剥离{{ 1}}开头的字节。这只是处理编码字节的许多方法之一,而不是处理Unicode。如果您的最终输出将涉及,例如,将这些字符串打印到您的控制台或将它们写入UTF-8文件,它将变得更加痛苦。如果最终输出将是另一个UTF-16-BE文件,并且如果保存一点CPU非常重要,那么这样做可能是值得的。但除此之外,我会选择第一个。
<子> 1。实际上,你最后还有一个额外的\0
。但可能在您的真实数据中,这实际上是下一个字符的第一个字节 - 也许是\0
,在UTF-16-BE中,当然看起来像\n
。
答案 1 :(得分:-1)
看起来像正则表达式库https://docs.python.org/3/library/re.html的工作。匹配合适的正则表达式以获得每行的命中数。添加em以获取文件级别:
pattern = re.compile("engine")
len(pattern.findall("engine engineers love engineering"))
>>>
3