如何计算段落中的单词数并排除某些单词(来自文件)?

3 投票
3 回答
11977 浏览
提问于 2025-04-17 01:52

我刚开始学习Python,所以我的问题可能有点傻。我的目标是创建一个程序,具体功能包括:


  • 导入一个文本文件(这个我搞定了)
  • 统计总的单词数(这个我也搞定了)
  • 统计某个特定段落中的单词数,这个段落是从一个特定的短语开始(比如“P1”),以另一个参与者“P2”结束,并且要把这些单词从我的总单词数中排除。结果我搞出来的却是统计字符数,而不是单词数 :/
  • 单独打印每个段落(这个我也搞定了)
  • 把“P1”、“P2”等的单词从我的总单词数中排除。

我的文本文件大概是这样的:


P1: 啦啦啦。
P2: 啦啦啦啦。
P1: 啦啦。
P3: 啦。

我最后写出了这样的代码:

text = open (r'C:/data.txt', 'r')
lines = list(text)
text.close()
words_all = 0
for line in lines:
    words_all = words_all + len(line.split())
print 'Total words:   ', words_all

words_par = 0
for words_par in lines:
    if words_par.startswith("P1" or "P2" or "P3") & words_par.endswith("P1" or "P2" or "P3"):
        words_par = line.split()
    print len(words_par)
    print words_par.replace('P1', '') #doesn't display it but still counts
else:
    print 'No words'

有没有什么建议可以改进它?

谢谢!

3 个回答

2

也许我没有完全理解需求,但我会尽力而为。

关于计算所有单词的第一部分,整体还不错。我会稍微简化一下:

with open('C:/data.txt', 'r') as textfile:
    lines = list(textfile)
words_all = sum([len(line.split()) for line in lines])
print 'Total words:   ', words_all

在第二部分,似乎出现了一些问题。

words_par = 0 # You can leave out this line,
              # 'words_par' is initialized in the for-statement

这里还有更多问题:

    if words_par.startswith("P1" or "P2" or "P3") & words_par.endswith("P1" or "P2" or "P3"):

"P1" 或 "P2" 或 "P3" 这个表达式的结果是 "P1"(非空字符串被认为是“真”值)。所以你可以把这一行简化为

    if words_par.startswith("P1") & words_par.endswith("P1"):

这可能不是你想要的结果。
当条件判断为 False 时,split 方法不会被调用,words_par 仍然是一个字符串(而不是你期待的字符串列表)。所以 len(words_par) 返回的是字符的数量,而不是单词的数量。

(稍微偏离一下话题:在我看来,这个错误是因为变量命名不准确导致的。如果命名不同的话,

for line in lines:
    if line.startswith(...:
        words_par = line.split()
    print len(words_par)

就会产生一个清晰的错误信息。再读一遍,这肯定是你本来想表达的意思。)

2

你不应该用 open ('zery.txt', 'r') 来调用标识符 text。这个标识符不是文件里的文本,而是文件的处理器,在文档中被称为“类似文件的对象”(顺便说一下,我从来没搞懂“类似文件的对象”是什么意思)。

.

with open ('C:/data.txt', 'r')  as f:
    ........
    ........

比起这个,

f = open ('C:/data.txt', 'r') 
    ......
    .....
f.close()

更好。

你应该看看关于 split() 的说明,这样你会发现你可以这样做:

with open ('C:/data.txt', 'r') as f:
    text = f.read()
words_all = len(text.split())
print 'Total words:   ', words_all

.

如果你的文本结构是:

P1: Bla bla bla. 
P2: Bla bla bla bla. 
P1: Bla bla. 
P3: Bla.

那么 words_par.endswith("P1" or "P2" or "P3") 永远会是 False,因此你想要的分割不会发生。

所以,words_par 不会变成一个列表,它仍然是一个字符串,这就是为什么字符会被计数。

.

另外,你的代码肯定是错的。

如果分割真的发生了,那么在代码开头的第一个循环中得到的最后一行会被反复分割。

所以,应该是:

for words_par in lines: 
    if words_par.startswith("P1" or "P2" or "P3"):
        words_par = line.split() 

而不是:

for line in lines: 
    if line[0:2] in ("P1","P2","P3") :
        words_par = line.split() 
2

第一部分是没问题的,你成功地计算了总字数并打印了结果。

但你出错的地方在这里:

words_par = 0
for words_par in lines:
    if words_par.startswith("P1" or "P2" or "P3") & words_par.endswith("P1" or "P2" or "P3"):
        words_par = line.split()
    print len(words_par)
    print words_par.replace('P1', '') #doesn't display it but still counts
else:
    print 'No words'

words_par 最开始是一个字符串,包含了文件中的一行内容。在一个永远不会满足的条件下,它被转换成了一个列表,使用了

line.split()

这个表达式。如果这个表达式

words_par.startswith("P1" or "P2" or "P3") & words_par.endswith("P1" or "P2" or "P3")

有可能返回 True,那么它总是会分割你文件的最后一行,因为它最后一次被赋值是在程序的第一部分,那时你计算了文件中的总字数。实际上应该是

words_par.split()

另外,

words_par.startswith("P1" or "P2" or "P3")

总是会是

words_par.startswith("P1")

因为

"P1" or "P2" or "P3"

总是会评估为第一个,也就是在这个情况下的第一个字符串。如果你想了解更多,可以看看 http://docs.python.org/reference/expressions.html

顺便提一下,除非你想进行位运算比较,否则最好避免使用

something & something

而是使用

something and something

第一个会无论如何都评估两个表达式,而第二个只有在第一个为 True 时才会评估第二个表达式。如果你这样做,你的代码会运行得更高效一些。

接下来这一行

print len(words_par)

总是会计算这一行中的字符数,因为 if 语句总是会评估为 False,而 word_par 从未被分割成一个单词列表。

而且,for 循环中的 else 子句无论序列是否为空都会被执行。想了解更多信息,可以查看 http://docs.python.org/reference/compound_stmts.html#the-for-statement

我写了一个我认为符合你需求的版本,作为示例。为了保持简单,我避免使用像列表推导式这样的东西,因为你说你刚开始学习,所以这不是最优的,但希望能让你明白。此外,我没有添加注释,所以如果有不明白的地方,随时可以问我。

words = None
with open('data.txt') as f:
    words = f.read().split()
total_words = len(words)
print 'Total words:', total_words

in_para = False
para_count = 0
para_type = None
paragraph = list()
for word in words:
  if ('P1' in word or
      'P2' in word or
      'P3' in word ):
      if in_para == False:
         in_para = True
         para_type = word
      else:
         print 'Words in paragraph', para_type, ':', para_count
         print ' '.join(paragraph)
         para_count = 0
         del paragraph[:]
         para_type = word
  else:
    paragraph.append(word)
    para_count += 1
else:
  if in_para == True:
    print 'Words in last paragraph', para_type, ':', para_count
    print ' '.join(paragraph)
  else:
    print 'No words'

编辑:

我刚刚注意到示例中有一些多余的代码。变量 para_count 是不需要的,因为单词已经被添加到段落变量中了。所以可以直接这样做:

print 'Words in paragraph', para_type, ':', para_count

这样就少了一个需要跟踪的变量。以下是修正后的代码片段。

print 'Words in paragraph', para_type, ':', len(paragraph)

这里是修正后的代码片段。

in_para = False
para_type = None
paragraph = list()
for word in words:
  if ('P1' in word or
      'P2' in word or
      'P3' in word ):
      if in_para == False:
         in_para = True
         para_type = word
      else:
         print 'Words in paragraph', para_type, ':', len(paragraph)
         print ' '.join(paragraph)
         del paragraph[:]
         para_type = word
  else:
    paragraph.append(word)
else:
  if in_para == True:
    print 'Words in last paragraph', para_type, ':', len(paragraph)
    print ' '.join(paragraph)
  else:
    print 'No words'

撰写回答