Python如何正确保留⼤括号?
⾃从Python 3.6开始,引⼊了f表达式(f-string),这使得Python在填充字符串时可以进⾏⼀些简单的计算。并且f表达式的运算速度是字符串.format⽅法的很多倍。
⽆论是f表达式还是字符串的.format⽅法,我们都可以使⽤⼤括号作为占位符,来填充数据。例如:
>>> name = 'kingname'
>>> print(f'我的名字是:{name}')
我的名字是:kingname
>>> print(f'1+1的结果为:{1 + 1}')
1+1的结果为:2
>>> salary = 999999
>>> print('我的⽉薪是:{salary}'.format(salary=salary))
我的⽉薪是:999999
但现在问题来了,如果我希望在使⽤f表达式或者.format⽅法填充内容的同时,⼜能保留⼤括号应该怎么办呢?
举个例⼦,在写爬⾍的时候,我需要使⽤正则表达式从当前URL中提取当前的页数:page=\d{0,3}。但是,对于不同的⽹站,表⽰页数的这个参数名可能是不⼀样的,有些是page=xxx,有些是Pag=xxx,有些是pageNo=xxx,有些是p=xxx。所以我想动态⽣成这个正则表达式。
如果我们直接使⽤f表达式或者.format⽅法,就会报错:
>>> page_name = 'page'
>>> page_regex_template = '{page_name}=\d{0,3}'
>>> print(page_regex_template.format(page_name=page_name))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: '0,3'
为了能够正常⽣成正则表达式,可能有⼈会想到使⽤古⽼的%s占位符:
>>> page_name = 'page'
>>> page_regex_template = '%s=\d{0,3}'
>>> print(page_regex_template % page_name)
page=\d{0,3}
虽然确实可⾏,但是混⽤两种填充字符串的⽅法,代码会变得不好维护,⽽且%s这种占位符填充速度也⾮常慢。
实际上,在Python的f表达式和.format⽅法中,如果你需要保留⼤括号,那么只需要写成⼤括号套⼤括号的形式就⾏了:
>>> page_name = 'page'
>>> page_regex_template = '{page_name}=\d{{0,3}}'
>>> print(page_regex_template.format(page_name=page_name))
page=\d{0,3}
⼤括号⾥⾯的第⼀层⼤括号会⾃动失效,变成普通的字符。但如果是⼤括号套⼤括号套⼤括号,那么最⾥⾯的⼀对⼤括号会继续⽣效充当占位符,例如:
>>> page_name = 'page'
>>> page_range = '0,5'
>>> page_regex_template = '{page_name}=\d{{{page_range}}}'
>>> print(page_regex_template.format(page_name=page_name, page_range=page_range))
page=\d{0,5}
总结起来就是,如果从外向内数,如果最外层⼤括号称为第1层,那么,第奇数层的⼤括号⽤来填充数据,第偶数层的⼤括号就是普通的字符。因此,如果不考虑代码可读性,如果我们需要最终⽣成的字符串本⾝就是嵌套⼤括号的形式,我们还可以进⼀步写成:
>>> ugly_string = '2层嵌套⼤括号:{{{{{variable}}}}}'
>>> print(ugly_string.format(variable=variable))
2层嵌套⼤括号:{{name}}
>>> ugly_string = '3层嵌套⼤括号:{{{{{{{variable}}}}}}}'
>>> print(ugly_string.format(variable=variable))
3层嵌套⼤括号:{{{name}}}
假设我们希望最终输出的字符串⾥⾯,保留n层⼤括号,那么在代码⾥⾯,我们需要写2n + 1层⼤括号。⼤家也看出来了,如果你要这样写,数⼤括号的个数都要把你的眼镜数瞎。所以,在实际开发中,⼤括号的层数绝对不要超过2层。
以下内容供学有余⼒的同学阅读。
上⾯讲到的⽅法,适⽤于⼤括号成对出现的情况,如果⼤括号只有半边,例如有些⽹站的正⽂信息是以JSON格式写在源代码⾥⾯的,于是我们可以使⽤正则表达式提取出包含正⽂的JSON然后进⼀步处理,⼀般来说,正则表达式可能是这样的:content=(\{);。不过,有的⽹站⽤的单词是content,有的⽹站⽤的是detail,所以这个地⽅需要填充,如果我们像往常那样写,那么还是会报错,例如:
>>> content_name = 'detail'
>>> content_json_template = '{content_name}=({\{})$'python正则表达式不包含
>>> print(content_json_template.format(content_name=content_name))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: unexpected '{' in field name
套⼀层不⾏,那我们看看套两层如何:
>>> content_name = 'detail'
>>> content_json_template = '{content_name}=({{\{}})$'
>>> print(content_json_template.format(content_name=content_name))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: Replacement index 0 out of range for positional args tuple
套两层还是错。
如果字符串不含反斜杠,我们可以使⽤f表达式配合引号包住半边⼤括号来实现,例如:
>>> name = 'kingname'
>>> print(f'我的名字是:{name},我的参数是:{"{"}')
我的名字是:kingname,我的参数是:{
但问题是,f表达式⾥⾯是不允许出现反斜杠的,否则会报错:
>>> content_name = 'detail'
>>> content_regex = f'{content_name}=({\"{"})$'
File "<stdin>", line 1
SyntaxError: f-string expression part cannot include a backslash
⽽.format⽅法⽀持反斜杠,但它⼜不⽀持引号包住单边⼤括号的写法:
>>> name = 'kingname'
>>> print('我的名字是:{name},我的参数是:{"{"}'.format(name=name))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: unexpected '{' in field name
遇到这种情况,我们应该怎么解决呢?只要把思路放开,灵活变通,能出很多⽅法,这⾥仅举两例:把⼤括号放到值⾥⾯
把思路调整过来,既然⼤括号不能放在句⼦模板⾥⾯,那我们就放在被填充的值⾥⾯:
# 使⽤.format⽅法
>>> name = 'kingname'
>>> brace = '{'
>>> print('我的名字是:{name},我的参数是:{brace}'.format(name=name, brace=brace))
我的名字是:kingname,我的参数是:{
# 使⽤f表达式
>>> content_name = 'detail'
>>> brace = '\{'
>>> print(f'{content_name}=({brace})$')
detail=(\{)$
不要忘记字符串拼接
⼤家最容易犯的⼀个问题就是学了新的东西,就忘记了旧的,实际上⽤字符串拼接也能解决问题:
>>> content_name = 'detail'
>>> content_json = content_name + '=(\{)$'
>>> print(content_json)
detail=(\{)$
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论