Python 使用正则表达式从字符串中提取所有数字(长文解析)

为什么我们需要从字符串中提取数字?

在实际的编程场景中,字符串处理是一个非常常见的任务。尤其是在处理用户输入、日志分析、数据清洗等任务时,我们常常会遇到一个需求:从一段混杂的字符串中提取出所有的数字。例如,假设你有一个订单号如 "订单号:20230815-987654",你想从中提取出 20230815987654 两个数字,用于后续的处理或验证。

这时候,正则表达式(Regular Expression,简称 regex)就派上用场了。正则表达式是一种强大的文本匹配工具,能够根据特定的模式从字符串中提取我们需要的数据。在 Python 中,正则表达式主要通过 re 模块来实现。

正则表达式的基本概念

正则表达式是一门独立的语言,但 Python 对它的支持非常强大。简单来说,正则表达式就是一种描述字符串模式的规则。通过这些规则,我们可以完成字符串查找、替换、分割和提取等任务。

例如,\d 是一个正则表达式中的元字符,它表示任意一个数字字符。如果你写成 \d+,就表示匹配一个或多个连续的数字。这正是我们从字符串中提取所有数字的关键点。

Python 使用正则表达式从字符串中提取所有数字

Python 提供了 re.findall() 函数,可以用来查找所有与正则表达式匹配的内容。这个函数返回一个列表,里面包含所有匹配的子串。我们可以使用它来提取字符串中的所有数字。

以下是一个简单的例子:

import re

text = "今天天气不错,温度是25°C。订单号:20230815-987654。折扣是8折。"
numbers = re.findall(r'\d+', text)
print(numbers)  # 输出:['25', '20230815', '987654', '8']

在这个例子中,我们使用了 \d+ 作为正则表达式,表示匹配所有连续的数字。re.findall() 会遍历整个字符串,并将所有符合这个模式的数字提取出来。

为什么要使用 re.findall?

相比 re.search()re.match()re.findall() 更适合完成“提取所有匹配项”的任务。re.search() 会返回第一个匹配结果,而 re.match() 只匹配字符串的开头部分。如果你想提取所有数字,re.findall() 是最直接的方法。

正则表达式的更多用途

正则表达式不仅可以提取数字,还能处理更复杂的情况,比如只提取整数、提取带小数点的数字,或者提取固定长度的数字。我们将在下文中详细介绍这些用法。

提取所有数字的常见正则表达式写法

在实际开发中,我们可能会遇到各种不同的数字格式,因此需要针对不同的情况进行正则表达式的调整。以下是一些常见的情况和对应的写法:

提取所有整数

import re

text = "收入:12000,支出:-3000,利润:9000"
numbers = re.findall(r'\d+', text)
print(numbers)  # 输出:['12000', '3000', '9000']

注意:这种写法会忽略负号 -。如果你想提取负数,可以使用更复杂的正则表达式。

提取所有正负整数

import re

text = "收入:+12000,支出:-3000,利润:9000"
numbers = re.findall(r'[-+]?\d+', text)
print(numbers)  # 输出:['+12000', '-3000', '9000']

这里的 [-+]? 表示匹配一个可选的负号或正号,\d+ 表示匹配一个或多个数字。

提取小数和浮点数

import re

text = "价格:3.14,折扣:0.8,总价:1234.567"
numbers = re.findall(r'\d+\.\d+', text)
print(numbers)  # 输出:['3.14', '0.8', '1234.567']

这个正则表达式可以匹配类似 3.14 这样的浮点数,但无法处理像 3..14 这类不完整的数字格式。如果你需要支持这些格式,可以使用更复杂的模式。

实际案例:从文本中提取电话号码中的数字

有时候,我们需要从更复杂的文本中提取数字。例如,从一段包含电话号码、日期、金额等信息的文本中,提取出电话号码中的数字部分。

import re

text = "请拨打 (123) 456-7890 联系我们,或者发邮件到 info@example.com"
numbers = re.findall(r'\d+', text)
print(numbers)  # 输出:['123', '456', '7890']

虽然这个正则表达式提取了所有数字,但它也把日期或地址中的数字一并提取了出来。为了更精确地匹配电话号码,我们可以优化正则表达式:

import re

text = "请拨打 (123) 456-7890 联系我们,或者发邮件到 info@example.com"
numbers = re.findall(r'\d{3} \d{3}-\d{4}', text)
print(numbers)  # 输出:['123 456-7890']

这个正则表达式更精确地匹配了电话号码的格式。当然,电话号码的格式在全球范围内有所不同,但你可以根据自己的需求灵活调整正则表达式。

更进一步:提取多个电话号码

如果你的字符串中包含多个电话号码,正则表达式依然能够很好地处理:

import re

text = "电话1:(123) 456-7890,电话2:(456) 789-1234,电话3:(789) 123-4567"
numbers = re.findall(r'\d{3} \d{3}-\d{4}', text)
print(numbers)  # 输出:['123 456-7890', '456 789-1234', '789 123-4567']

这个例子展示了正则表达式在提取多个匹配项时的强大能力。

高级技巧:提取数字并转换为整数或浮点数

虽然 re.findall() 返回的是字符串列表,但我们通常需要将它们转换为整数或浮点数进行计算。以下是如何将提取到的字符串数字转换为整数和浮点数的示例:

转换为整数

import re

text = "收入:12000,支出:-3000,利润:9000"
numbers = re.findall(r'[-+]?\d+', text)
int_numbers = [int(num) for num in numbers]
print(int_numbers)  # 输出:[12000, -3000, 9000]

转换为浮点数

import re

text = "价格:3.14,折扣:0.8,总价:1234.567"
numbers = re.findall(r'\d+\.\d+', text)
float_numbers = [float(num) for num in numbers]
print(float_numbers)  # 输出:[3.14, 0.8, 1234.567]

这些转换操作非常常见,尤其在进行数据处理或分析时。正则表达式提取数字只是第一步,后续的类型转换才能真正发挥数字的价值。

多种数字格式的提取总结

数字类型 正则表达式 说明
所有整数 \d+ 匹配一个或多个数字
所有正负整数 [-+]?\d+ 匹配正号、负号或无符号的整数
所有小数 \d+\.\d+ 匹配小数点前后都有数字的格式
所有数字(包括小数点前后有空格的情况) \d+\.?\d* 匹配整数和小数,允许小数点后无数字

通过组合不同的正则表达式,你可以应对各种数字提取的需求。

常见错误和注意事项

在使用正则表达式提取数字时,初学者常犯的一些错误包括:

  • 忘记使用原始字符串(r''):在 Python 中,正则表达式建议使用原始字符串,避免转义字符的干扰。
  • 忽略负号或小数点:如上文提到的,如果你需要提取负数或小数,正则表达式必须包含这些符号。
  • 匹配到不相关的数字:比如在提取电话号码时,如果只用 \d+,可能会匹配到其他不相关的数字。
  • 未做类型转换:提取的数字是字符串,如果不转换类型,将无法进行数学计算。

如何避免这些错误?

  • 使用 r'\d+' 而不是 '\d+'
  • 根据实际需求选择合适的正则表达式;
  • 提取后使用 int()float() 转换类型;
  • 配合 re.sub() 清洗数据,确保提取的数字是干净的。

结论

在 Python 中使用正则表达式从字符串中提取所有数字,是一种非常高效且灵活的方式。通过 re.findall() 函数和合适的正则表达式,你可以快速提取出各种格式的数字,包括整数、负数和小数。当然,正则表达式的学习曲线稍高,但只要掌握了基本规则,就能在实际项目中游刃有余地处理各种字符串数据。

希望这篇文章能帮助你更好地理解 Python 使用正则表达式从字符串中提取所有数字的方法。在实际开发中,灵活运用这些技巧,将大大提升你处理文本数据的效率。