从Python3.6开始,引入了f-expression(f-string),可以让Python在填充字符串的时候进行一些简单的计算。而且f表达式的计算速度是字符串的很多倍。格式化方法。无论是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(mostrecentcalllast):File"",line1,inKeyError:'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}总结一下,如果从外面算向内,如果最外面的花括号称为第一层,那么奇数花括号用来填充数据,偶数花括号是普通字符。因此,如果不考虑代码可读性,如果我们需要最终生成的字符串本身是嵌套大括号的形式,我们可以进一步写成:>>>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}=({\{})$'>>>print(content_json_template.format(content_name=content_name))Traceback(mostrecentcalllast):File"",line1,inValueError:unexpected'{'infieldname不能应用到一层,那么我们看看如何应用两层:>>>content_name='detail'>>>content_json_template='{content_name}=({{\{}})$'>>>print(content_json_template.format(content_name=content_name))Traceback(mostrecentcallast):File"",line1,inIndexError:Replacementindex0outofrangeforpositionalargstuplesetoftwolayers仍然是错误的。如果字符串中不包含反斜杠,我们可以使用带引号的f表达式将半花括号括起来,例如:>>>name='kingname'>>>print(f'mynameis:{name},我的参数是:{"{"}')我的名字是:kingname,我的参数是:{但是问题是f表达式中不能有反斜杠,否则会报错:>>>content_name='detail'>>>content_regex=f'{content_name}=({\"{"})$'File"",line1SyntaxError:f-stringexpressionpartcannotincludeabackslash和.format方法支持反斜杠,但不支持写法引号内的单边花括号:>>>name='kingname'>>>print('我的名字是:{name},我的参数是:{"{"}'.format(name=name))Traceback(mostrecentcalllast):File"",line1,inValueError:unexpected'{'infieldname遇到这种情况,应该怎么解决呢?放开你的想法,灵活一点。查找的方法有很多种,这里只举两个例子:把花括号放在值里调整思路,既然句子模板里不能放花括号,那我们就把它们放在填充的值里:#Usingthe.formatmethod>>>name='kingname'>>>brace='{'>>>print('我的名字是:{name},我的参数是:{brace}'.format(name=name,brace=brace))我的名字是:kingname,我的参数是:{#usefexpression>>>content_name='detail'>>>brace='\{'>>>print(f'{content_name}=({brace})$')detail=(\{)$不要忘记字符串拼接。每个人最常犯的问题之一就是学习新事物而忘记旧事物。其实字符串拼接也可以解决问题。:>>>content_name='detail'>>>content_json=content_name+'=(\{)$'>>>print(content_json)detail=(\{)$转载可通过以下二维码关注本文,请联系UnheardCode公众号。