Python 2.6+中的str.format()和正则表达式

24

在Python 2.6和Python 3中,使用str.format()是格式化字符串的新标准。但是当我在使用str.format()与正则表达式一起时遇到了问题。

我编写了一个正则表达式来返回所有在指定域名下面一级的域名,或者是第二级域名为www且在指定域名下面两级的域名...

假设指定的域名为delivery.com,那么我的正则表达式应该返回a.delivery.com、b.delivery.com、www.c.delivery.com...但不应返回x.a.delivery.com。

import re

str1 = "www.pizza.delivery.com"
str2 = "w.pizza.delivery.com"
str3 = "pizza.delivery.com"

if (re.match('^(w{3}\.)?([0-9A-Za-z-]+\.){1}delivery.com$', str1): print 'String 1 matches!'
if (re.match('^(w{3}\.)?([0-9A-Za-z-]+\.){1}delivery.com$', str2): print 'String 2 matches!'
if (re.match('^(w{3}\.)?([0-9A-Za-z-]+\.){1}delivery.com$', str3): print 'String 3 matches!'

运行此命令应该会得到以下结果:

String 1 matches!
String 3 matches!

现在的问题是,当我尝试使用str.format动态替换delivery.com时...

if (re.match('^(w{3}\.)?([0-9A-Za-z-]+\.){1}{domainName}$'.format(domainName = 'delivery.com'), str1): print 'String 1 matches!'

这似乎会失败,因为str.format()期望{3}{1}是函数的参数。(我假设)

我可以使用+运算符连接字符串。

'^(w{3}\.)?([0-9A-Za-z-]+\.){1}' + domainName + '$'

问题归结为:当字符串(通常是正则表达式)中包含“{n}”时,是否可以使用str.format()

与问题不直接相关,但是通过养成始终使用原始字符串的正则表达式习惯,您将在以后节省大量的麻烦。 - Mark Peters
@Mark,这是什么原因?感谢你的提示。 - brildum
4
通常情况下,如果你在字符串字面值中使用反斜杠,你应该使用原始字符串。否则,你可能会遇到意想不到的字符串转义。在 Windows 文件路径中这一点体现得最明显,非原始字符串 "c:\names\bob" 的含义并不是你想象中的那样。在正则表达式中,使用原始字符串意味着你输入的是你要匹配的正则表达式字符串。为了在正则表达式中匹配单个反斜杠,你需要用另一个反斜杠进行转义:\。然而,在非原始字符串中,这个序列产生一个单个的反斜杠,但从正则表达式的角度看,并不容易理解。在原始字符串中,r'\' 可以按预期传递。 - Mark Peters
3个回答

41

你需要先格式化字符串再使用正则表达式,把所有东西都放在一行中真的不值得。通过双大括号转义来完成转义:

>>> pat= '^(w{{3}}\.)?([0-9A-Za-z-]+\.){{1}}{domainName}$'.format(domainName = 'delivery.com')
>>> pat
'^(w{3}\\.)?([0-9A-Za-z-]+\\.){1}delivery.com$'
>>> re.match(pat, str1)
此外,re.match是在字符串开头进行匹配的,如果使用re.match,您不必放置^,如果您正在使用re.search,则需要^。请注意,在正则表达式中,{1}相当冗余。

4
“{1}”不仅是多余的,使用“www”会比“w{{3}}”更清晰。我知道这并没有回答原始问题,但似乎对于这种情况来说是更好的解决方案。 - Don O'Donnell

16
根据文档,如果您需要在格式化操作中保留显示原始的 {} 符号,则可以在原始字符串中使用 {{}}
'^(w{{3}}\.)?([0-9A-Za-z-]+\.){{1}}{domainName}$'.format(domainName = 'delivery.com')

0
很不幸,对于我的情况来说,它不起作用,最后我使用了连接操作,如pattern='{'+Acc[0]+'}(\.\d+)?',其中Acc[0]是我的正则表达式中的变量项。
我尝试了以下格式,但都失败了。我与你分享,也许你会感兴趣(我使用的是Python 3.7)。
pattern='{{Acc[0]}}(\.\d+)?'
pattern='{{ID}}(\.\d+)?'.format(ID = Acc[0])
pattern='{{1}}(\.\d+)?'.format(ID = Acc[0])
pattern="{{}}(\.\d+)?".format(Acc[0])
pattern=fr"{{Acc[0]}}(\.\d+)?"
pattern = "%s(\\.\d+)?" % (Acc[0])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接