Python 将字符串中的所有数字替换为星号(长文讲解)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

在编程和数据处理中,将字符串中的敏感数字替换为星号是一个常见的需求。例如,在用户注册时隐藏身份证号、银行卡号等信息,或是在日志脱敏场景中保护隐私数据。本文将深入探讨如何用 Python 实现这一功能,并通过不同方法对比、代码示例和实际案例,帮助读者理解其核心原理与应用场景。


一、字符串基础与替换逻辑

字符串的不可变性

Python 中的字符串是不可变对象,这意味着对字符串的任何修改都会生成新的字符串。例如:

original = "Hello123"  
new_str = original.replace("123", "***")  
print(new_str)  # 输出 "Hello***"  

这里的 replace() 方法会创建新字符串,而非直接修改原字符串。

直接替换的局限性

若需替换所有数字,逐个字符替换会更灵活。例如:

text = "Password1234"  
result = ""  
for char in text:  
    if char.isdigit():  # 判断是否为数字  
        result += "*"  
    else:  
        result += char  
print(result)  # 输出 "Password****"  

此方法逐个检查字符,但效率较低,尤其在处理长字符串时可能不够高效。


二、正则表达式(Regex)的灵活应用

正则表达式简介

正则表达式是文本模式匹配的利器,可以高效定位并替换字符串中的特定模式。在 Python 中,re 模块提供了正则表达式功能。

核心语法

  • \d:匹配任意单个数字(0-9)。
  • +:匹配前一个字符 1 次或多次。
  • re.sub(pattern, replacement, string):替换匹配到的内容。

实现数字替换的代码示例

import re  

def replace_numbers_with_asterisks(text):  
    return re.sub(r"\d+", "*", text)  

print(replace_numbers_with_asterisks("Phone: 123-456-7890"))  # 输出 "Phone: *-*-*"  
print(replace_numbers_with_asterisks("Year2023"))             # 输出 "Year*"  

问题与优化
上述代码将连续数字替换为单个星号,若需替换为与原数字长度相同的星号(例如 123***),可使用回调函数:

def replace_with_same_length(match):  
    return "*" * len(match.group())  

def precise_replace(text):  
    return re.sub(r"\d+", replace_with_same_length, text)  

print(precise_replace("ID: 123456"))  # 输出 "ID: ******"  

三、进阶方法与代码优化

方法 1:使用 re.compile() 提升性能

若需多次调用正则表达式,预编译模式可减少重复解析开销:

import re  

pattern = re.compile(r"\d+")  

def optimized_replace(text):  
    return pattern.sub("*", text)  

for _ in range(1000):  
    optimized_replace("Test123")  

方法 2:列表推导式与 join() 组合

通过遍历字符并组合新字符串,代码更简洁:

def list_comprehension_approach(text):  
    return "".join(["*" if c.isdigit() else c for c in text])  

print(list_comprehension_approach("2023 is the year"))  # 输出 "** is the year"  

方法 3:处理 Unicode 数字(可选)

若需支持 Unicode 数字(如罗马数字、汉字数字),可扩展匹配模式:

def replace_unicode_numbers(text):  
    return re.sub(r"[\d\u0660-\u0669\u0e50-\u0e59]+", "*", text)  

print(replace_unicode_numbers("泰语数字:๑๒๓"))  # 输出 "泰语数字:***"  

四、性能对比与场景选择

不同方法的效率测试

通过 timeit 模块对比三种方法:

import timeit  

test_str = "a1b2c3d4e5" * 1000  

def method1(text):  
    return re.sub(r"\d+", "*", text)  

def method2(text):  
    return "".join(["*" if c.isdigit() else c for c in text])  

def method3(text):  
    return re.sub(r"\d+", "*", text, flags=re.ASCII)  

print("Method1:", timeit.timeit(lambda: method1(test_str), number=1000))  
print("Method2:", timeit.timeit(lambda: method2(test_str), number=1000))  
print("Method3:", timeit.timeit(lambda: method3(test_str), number=1000))  

常见结果

  • 正则表达式(Method1)通常最快,因其底层用 C 实现。
  • 列表推导式(Method2)次之,适合简单场景。
  • 若需禁用 Unicode 支持(如纯 ASCII 字符),可添加 re.ASCII 标志加速(Method3)。

场景选择建议

场景需求推荐方法优势与适用性
基础替换(简单字符串)列表推导式或直接循环代码直观,适合新手理解
高效处理长字符串正则表达式(re.sub()底层优化,速度最快
需保留数字长度回调函数 + 正则表达式精确控制替换后的星号数量
多语言/Unicode 支持自定义 Unicode 正则模式扩展匹配范围,但需注意性能影响

五、实际案例与扩展应用

案例 1:日志脱敏

假设日志内容包含用户 ID 和订单号:

def log_sanitizer(log_entry):  
    return re.sub(r"\b\d{4,}\b", "****", log_entry)  

print(log_sanitizer("User 123456 logged in. Order #7890123 processed."))  

此方法通过 \b 匹配单词边界,避免替换非数字内容。

案例 2:密码强度验证中的替换

在密码设置时隐藏部分字符:

def hide_password_chars(password):  
    return re.sub(r"(?<=\w)\d(?=\w)|\d", "*", password)  

print(hide_password_chars("Pass123word"))  # 输出 "Pass**3word"  

此正则通过正向预查((?<=\w))和后向预查((?=\w))定位中间的数字,实现部分隐藏。


六、常见问题与解决方案

问题 1:替换后星号数量不足

原因:默认正则模式将连续数字视为一个整体替换为单个星号。
解决:使用回调函数或 re.finditer() 获取匹配位置:

def replace_with_length(text):  
    result = list(text)  
    for match in re.finditer(r"\d+", text):  
        start, end = match.span()  
        result[start:end] = ["*"] * (end - start)  
    return "".join(result)  

print(replace_with_length("1234"))  # 输出 "****"  

问题 2:特殊字符干扰

场景:字符串中存在类似数字的符号(如 ²)。
解决:通过 Unicode 范围或自定义模式精确匹配:

re.sub(r"[\d\u2460-\u24FF]+", "*", "测试①号:2²")  

七、结论

将字符串中的数字替换为星号是 Python 中一项实用技能,其核心在于理解字符串操作逻辑与正则表达式的灵活运用。通过本文的讲解,读者可以掌握:

  1. 字符串不可变性与基础替换方法;
  2. 正则表达式在模式匹配中的高效性;
  3. 不同场景下的代码优化技巧与性能对比。

无论是处理用户隐私数据、日志脱敏还是密码强度验证,这些方法都能提供灵活的解决方案。建议读者通过实际项目练习,进一步巩固对正则表达式和字符串操作的理解。


通过本文的学习,您已掌握了 Python 中字符串数字替换的核心技术。若需更复杂的数据处理需求,可进一步探索 re 模块的高级功能或第三方库(如 fuzzywuzzy),但基础方法的熟练运用仍是解决问题的第一步。

最新发布