如何用Python正则表达式将字符串中的datetime.datetime对象替换为数字列表
如何用Python正则表达式将字符串中的datetime.datetime对象替换为数字列表
我懂你遇到的问题,就是想把字符串里那些datetime.datetime(...)格式的内容,替换成里面的数字组成的列表对吧?咱们先看看你原来的正则哪里出问题了。
你的原正则是:
DATETIME_PATTERN = r"datetime.datetime\(((\d+)(,\s*\d+)*), tzinfo=.*\)"
这里的.*是贪婪匹配,会把从tzinfo=开始后面的所有内容都“吞”掉,直到字符串末尾,这就导致它会误替换掉中间不该动的内容,比如后面的'bar': 'some data'部分也被卷进去了,这肯定不是你想要的。
那怎么改呢?关键是要让正则只匹配当前datetime.datetime(...)内部的tzinfo部分,而不超出这个对象的范围。
改进后的正则方案
我们可以把贪婪的.*换成更精确的匹配,比如只匹配到右括号)之前的内容,这样就能精准锁定单个datetime对象的范围:
import re input_str = "{'foo': datetime.datetime(2022, 5, 23, 0, 0, tzinfo=tzlocal()), 'bar': 'some data', 'foobar': datetime.datetime(2022, 8, 3, 13, 57, 41, tzinfo=<UTC>), 'barlist': ['hello', 'world']}" # 改进的正则:精准匹配单个datetime.datetime对象,捕获数字部分 DATETIME_PATTERN = r"datetime\.datetime\((\d+(?:,\s*\d+)*), tzinfo=[^)]*\)" modified_input_str = re.sub(DATETIME_PATTERN, r"[\1]", input_str) print(modified_input_str)
这里的关键改动点:
datetime\.datetime:转义了点号,因为正则里.默认匹配任意字符,必须转义才能匹配字面意义的点(\d+(?:,\s*\d+)*):捕获所有数字和分隔的逗号+空格组合,(?:...)是非捕获组,只用来重复匹配逗号加数字的模式,不会额外生成捕获组tzinfo=[^)]*:[^)]表示匹配除了右括号)之外的任意字符,这样就不会超出当前datetime对象的括号范围,完美避免了贪婪匹配的问题
运行这段代码后,就能得到你想要的结果:
{'foo': [2022, 5, 23, 0, 0], 'bar': 'some data', 'foobar': [2022, 8, 3, 13, 57, 41], 'barlist': ['hello', 'world']}
你自定义调整的版本
你后来也针对自己的特定需求修改了正则:
DATETIME_PATTERN = r"datetime\.datetime\((\d+(?:,\s*\d+)*), tzinfo=(?:[^\s\d])*\)"
这个版本把[^)]*换成了(?:[^\s\d])*,也就是只匹配非空白、非数字的字符,因为你知道自己场景里tzinfo=后面的内容不会有空格或数字,这个限制更严格,能进一步降低误匹配的概率,非常贴合你的实际需求。
这样调整后,正则的匹配精度就完全符合你的要求,不会再出现替换大段无关内容的问题了。
备注:内容来源于stack exchange,提问作者avhhh
相关产品推荐
相关产品推荐

