前言
本文深入探讨python字符串处理核心方法与正则表达式实战技巧,涵盖字符串编码转换、分割替换、正则表达式语法精髓,并通过日志解析、数据清洗等真实场景案例展示高阶应用。最后提供10道阶梯式练习题(附完整答案代码),助你从基础到进阶全面掌握文本处理技能。
一、字符串处理核心三剑客
1.1 编码转换(encode/decode)
text = "中文文本"
utf8_bytes = text.encode('utf-8') # 转为utf-8字节流
gbk_str = utf8_bytes.decode('utf-8').encode('gbk', errors='replace') # 转gbk编码
print(gbk_str.decode('gbk', errors='ignore')) # 输出:中文文本
注意:处理多语言文本时需统一编码格式,errors参数可指定处理非法字符策略(replace/ignore)
1.2 智能分割(split)
csv_line = "2023-07-25,192.168.1.1,get /api/data,200"
# 分割时处理多余空格
parts = [x.strip() for x in csv_line.split(',', maxsplit=3)]
print(parts) # ['2023-07-25', '192.168.1.1', 'get /api/data', '200']
进阶:rsplit()反向分割,partition()三段式分割
1.3 灵活替换(replace)
text = "python2 is outdated, but python2 code still exists"
new_text = text.replace("python2", "python3", 1) # 仅替换第一个匹配项
print(new_text) # "python3 is outdated, but python2 code still exists"
局限:无法处理模式匹配,需正则表达式进阶处理
二、正则表达式深度解析
2.1 re模块核心方法
import re
# 预编译提升性能(重要!)
phone_pattern = re.compile(r'(\+86)?1[3-9]\d{9}')
text = "联系方式:+8613812345678,备用号15812345678"
matches = phone_pattern.findall(text)
print(matches) # ['+86', ''] 分组匹配结果
2.2 正则语法精要
- 分组捕获:
(pattern)vs(?:pattern)(非捕获分组) - 贪婪控制:
.*?非贪婪匹配 vs.*贪婪匹配 - 断言魔法:
(?=...)正向肯定断言,(?<!...)逆向否定断言
三、真实场景实战案例
3.1 日志解析(apache日志)
log_line = '127.0.0.1 - - [25/jul/2023:15:30:22 +0800] "get /index.html http/1.1" 200 2326'
pattern = r'''
^(\d+\.\d+\.\d+\.\d+)\s+ # ip地址
([\w-]+)\s+ # 用户标识
([\w-]+)\s+ # 认证用户
\[(.*?)\]\s+ # 时间戳
"(.*?)\s+(.*?)\s+http/(\d\.\d)" # 请求信息
\s+(\d{3})\s+ # 状态码
(\d+) # 响应大小
'''
match = re.compile(pattern, re.x).search(log_line)
if match:
print(f"ip: {match.group(1)}, 状态码: {match.group(8)}")
3.2 数据清洗实战
def clean_html(raw):
# 删除html标签但保留内容
cleaner = re.compile(r'<[^>]+>| | |\n')
# 合并连续空格
return re.sub(r'\s{2,}', ' ', cleaner.sub(' ', raw))
dirty_html = "<p>hello world!</p>
"
print(clean_html(dirty_html)) # "hello world! "
四、进阶练习题与答案
练习题(10题)
- 提取嵌套json字符串中的特定字段(忽略转义引号)
- 验证复杂密码规则(大小写+数字+特殊符号,8-20位)
- 中英文混合文本分词处理
- 高效提取海量文本中所有url
- 转换日期格式(mm/dd/yyyy到yyyy-mm-dd)
- 识别并高亮sql注入特征
- 多模式匹配优化(使用正则字典)
- 解析非标准csv(含逗号字段)
- 多层级日志时间戳转换
- 构建简易模板引擎
以下是10个练习题的完整实现代码,每个解决方案均包含详细注释说明:
题1:提取嵌套json字符串中的特定字段(忽略转义引号)
import re
import json
def extract_json_field(json_str, target_field):
"""
提取json字符串中指定字段的值(处理转义引号)
:param json_str: 原始json字符串
:param target_field: 要提取的字段名
:return: 匹配值列表
"""
# 匹配字段值:字符串、数字、布尔、null
pattern = re.compile(
rf'"{target_field}"\s*:\s*("(?:\\"|[^"])*"|-?\d+\.?\d*|true|false|null)',
re.ignorecase
)
return [json.loads(m.group(1)) if m.group(1).startswith('"')
else eval(m.group(1))
for m in pattern.finditer(json_str)]
# 测试用例
sample_json = '''
{"user": "alice", "data": "{\\"info\\": \\"secret\\"}", "age": 25}
'''
print(extract_json_field(sample_json, "data")) # 输出: ['{"info": "secret"}']
关键点:正则处理转义引号\\",使用json.loads解析字符串值
题2:验证复杂密码规则(大小写+数字+特殊符号,8-20位)
import re
def validate_password(password):
"""
验证密码复杂度:
- 至少1个大写字母
- 至少1个小写字母
- 至少1个数字
- 至少1个特殊符号(!@#$%^&*)
- 长度8-20
"""
pattern = re.compile(
r'^(?=.*[a-z])(?=.*[a-z])(?=.*\d)(?=.*[!@#$%^&*])[\w!@#$%^&*]{8,20}$'
)
return bool(pattern.fullmatch(password))
# 测试
print(validate_password("abc123#")) # false(长度不足)
print(validate_password("abcdefg123!")) # true
技巧:使用正向肯定断言(?=)确保各类型存在
题3:中英文混合文本分词
def split_chinese_english(text):
"""
中英文分词:中文按字分割,英文按单词分割
"""
return re.findall(r'\b\w+\b|[\u4e00-\u9fa5]', text)
# 测试
sample = "hello世界!python 代码 2023"
print(split_chinese_english(sample)) # ['hello世界', 'python', '代码', '2023'] 由于\w+匹配的是单词,而hello世界是 连在一起的并非单词所以 没有达到分词的效果
def split_chinese_english(text):
"""
中英文分词:中文按字分割,英文按单词分割
"""
pattern = r'[a-za-z0-9]+|[\u4e00-\u9fa5]'
return re.findall(pattern, text)
# 测试
sample = "hello世界!python代码2023"
print(split_chinese_english(sample)) # ['hello', '世', '界', 'python', '代', '码', '2023']
def split_chinese_english(text):
# 先将英文和数字部分提取出来
english_num_pattern = re.compile(r'[a-za-z0-9]+')
english_num_matches = english_num_pattern.findall(text)
# 去除英文和数字部分,只保留中文和其他字符
chinese_text = english_num_pattern.sub('', text)
# 对中文部分进行分词
chinese_words = jieba.lcut(chinese_text)
result = []
index = 0
for char in text:
if re.match(r'[a-za-z0-9]', char):
if index < len(english_num_matches) and text.startswith(english_num_matches[index], text.index(char)):
result.append(english_num_matches[index])
index += 1
elif char in ''.join(chinese_words):
for word in chinese_words:
if text.startswith(word, text.index(char)):
result.append(word)
break
return result
# 测试
sample = "hello世界!python代码2023"
print(split_chinese_english(sample)) # ['hello', '世界', '!', 'python', '代码', '2023']
原理:\b\w+\b匹配英文单词,[\u4e00-\u9fa5]匹配单个汉字
题4:高效提取海量文本中的url
import re
from urllib.parse import urlparse
# 预编译提升性能
url_pattern = re.compile(
r'https?://(?:[-\w.]|(?:%[\da-fa-f]{2}))+(?:[/?#][^\s"]*)?',
re.ignorecase
)
def extract_urls_large_file(file_path):
"""流式读取大文件提取url"""
with open(file_path, 'r', encoding='utf-8') as f:
for line in f:
yield from (urlparse(url).geturl() for url in url_pattern.findall(line))
# 使用示例
# for url in extract_urls_large_file("bigfile.log"):
# print(url)
优化点:流式读取避免内存溢出,预编译正则提升效率
题5:转换日期格式(mm/dd/yyyy到yyyy-mm-dd)
def convert_date_format(text):
"""将mm/dd/yyyy格式转为yyyy-mm-dd"""
return re.sub(
r'\b(0?[1-9]|1[0-2])/(0?[1-9]|[12]\d|3[01])/(\d{4})\b',
lambda m: f"{m.group(3)}-{m.group(1).zfill(2)}-{m.group(2).zfill(2)}",
text
)
# 测试
print(convert_date_format("date: 7/25/2023, 12/31/2024"))
# 输出:date: 2023-07-25, 2024-12-31
注意:使用zfill补零,\b确保完整日期匹配
题6:识别并高亮sql注入特征
def highlight_sql_injection(text):
"""高亮常见sql注入关键词"""
keywords = r'union|select|insert|delete|update|drop|--|\/\*'
return re.sub(
f'(python字符串正则匹配,python字符串正则替换,python字符串正则替换)',
lambda m: f'\033[31m{m.group(1)}\033[0m',
text,
flags=re.ignorecase
)
# 测试
sample = "select * from users where id=1 union select password from admins"
print(highlight_sql_injection(sample))
效果:在终端显示红色高危关键词
题7:多模式匹配优化(正则字典)
class fastmatcher:
def __init__(self):
self.patterns = {
'email': re.compile(r'\b[a-za-z0-9._%+-]+@[a-za-z0-9.-]+\.[a-z|a-z]{2,}\b'),
'phone': re.compile(r'\+?\d{1,3}[-. ]?\(?\d{3}\)?[-. ]?\d{3}[-. ]?\d{4}'),
'hashtag': re.compile(r'#\w+')
}
def match_all(self, text):
return {k: p.findall(text) for k, p in self.patterns.items()}
# 使用示例
matcher = fastmatcher()
print(matcher.match_all("contact: test@example.com #info 123-456-7890"))
题8:解析非标准csv(含逗号字段)
def parse_nonstandard_csv(csv_str):
"""解析带逗号的csv字段(使用正则)"""
return re.findall(
r'(?:^|,)(?:"((?:[^"]|"")*)"|([^",]*))',
csv_str
)
# 测试
sample = '1, "quote, test", "escaped ""double quote"""'
print([tuple(filter(none, m)) for m in parse_nonstandard_csv(sample)])
# 输出:[('1',), ('quote, test',), ('escaped "double quote"',)]
题9:多层级日志时间戳转换
from datetime import datetime
def convert_log_timestamp(log_line):
"""转换[25/jul/2023:15:30:22 +0800]到iso格式"""
def repl(m):
dt = datetime.strptime(m.group(1), "%d/%b/%y:%h:%m:%s %z")
return dt.isoformat()
return re.sub(
r'\[(\d{2}/\w{3}/\d{4}:\d{2}:\d{2}:\d{2} [+\-]\d{4})\]',
repl,
log_line
)
# 测试
log = '[25/jul/2023:15:30:22 +0800] "get /" 200'
print(convert_log_timestamp(log))
# 输出:2023-07-25t15:30:22+08:00 "get /" 200
题10:构建简易模板引擎
class simpletemplate:
def __init__(self, template):
self.pattern = re.compile(r'\{\{(\w+)\}\}')
self.template = template
def render(self, **context):
return self.pattern.sub(
lambda m: str(context.get(m.group(1), '')), self.template
)
# 使用示例
tpl = simpletemplate("hello, {{name}}! your score: {{score}}")
print(tpl.render(name="alice", score=95))
# 输出:hello, alice! your score: 95
实际使用中需根据具体需求添加异常处理、性能优化等逻辑。建议结合单元测试验证边界条件。
五、性能优化关键点
- 预编译正则:重复使用模式务必预编译
- 惰性匹配:避免.*导致的回溯爆炸
- 原子分组:
(?>pattern)减少回溯 - unicode优化:
re.ascii标志提升英文处理速度 - 替代方案:简单文本处理优先使用字符串方法
掌握字符串处理与正则表达式,将使你在数据处理、日志分析、web开发等领域游刃有余。本文涉及的技术需要反复实践,建议读者亲自测试每个示例代码,并尝试扩展练习题功能。
到此这篇关于python字符串处理与正则表达式用法的文章就介绍到这了,更多相关python字符串处理与正则表达式内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论