好的,我们来聊聊如何在Python中从一段英文文本中找出所有不重复的单词。这是一个很常见的文本处理需求,我们可以用几种方法来完成,并且我会尽量把细节讲清楚,让这个过程尽可能地自然,就像我们自己一点点摸索出来的一样。
想象一下,你拿到一段英文,比如某篇博客文章、一本书的片段,或者朋友发来的邮件,你想知道这段文字里到底有多少“不一样”的词。不是总共的词,而是那些只出现过一次,或者说,每种词只算一个,我们想统计一下有多少种不同的词。
核心思路:
要挑出不重复的单词,最直接的想法就是:
1. 把文本分割成一个个单词。
2. 对这些单词进行“去重”处理。
听起来简单,但实现起来有一些小细节需要注意。
方法一:使用集合 (Set) – 最Pythonic、最优雅的方式
Python的`set`数据结构非常适合处理“唯一性”的问题。它的一个核心特性就是:集合里的元素是无重复的。如果你尝试往一个集合里添加一个已经存在的元素,它会直接忽略,不会报错,也不会改变集合本身。
步骤分解:
1. 获取文本: 首先,我们需要一段英文文本。可以是一行字符串,也可以是从文件读取的内容。
```python
假设这是我们拿到的一段英文文本
text = "This is a sample text. This text contains sample words, and sample is a common word."
```
2. 预处理文本(关键!): 原始文本里有很多东西是我们不想要的,比如:
标点符号: 句号(.)、逗号(,)、感叹号(!)、问号(?)等等,它们会“粘”在单词后面,导致“text.”和“text”被认为是不同的单词,这肯定不是我们想要的。
大小写: “This”和“this”在意思上是一样的,但如果不处理,它们会被当作两个不同的单词。
所以,我们需要做一些清理工作:
全部转为小写: 这是最简单有效的处理大小写的方法。
移除标点符号: 我们可以用几种方式移除标点。一种是遍历字符串,只保留字母和空格;另一种是使用更强大的字符串处理工具,比如`string.punctuation`和`str.translate()`,或者正则表达式。
让我们一步步来,用一个相对直观的方式:
```python
import string
1. 转为小写
text_lower = text.lower()
print(f"转小写后: {text_lower}")
输出: 转小写后: this is a sample text. this text contains sample words, and sample is a common word.
2. 移除标点符号
string.punctuation 包含了很多常见的标点符号
str.translate() 是一个高效移除字符的方法
创建一个转换表,将所有标点符号映射为 None (即删除)
translator = str.maketrans('', '', string.punctuation)
text_clean = text_lower.translate(translator)
print(f"移除标点后: {text_clean}")
输出: 移除标点后: this is a sample text this text contains sample words and sample is a common word
```
思考一下: 为什么`str.maketrans('', '', string.punctuation)`这样写?`maketrans`可以用来做字符的替换、删除或组合。前两个空字符串表示我们不做字符的一一对应替换,第三个参数`string.punctuation`则指定了要删除的所有字符。
3. 将文本分割成单词: 清理完文本后,我们就可以用空格作为分隔符,把字符串拆分成一个单词列表了。
```python
words = text_clean.split()
print(f"分割后的单词列表: {words}")
输出: 分割后的单词列表: ['this', 'is', 'a', 'sample', 'text', 'this', 'text', 'contains', 'sample', 'words', 'and', 'sample', 'is', 'a', 'common', 'word']
```
注意: `split()`方法默认会根据连续的空格来分割,并且会忽略掉开头和结尾的空格,这通常是我们想要的。
4. 利用集合进行去重: 现在,我们将这个单词列表转换为一个集合。Python会自动处理重复项。
```python
unique_words_set = set(words)
print(f"去重后的单词集合: {unique_words_set}")
输出: 去重后的单词集合: {'common', 'a', 'word', 'sample', 'this', 'text', 'is', 'contains', 'and', 'words'}
```
你看,集合里每个单词都只出现了一次!
5. 转换为列表(如果需要): 有时候,我们可能更喜欢一个列表形式的结果,而不是集合。集合是无序的,而列表是有序的(但这里的顺序取决于集合内部的哈希算法,并不是原始文本顺序)。
```python
unique_words_list = list(unique_words_set)
print(f"转换为列表后的不重复单词: {unique_words_list}")
输出: 转换为列表后的不重复单词: ['common', 'a', 'word', 'sample', 'this', 'text', 'is', 'contains', 'and', 'words']
```
代码整合:
```python
import string
def get_unique_words(text):
"""
从给定的英文文本中提取所有不重复的单词。
Args:
text: 包含英文文本的字符串。
Returns:
一个包含文本中所有不重复单词的列表。
"""
1. 将文本全部转为小写,以便大小写不敏感地处理
text_lower = text.lower()
2. 移除所有标点符号
string.punctuation 提供了常见的标点符号集合
maketrans 方法创建一个转换表,将标点符号映射为 None (即删除)
translator = str.maketrans('', '', string.punctuation)
text_clean = text_lower.translate(translator)
3. 使用空格作为分隔符将文本分割成单词列表
words = text_clean.split()
4. 将单词列表转换为集合,集合会自动去除重复的元素
unique_words_set = set(words)
5. 将集合转换回列表返回 (集合是无序的,列表的顺序也不是原始顺序)
return list(unique_words_set)
示例用法
sample_text = "This is a sample text. This text contains sample words, and sample is a common word. Is it?"
unique_words = get_unique_words(sample_text)
print("原始文本:")
print(sample_text)
print("
不重复的单词列表:")
print(unique_words)
```
优点:
简洁高效: Python的`set`就是为此而生,代码非常短小精悍。
易于理解: 集合的“唯一性”特性是它的核心,一旦理解了这一点,逻辑就很清晰。
性能好: 对于大型文本,集合的查找和插入操作通常比列表更有效率(接近O(1)的平均时间复杂度)。
方法二:使用列表和循环 – 更“手动”但理解更深入
虽然集合是首选,但我们也可以不直接使用集合,而是通过循环和另一个列表来手动实现去重。这能帮助我们更直观地理解“去重”这个过程。
步骤分解:
1. 预处理文本: 同方法一,先将文本转小写并移除标点。
2. 分割单词: 同方法一,得到单词列表。
3. 手动去重:
创建一个空的列表,用来存放不重复的单词。
遍历原始的单词列表。
对于列表中的每一个单词,检查它是否已经存在于我们用来存放不重复单词的那个新列表中。
如果不存在,就把它添加到新列表中。
如果已经存在,就跳过它。
代码实现:
```python
import string
def get_unique_words_manual(text):
"""
从给定的英文文本中提取所有不重复的单词,使用手动循环去重。
Args:
text: 包含英文文本的字符串。
Returns:
一个包含文本中所有不重复单词的列表。
"""
1. 文本预处理 (同方法一)
text_lower = text.lower()
translator = str.maketrans('', '', string.punctuation)
text_clean = text_lower.translate(translator)
2. 分割单词 (同方法一)
words = text_clean.split()
3. 手动去重
unique_words_list = [] 用来存放不重复的单词
for word in words:
检查当前单词是否已经存在于 unique_words_list 中
if word not in unique_words_list:
如果不存在,就添加到列表中
unique_words_list.append(word)
return unique_words_list
示例用法
sample_text = "This is a sample text. This text contains sample words, and sample is a common word. Is it?"
unique_words_manual = get_unique_words_manual(sample_text)
print("
手动去重方法 ")
print("原始文本:")
print(sample_text)
print("
不重复的单词列表:")
print(unique_words_manual)
```
思考与权衡:
`if word not in unique_words_list:` 这一步是关键。在Python中,`list.count(item)`和`item in list`的操作,对于列表来说,平均时间复杂度是O(n),也就是说,它需要遍历列表来查找。当`unique_words_list`变得越来越长时,每次检查都会花费更多时间。
性能: 对于非常大的文本,这种方法会比使用集合慢得多,因为每次添加单词前都要进行一次列表查找。
优点:
教学意义: 非常直观地展示了“去重”的逻辑,适合初学者理解。
保留顺序(部分): 这种方法会保留单词首次出现的顺序。例如,如果“apple”先出现,然后“banana”后出现,那么在结果列表里,“apple”会排在“banana”前面(只要它们都是不重复的)。集合是无序的,所以不能保证这个顺序。
方法三:使用 `collections.Counter` – 结合计数与去重
`collections.Counter` 是一个非常有用的工具,它实际上是一个字典的子类,用于计算可哈希对象的出现次数。虽然它的主要目的是计数,但它也间接帮助我们找出不重复的元素,并且可以很方便地获取到所有单词的列表。
步骤分解:
1. 预处理文本: 同方法一。
2. 分割单词: 同方法一。
3. 使用 `Counter`: 直接将单词列表传给 `Counter`。它会返回一个字典(或者像字典一样工作),键是单词,值是该单词出现的次数。
4. 提取不重复单词: `Counter` 对象本身就是“键”(即单词)的集合。我们可以直接获取它的键。
代码实现:
```python
import string
from collections import Counter
def get_unique_words_with_counter(text):
"""
从给定的英文文本中提取所有不重复的单词,使用 collections.Counter。
Args:
text: 包含英文文本的字符串。
Returns:
一个包含文本中所有不重复单词的列表。
"""
1. 文本预处理 (同方法一)
text_lower = text.lower()
translator = str.maketrans('', '', string.punctuation)
text_clean = text_lower.translate(translator)
2. 分割单词 (同方法一)
words = text_clean.split()
3. 使用 Counter 统计单词出现次数
word_counts = Counter(words)
print(f"Counter 结果: {word_counts}")
输出: Counter 结果: Counter({'sample': 3, 'this': 2, 'is': 2, 'a': 2, 'text': 2, 'common': 1, 'words': 1, 'and': 1, 'word': 1, 'it': 1})
4. Counter 的键就是所有不重复的单词
.keys() 返回一个视图对象,我们转换为列表
unique_words_list = list(word_counts.keys())
return unique_words_list
示例用法
sample_text = "This is a sample text. This text contains sample words, and sample is a common word. Is it?"
unique_words_counter = get_unique_words_with_counter(sample_text)
print("
Counter 方法 ")
print("原始文本:")
print(sample_text)
print("
不重复的单词列表:")
print(unique_words_counter)
```
思考:
`Counter` 在内部也是使用了字典来存储计数,所以获取键(不重复单词)的操作非常高效。
它也提供了很多方便的统计功能,比如 `most_common()`,如果你想知道哪些单词出现次数最多,那 `Counter` 就非常适合了。
优点:
功能全面: 不仅能找出不重复单词,还能轻松知道每个单词的频率。
效率高: 内部实现高效,与集合方法类似。
代码可读性好: 意图明确,“计算单词出现次数”本身就包含了“找出不重复单词”的含义。
进阶:使用正则表达式进行更精细的单词提取
上面的方法都是基于空格和简单的标点移除。但有时,文本可能包含连字符词(如“wellbeing”)、缩写(如“don't”)等,或者我们想更精确地定义“单词”。这时候,正则表达式就派上用场了。
思路:
定义一个模式,来匹配我们认为的“单词”。一个常见的模式是匹配连续的字母。
代码实现:
```python
import re 导入正则表达式模块
def get_unique_words_regex(text):
"""
从给定的英文文本中提取所有不重复的单词,使用正则表达式。
Args:
text: 包含英文文本的字符串。
Returns:
一个包含文本中所有不重复单词的列表。
"""
1. 将文本全部转为小写
text_lower = text.lower()
2. 使用正则表达式查找所有单词
表示单词边界,确保我们匹配的是完整的单词
[az]+ 匹配一个或多个小写字母
另一种常见的模式是 r"w+",它会匹配字母、数字和下划线
这里我们选择只匹配字母,更符合“单词”的定义,但也可以根据需求调整
words = re.findall(r'[az]+', text_lower)
print(f"Regex 找到的单词列表: {words}")
如果使用 r'[az]+'
输出: Regex 找到的单词列表: ['this', 'is', 'a', 'sample', 'text', 'this', 'text', 'contains', 'sample', 'words', 'and', 'sample', 'is', 'a', 'common', 'word', 'is', 'it']
注意:这里标点符号已经通过正则模式自动排除,无需额外translate
3. 使用集合去重
unique_words_set = set(words)
4. 转换为列表返回
return list(unique_words_set)
示例用法
sample_text = "This is a sample text. This text contains sample words, and sample is a common word. Is it? Wellbeing is important."
unique_words_regex = get_unique_words_regex(sample_text)
print("
Regex 方法 ")
print("原始文本:")
print(sample_text)
print("
不重复的单词列表:")
print(unique_words_regex)
```
思考:
`re.findall(r'[az]+', text_lower)`
`re.findall()`: 找到所有匹配模式的子串,并以列表形式返回。
`r''`: 表示这是一个原始字符串,避免反斜杠被解释。
``: 匹配一个单词边界。这很重要,比如它可以防止“text.”被匹配成“text”,因为它会在`.`之前停下。
`[az]+`: 匹配一个或多个小写字母。
优点:
灵活性高: 可以根据需要精确定义“单词”的构成(例如,允许数字、连字符等)。
一步到位: 在匹配单词的同时,就处理了标点和边界问题。
缺点:
学习曲线: 正则表达式对于初学者可能稍微复杂一些。
性能: 对于非常复杂的模式,正则表达式的性能可能会略低于简单的字符串操作,但通常来说,对于大多数常见的单词匹配,性能是足够的。
总结与建议
对于绝大多数情况,方法一(使用集合 `set`) 是最推荐的方式。它简洁、高效,并且充分利用了Python的特性。
如果你需要的是理解“去重”的底层逻辑,或者需要保持单词首次出现的顺序,那么方法二(手动循环) 值得一试,但要注意其在处理大数据集时的性能瓶颈。
如果你不仅想找出不重复的单词,还想知道它们的出现频率,那么方法三(`collections.Counter`) 是最佳选择。
如果你的文本处理需求更复杂,需要精确控制单词的定义(比如包含连字符、特定的符号组合等),那么方法四(正则表达式) 提供了最大的灵活性。
在实际应用中,你会根据具体场景选择最适合你的方法。核心步骤不变:文本清理 > 分割单词 > 去重。而`set`、`Counter`和`re`模块,都是Python为我们准备好的强大工具,善用它们能让你的代码事半功倍。