4

我是 python 新手。我得到一个包含大约 2000 个文本文件的文件夹。我应该输出每个单词及其出现的次数(在文件中不重复)。例如,句子:“i am what i am”必须在文件中仅包含一次“i”。

我可以为单个文件执行此操作,但如何为多个文件执行此操作?

from collections import Counter
import re

def openfile(filename):
    fh = open(filename, "r+")
    str = fh.read()
    fh.close()
    return str

def removegarbage(str):
    # Replace one or more non-word (non-alphanumeric) chars with a space
    str = re.sub(r'\W+', ' ', str)
    str = str.lower()
    return str

def getwordbins(words):
    cnt = Counter()
    for word in words:
        cnt[word] += 1
    return cnt

def main(filename, topwords):
    txt = openfile(filename)
    txt = removegarbage(txt)
    words = txt.split(' ')
    bins = getwordbins(words)
    for key, value in bins.most_common(topwords):
        print key,value

main('speech.txt', 500)
4

4 回答 4

5

glob()您可以使用模块中的origlob()函数获取文件列表glob。我注意到您没有Counter有效地使用该对象。最好只调用它的update()方法并将单词列表传递给它。这是您的代码的简化版本,它处理*.txt在指定文件夹中找到的所有文件:

from collections import Counter
from glob import iglob
import re
import os

def remove_garbage(text):
    """Replace non-word (non-alphanumeric) chars in text with spaces,
       then convert and return a lowercase version of the result.
    """
    text = re.sub(r'\W+', ' ', text)
    text = text.lower()
    return text

topwords = 100
folderpath = 'path/to/directory'
counter = Counter()
for filepath in iglob(os.path.join(folderpath, '*.txt')):
    with open(filepath) as file:
        counter.update(remove_garbage(file.read()).split())

for word, count in counter.most_common(topwords):
    print('{}: {}'.format(count, word))
于 2013-06-08T10:06:28.790 回答
2

os.listdir(),它会给你一个目录中所有条目的列表。

http://docs.python.org/2/library/os.html#os.listdir

于 2013-06-08T07:33:07.270 回答
2

如果我的解释正确,您想为每个单词计算包含该单词的文件数。这是你可以做的。

对于每个文件,获取该文件中的一组单词(即单词应该是唯一的)。然后,对于每个字数,可以找到它的集合数。

这是我的建议:

  1. 循环遍历目标目录中的所有文件。您可以os.listdir用于此目的。
  2. 制作一组在此文件中找到的单词:

    with open(filepath, 'r') as f:
        txt = removegarbage(f.read())
        words = set(txt.split())
    
  3. 现在,当您在每个文件中都有一组单词时,您终于可以使用Counter这些单词了。最好使用它的update方法。这是一个小演示:

    >>> a = set("hello Python world hello".split())
    >>> a
    {'Python', 'world', 'hello'}
    >>> b = set("foobar hello world".split())
    >>> b
    {'foobar', 'hello', 'world'}
    >>> c = Counter()
    >>> c.update(a)
    >>> c.update(b)
    >>> c
    Counter({'world': 2, 'hello': 2, 'Python': 1, 'foobar': 1})
    
于 2013-06-08T07:49:45.210 回答
0

所以你可能会做一些类似的事情:

#!python
from __future__ import print_function
# Your code here
# ...
#

if __name__ == '__main__':
    import sys

    top=500

    if len(sys.argv) < 2:
        print ("Must supply a list of files to operate on", file=sys.stderr)
        ## For Python versions older than 2.7 use print >> sys.stderr, "..."
        sys.exit(1)

    for each in sys.argv[1:]:
        main(each, top)

请注意,我展示了一种包装现有函数的简单方法,以便您可以使用任意数量的文件名参数调用程序。如果你愿意,你也可以只使用一个指向目录的参数(你想要处理所有文件的目录:

#!python
from __future__ import print_function
# Your code here
# ...
# 
if __name__ == '__main__':
    import sys

    top = 500

    if len(sys.argv) != 2:
        ## Require exactly one argument: sys.argv[0] is our own executable filename
        ## (Similarly to how class methods are called with "self" as their first
        ## argument, but on the OS layer)
        print ("Must supply directory name full of files to be processed", file=sys.stderr)
        sys.exit(1)
    for each in os.listdir(sys.argv[1]):
        main(each, top)

您可以选择许多其他方式来处理您的参数、硬编码默认参数等。我将让您想象如何将“top”从硬编码值更改为命令行参数。为了获得额外的功劳,使用 option/arg 解析模块( argparseoptparse )使其成为具有默认值的命令行开关。

请注意,此if __name__ == ....业务是 Python 约定,它通过鼓励您将功能与操作分开来促进良好的编程实践。因此,您的所有功能都可以在该if __name__ == '__main__':行之上定义,并且您的脚本执行的所有操作(使用该功能)都可以在它之后调用。这允许您的文件被其他程序用作模块,同时仍然允许它拥有自己的实用程序作为自己的程序。(这是一个几乎是 Python 独有的特性,尽管 Ruby 实现了一组相似的语义,但语法略有不同)。

这些__future__东西允许您使用 Python 2.7 编写程序,该程序使用print与 Python 3.x 兼容的语义。这对于最终过渡到 Python 3 以及讨论该语言很有用,因此我们可以逐步淘汰旧的“print”作为语句并促进“print()”函数的使用。如果您不关心细节,请不要担心。只要意识到差异是普遍存在的,必须大多是次要的。您将看到的绝大多数示例都使用旧的打印语义,并且您将希望使用更新的、稍微不兼容的语义。

(注意:在我最初的帖子中,我from __future__ import在该__main__部分中有。特别是那行不通(并且通常 Python__future__导入应该在任何其他代码之前发生)。[我基本上是在试图传达这个想法并且不想要陷入 Python2.x 和 Python3 打印语义之间的差异。

于 2013-06-08T08:40:46.957 回答