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

25 投票
3 回答
40130 浏览
提问于 2025-04-15 16:50

在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()

3 个回答

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])
16

根据文档的说明,如果你在格式化字符串的时候需要保留一个字面上的{},那么在原始字符串中就要用{{}}来表示。

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

首先,你需要格式化字符串,然后再使用正则表达式。把所有内容放在一行里其实没什么必要。要进行转义的话,可以通过把大括号写两次来实现:

>>> 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} 是多余的。

撰写回答