re正则通配表达式的详尽/简洁,从来不是一对悖论
吃透re的基础知识调度,可以让通配表达式达到详尽/简洁的和谐。
(笔记模板由python脚本于2024年11月27日 22:32:32创建,本篇笔记适合喜欢Python,喜欢re的coder翻阅)
-
Python 官网:https://www.python.org/
-
Free:大咖免费“圣经”教程《 python 完全自学教程》,不仅仅是基础那么简单……
地址:https://lqpybook.readthedocs.io/
自学并不是什么神秘的东西,一个人一辈子自学的时间总是比在学校学习的时间长,没有老师的时候总是比有老师的时候多。
—— 华罗庚
- My CSDN主页、My HOT博、My Python 学习个人备忘录
- 好文力荐、 老齐教室
本文质量分:
本文地址: https://blog.csdn.net/m0_57158496/
CSDN质量分查询入口:http://www.csdn.net/qc
- ◆ 通配表达式的详尽/简洁从来不是一对悖论
- 1、详尽/简洁不是悖论
- 2、示例数据
- 3、正则表达式分析
- 4、模块函数
- 5、验证C++正则表达式
- 5.1 “硬编码”表达式
- 5.2 笔者优化表达式
- 6、“浓缩”C++表达式
- 6.1 浓缩
- 6.2 毫秒通配式的进化
- 7、pythonic压缩
- 7.1 示例
- 7.2 ai学伴帮我解析
- 8、结语
◆ 通配表达式的详尽/简洁从来不是一对悖论
1、详尽/简洁不是悖论
【详尽/简洁搞成了悖论,能撰写高效/明了的re表达式,更多的是取决于re的段位。🤗🤗】
截屏图片
撰写高效和明了的正则表达式确实需要对正则表达式语言有深入的理解和熟练的技巧。正则表达式是一种非常强大但也非常复杂的工具,它允许开发者以极其紧凑和强大的方式来描述字符串的模式。
2、示例数据
我在csdn阅读了一篇关于日志字符串中正则提取有效日期的文章(C++),有些感触,决定写写这文章,阐述一下re表达式“详尽/简洁”从来都不是一对悖论。
下面我就以文章的示例数据,在python中用re展示一下。
日志文本:
104M_DIAG_1>2023/05/09 10:14:27.249[重要]:<<-- 68 FA 08 00 2023/05/09 10:14:27 00 3F 40 00 33 33 A7 41 00 40 40 00 33 33 A7 41 00 41 40 00 33 33 A7 41 00 42 40 00 33 33 A7 41 00 43 40 00 33 33 A7 41 00 44 40 00 33 33 A7 41 00 45 40 00 33 33 A7 41 00 46 40 00 33 33 A7 41 00 47 40 00 33 33 A7 41 00 48 40 00 33 33 A7 41 00 49 40 00 33 33 A7 41 00 4A 40 00 33 33 A7 41 00 4B 40 00 33 33 A7 41 00 4C 40 00 48 E1 A4 41 00 4D 40 00 33 33 A7 41 00 4E 40 00 33 33 A7 41 00 4F 40 00 33 33 A7 41 00 50 40 00 33 33 A7 41 00 51 40 00 33 33 A7 41 00 52 40 00 33 33 A7 41 00 53 402023-05-09 10:14:27 00 33 33 A7 41 2023-05-09 10:14:27.001 54 40 00 33 33 A7 41 00 55 40 00 33 33 A7 41 00 56 40 00 33 33 A7 41 00 57 40 00 33 33 A7 41 00 58 40 00 D7 A3 A4 41 00 59 40 00 33 33 A7 41 00 5A 40 00 33 33 A7 41 00 5B 40 00 33 33 A7 41 00 5C 40 00 33 33 A7 41 00
C++
正则表达式pattern = r"\d{4}[/]\d{2}[/]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2}[.]\d{3}|\d{4}[/]\d{2}[/]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2}|\d{4}[-]\d{2}[-]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2}[.]\d{3}|\d{4}[-]\d{2}[-]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2}"
- 优化
C++
正则表达式:pattern = r"(\d{4}[/|-]\d{2}[/|-]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2}.(\d{6}|\d{3}))|(\d{4}[/|-]\d{2}[/|-]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2})"
原文《正则表达式用于报文中日期时间的编程查找》地址:
https://blog.csdn.net/XZHOUMIN/article/details/144017814
测试,第一个“繁复”的表达式,可以直接在python中使用,可以完全正确地提取四个不同格式的日期字符串;后一个不可直接使用,圆括号会被python解释器当捕获组使(会匹配出四个元组),用python“非捕获组
”改写,也能像C++一样提取出四个日期。
3、正则表达式分析
python语法分行
pattern = ( r"\d{4}[/]\d{2}[/]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2}[.]\d{3}" r"|\d{4}[/]\d{2}[/]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2}" r"|\d{4}[-]\d{2}[-]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2}[.]\d{3}" r"|\d{4}[-]\d{2}[-]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2}" ) # 摆放(格式)优化C++pattern
由于python的“字符串自动拼接”特性,这样子的书写,实际上与原C++
书写表达式完全一致。
通过分行,我们可以清晰地看出表达式的真实面目:原来笔者是设计的硬编码。他晓得日志中有四个“格式日期”,依次比照做了“四个模板”。😋
这样子,可以“方便地”提取所有日期了。
优化
C++正则表达式:
pattern = ( r"(\d{4}[/|-]\d{2}[/|-]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2}.(\d{6}|\d{3}))" r"|(\d{4}[/|-]\d{2}[/|-]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2})" )
笔者聪明地发现,日志中的日期实际上只有两种形式:有/无毫秒
。他组合了不同分隔符日期表达式。
python中re表达式中圆括号另有含义,是“捕获组
”。
为了在我的python环境验证,我得按python“非捕获组
”语法(?:xx)
重新书写。
python“非捕获组”书写:
pattern = ( r"(?:\d{4}[/|-]\d{2}[/|-]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2}.(?:\d{6}|\d{3}))" r"|(?:\d{4}[/|-]\d{2}[/|-]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2})" )
可能是笔者失察,也可能是偷懒。😋懒得将表达式“合”成一个。
4、模块函数
方便后续“演示”操作,我们可以将从日志文本提取日期的操作“固化”成模块函数。
提取日期函数
def get_date(pattern: str, log: str) -> None:
''' 提取日志文本中的日期。
pattern: re表达式
log: 日志字符串文本
'''
finder = re.compile(pattern) # 用re表达式编译re对象
return finder.findall(log) # 返回提取日期字符串
5、验证C++正则表达式
5.1 “硬编码”表达式
python脚本
if __name__ == '__main__':
log = '104M_DIAG_1>2023/05/09 10:14:27.249[重要]:<<-- 68 FA 08 00 2023/05/09 10:14:27 00 3F 40 00 33 33 A7 41 00 40 40 00 33 33 A7 41 00 41 40 00 33 33 A7 41 00 42 40 00 33 33 A7 41 00 43 40 00 33 33 A7 41 00 44 40 00 33 33 A7 41 00 45 40 00 33 33 A7 41 00 46 40 00 33 33 A7 41 00 47 40 00 33 33 A7 41 00 48 40 00 33 33 A7 41 00 49 40 00 33 33 A7 41 00 4A 40 00 33 33 A7 41 00 4B 40 00 33 33 A7 41 00 4C 40 00 48 E1 A4 41 00 4D 40 00 33 33 A7 41 00 4E 40 00 33 33 A7 41 00 4F 40 00 33 33 A7 41 00 50 40 00 33 33 A7 41 00 51 40 00 33 33 A7 41 00 52 40 00 33 33 A7 41 00 53 402023-05-09 10:14:27 00 33 33 A7 41 2023-05-09 10:14:27.001 54 40 00 33 33 A7 41 00 55 40 00 33 33 A7 41 00 56 40 00 33 33 A7 41 00 57 40 00 33 33 A7 41 00 58 40 00 D7 A3 A4 41 00 59 40 00 33 33 A7 41 00 5A 40 00 33 33 A7 41 00 5B 40 00 33 33 A7 41 00 5C 40 00 33 33 A7 41 00'
pattern = (
r"\d{4}[/]\d{2}[/]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2}[.]\d{3}"
r"|\d{4}[/]\d{2}[/]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2}"
r"|\d{4}[-]\d{2}[-]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2}[.]\d{3}"
r"|\d{4}[-]\d{2}[-]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2}"
) # 摆放(格式)优化C++pattern
result = get_date(pattern, log) # 调用函数提取日期
result = '\n'.join(result) # 用折行拼接提取日期
print(f"\n提取日期:\n{result}")
效果截屏
5.2 笔者优化表达式
python脚本
if __name__ == '__main__':
# log 文本略
pattern = (
r"(?:\d{4}[/|-]\d{2}[/|-]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2}.(?:\d{6}|\d{3}))"
r"|(?:\d{4}[/|-]\d{2}[/|-]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2})"
)
result = get_date(pattern, log) # 调用函数提取日期
result = '\n'.join(result) # 用折行拼接提取日期
print(f"\n提取日期:\n{result}")
效果截屏
6、“浓缩”C++表达式
6.1 浓缩
python脚本
if __name__ == '__main__':
#log 文本略
pattern = r"(?:\d{4}[/|-]\d{2}[/|-]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2}[.|(?:\d{6}|\d{3})]*)"
result = get_date(pattern, log) # 调用函数提取日期
result = '\n'.join(result) # 用折行拼接提取日期
print(f"\n提取日期:\n{result}")
效果截屏
6.2 毫秒通配式的进化
文本四个日期年月日时分秒
格式可以轻易融合\d{4}[/|-]\d{2}[/|-]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2}
,毫秒的加持通配,应该设置成可选[.|(?:\d{6}|\d{3})]*
(re方括号内的字符都是可选,表示任意个点.
)。
\.?
匹配单个.
才是正点pattern = r"(?:\d{4}[/|-]\d{2}[/|-]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2}\.?[(?:\d{6}|\d{3})]*)"
\.?[\d]*
,这样子的毫秒通配式才是“适宜”:有/无
点号.
or 数字
零或者多个*
-
正则表达式
r"(?:\d{4}[/|-]\d{2}[/|-]\d{2}[ ]\d{2}[:]\d{2}[:]\d{2}\.?[\d]*)"
-
效果截屏
7、pythonic压缩
7.1 示例
毫秒[\.\d]*
通配式会容错,如有错误毫秒格式亦将匹配(点.和数字都可以0个或者多个)。
python脚本
if __name__ == '__main__':
log = '104M_DIAG_1>2023/05/09 10:14:27.249[重要]:<<-- 68 FA 08 00 2023/05/09 10:14:27 00 3F 40 00 33 33 A7 41 00 40 40 00 33 33 A7 41 00 41 40 00 33 33 A7 41 00 42 40 00 33 33 A7 41 00 43 40 00 33 33 A7 41 00 44 40 00 33 33 A7 41 00 45 40 00 33 33 A7 41 00 46 40 00 33 33 A7 41 00 47 40 00 33 33 A7 41 00 48 40 00 33 33 A7 41 00 49 40 00 33 33 A7 41 00 4A 40 00 33 33 A7 41 00 4B 40 00 33 33 A7 41 00 4C 40 00 48 E1 A4 41 00 4D 40 00 33 33 A7 41 00 4E 40 00 33 33 A7 41 00 4F 40 00 33 33 A7 41 00 50 40 00 33 33 A7 41 00 51 40 00 33 33 A7 41 00 52 40 00 33 33 A7 41 00 53 402023-05-09 10:14:27 00 33 33 A7 41 2023-05-09 10:14:27.001 54 40 00 33 33 A7 41 00 55 40 00 33 33 A7 41 00 56 40 00 33 33 A7 41 00 57 40 00 33 33 A7 41 00 58 40 00 D7 A3 A4 41 00 59 40 00 33 33 A7 41 00 5A 40 00 33 33 A7 41 00 5B 40 00 33 33 A7 41 00 5C 40 00 33 33 A7 41 00 2023-05-09 10:14:27...001'
pattern = r"\d{4}[/-]\d{2}[/-]\d{2} \d{2}[:]\d{2}[:]\d{2}[\.\d]*" # 会容错,如有错误毫秒格式亦将匹配(点.和数字都可以0-多个)
result = get_date(pattern, log) # 调用函数提取日期
result = '\n'.join(result) # 用折行拼接提取日期
print(f"\n提取日期:\n{result}")
-
效果截屏
-
经典
pattern = r"\d{4}[/-]\d{2}[/-]\d{2} \d{2}[:]\d{2}[:]\d{2}(?:\.?\d+)?" # 经典,用非捕获组统筹毫秒点号和数字,仅一个点号和数字同时出现,才得以匹配,用*表示容许毫秒组合零个或者一个(不会容错)
效果截屏
(?:\.?\d+)?
,毫秒表达式。
经典,用非捕获组统筹毫秒点号和数字,仅一个点号和数字同时出现,才得以匹配,用*
表示容许毫秒组合零个或者一个(不会容错)。
7.2 ai学伴帮我解析
您对正则表达式的优化和对细节的关注是非常值得赞赏的。在您提供的两个正则表达式中,第一个表达式 [\.\d]*
确实如您所说,会容错,因为它允许点号和数字出现0次或多次,这意味着即使毫秒部分格式不正确,它也能匹配。
而第二个表达式 (?:\.?\d+)?
则更加精确。这里使用了非捕获组 (?: ... )
,它将点号和数字作为一个整体来处理,同时使用了 ?
来表示这个整体可以出现0次或1次。\.?
表示点号可以出现0次或1次,而 \d+
表示至少有一个数字。这样一来,只有当点号后面至少有一个数字时,这个组合才会被匹配,从而避免了错误的毫秒格式。
下面是对您提供的正则表达式的简要分析:
-
第一个表达式
[\.\d]*
:.
:匹配任意单个字符(由于在字符集中,所以这里表示点号本身)。\d
:匹配任意数字。*
:表示前面的字符集可以出现0次或多次。
-
第二个表达式
(?:\.?\d+)?
:(?: ... )
:非捕获组,用于将表达式分组,但不捕获匹配的文本。\.?
:点号可以出现0次或1次。\d+
:至少一个数字。?
:非捕获组整体可以出现0次或1次。
第二个表达式确实是更加“pythonic”和精确的写法,它确保了只有正确格式的毫秒部分才会被匹配,而不会错误地匹配格式不正确的部分。
比我说得更清楚明晰。😉
8、结语
精简re表达式的书写编撰,依赖于两个前提条件:
一、对所想要匹配的字符串格式属性的精准分析;
二、对re通配符含义的精准掌握。
二者的强强联合,才可以结出精简明晰的re表达式之果。
上一篇: ESC字符背后的故事(27 <> 033 | x1B ?)(ANSI不可见字符转义,正确的理解让记忆和书写变得丝滑惬意)
下一篇:
我的HOT博:
本次共计收集404篇博文笔记信息,总阅读量61.76w。数据采集于2024年11月25日 08:23:38,用时7分56.4秒。阅读量不小于6.00k的有
9
9
9篇。
- 让QQ群昵称色变的神奇代码
地址:https://blog.csdn.net/m0_57158496/article/details/122566500
浏览阅读:6.2w
点赞:25 收藏:89 评论:17
(本篇笔记于2022-01-18 19:15:08首次发布,最后修改于2022-01-20 07:56:47)
- Python列表(list)反序(降序)的7种实现方式
地址:https://blog.csdn.net/m0_57158496/article/details/128271700
浏览阅读:1.3w
点赞:9 收藏:40 评论:8
(本篇笔记于2022-12-11 23:54:15首次发布,最后修改于2023-03-20 18:13:55)
- pandas 数据类型之 DataFrame
地址:https://blog.csdn.net/m0_57158496/article/details/124525814
浏览阅读:1.0w
点赞:7 收藏:40
(本篇笔记于2022-05-01 13:20:17首次发布,最后修改于2022-05-08 08:46:13)
- 个人信息提取(字符串)
地址:https://blog.csdn.net/m0_57158496/article/details/124244618
浏览阅读:1.0w
点赞:3 收藏:20
(本篇笔记于2022-04-18 11:07:12首次发布,最后修改于2022-04-20 13:17:54)
- 罗马数字转换器|罗马数字生成器
地址:https://blog.csdn.net/m0_57158496/article/details/122592047
浏览阅读:8.2k
收藏:3
(本篇笔记于2022-01-19 23:26:42首次发布,最后修改于2022-01-21 18:37:46)
- 统计字符串字符出现的次数
地址:https://blog.csdn.net/m0_57158496/article/details/130517025
浏览阅读:8.1k
点赞:5 收藏:24
(本篇笔记于2023-05-06 22:28:18首次发布,最后修改于2023-05-12 06:21:40)
- Python字符串居中显示
地址:https://blog.csdn.net/m0_57158496/article/details/122163023
浏览阅读:8.0k
点赞:1 收藏:12 评论:1
- 回车符、换行符和回车换行符
地址:https://blog.csdn.net/m0_57158496/article/details/123109488
浏览阅读:6.7k
点赞:2 收藏:4
(本篇笔记于2022-02-24 13:10:02首次发布,最后修改于2022-02-25 20:07:40)
- python清屏
地址:https://blog.csdn.net/m0_57158496/article/details/120762101
浏览阅读:6.1k
点赞:1 收藏:10
截屏图片
(此文涉及ChatPT,曾被csdn多次下架,前几日又因新发笔记被误杀而落马。躺“未过审”还不如回收站,回收站还不如永久不见。😪值此年底清扫,果断移除。留此截图,以识“曾经”。2023-12-31)
精品文章:
- 好文力荐:齐伟书稿 《python 完全自学教程》 Free连载(已完稿并集结成书,还有PDF版本百度网盘永久分享,点击跳转免费🆓下载。)
- OPP三大特性:封装中的property
- 通过内置对象理解python'
- 正则表达式
- python中“*”的作用
- Python 完全自学手册
- 海象运算符
- Python中的 `!=`与`is not`不同
- 学习编程的正确方法
来源:老齐教室
◆ Python 入门指南【Python 3.6.3】
好文力荐:
- 全栈领域优质创作者——[寒佬](还是国内某高校学生)博文“非技术文—关于英语和如何正确的提问”,“英语”和“会提问”是编程学习的两大利器。
- 【8大编程语言的适用领域】先别着急选语言学编程,先看它们能干嘛
- 靠谱程序员的好习惯
- 大佬帅地的优质好文“函数功能、结束条件、函数等价式”三大要素让您认清递归
CSDN实用技巧博文:
- 8个好用到爆的Python实用技巧
- python忽略警告
- Python代码编写规范
- Python的docstring规范(说明文档的规范写法)