如何计算段落中的单词数并排除某些单词(来自文件)?
我刚开始学习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 个回答
也许我没有完全理解需求,但我会尽力而为。
关于计算所有单词的第一部分,整体还不错。我会稍微简化一下:
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)
就会产生一个清晰的错误信息。再读一遍,这肯定是你本来想表达的意思。)
你不应该用 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()
第一部分是没问题的,你成功地计算了总字数并打印了结果。
但你出错的地方在这里:
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'