字符串格式化的几种方法


参考:
《Python Tricks: A Buffet of Awesome Python Features》

1. 旧式的字符串格式化

>>> errno = 50159747054
>>> name = 'Bob'
>>> 'Hello, %s' % name
'Hello, Bob'
>>> '%x' % errno  # 将整数转为十六进制,并输出为字符串
'badc0ffee'

如果您想在一个字符串中进行多个替换,那么“旧版”字符串格式化语法会发生轻微的变化。因为% -运算符只接受一个参数,所以需要将右侧封装在一个元组中

>>> 'Hey %s, there is a 0x%x error!' % (name, errno)
'Hey Bob, there is a 0xbadc0ffee error!'

如果将映射传递给% -运算符,还可以在格式字符串中按名称引用变量替换

>>> 'Hey %(name)s, there is a 0x%(errno)x error!' % {... "name": name, "errno": errno }
'Hey Bob, there is a 0xbadc0ffee error!'

参考:
printf-style-string-formatting

2. 新式的字符串格式化

利用format来格式化字符串

>>> 'Hello, {}'.format(name)
'Hello, Bob'

format支持给指定位置的变量赋值

>>> 'Hey {name}, there is a 0x{errno:x} error!'.format(name=name, errno=errno)
'Hey Bob, there is a 0xbadc0ffee error!'

在format中,把errno和name调换一下位置,也依然能输出正确的结果

>>> 'Hey {name}, there is a 0x{errno:x} error!'.format(errno=errno, name=name)
'Hey Bob, there is a 0xbadc0ffee error!'

errno后面的 :x 表示的是输出一个十六进制的数

>>> "int: {0:d};  hex: {0:x};  oct: {0:o};  bin: {0:b}".format(42)
'int: 42;  hex: 2a;  oct: 52;  bin: 101010'
>>> # with 0x, 0o, or 0b as prefix:
>>> "int: {0:d};  hex: {0:#x};  oct: {0:#o};  bin: {0:#b}".format(42)
'int: 42;  hex: 0x2a;  oct: 0o52;  bin: 0b101010'

参考:
str.format
string-formatting
format string syntax

3. 字符串插值法(python 3.6+)—— f-string

python3.6 增加了一种新的方式来格式化字符串。这种方式能够让你在字符串常量中嵌入python表达式。

>>> f'Hello, {name}!'
'Hello, Bob!'

因为这种方法能够嵌入python表达式,你甚至可以用来来做内联算术。

>>> a = 5
>>> b = 10
>>> f'Five plus ten is {a + b} and not {2 * (a + b)}.'
'Five plus ten is 15 and not 30.'
>>> def greet(name, question):
... 	return f"Hello, {name}! How's it {question}?"
...
>>> greet('Bob', 'going')
"Hello, Bob! How's it going?"

那么这个函数是如何做到的呢?实际上,f这个字符串所做的事类似于下面这个操作

>>> def greet(name, question):
...	return ("Hello, " + name + "! How's it " +question + "?")

f-字符串中,如果要输出其他进制的数字,比如十六进制,就要在:后面加上#x官网上写的是:#0x,经过打印,发现效果是一样的。

>>> f"Hey {name}, there's a {errno:#x} error!"
"Hey Bob, there's a 0xbadc0ffee error!"
>>> f"Hey {name}, there's a {errno:#0x} error!"
"Hey Bob, there's a 0xbadc0ffee error!"

参考:
formatted-string-literals

4. Template Strings

Template Strings,较为简单。

>>> from string import Template
>>> t = Template('Hey, $name!')
>>> t.substitute(name=name)
'Hey, Bob!'

我们需要做的,就是从python内置的string库中导入Template,然后定义一个字符串,把这个字符串放入Template()中,再执行substitute()方法。

>>> templ_string = 'Hey $name, there is a $error error!'
>>> Template(templ_string).substitute(name=name, error=hex(errno))
'Hey Bob, there is a 0xbadc0ffee error!'

应用Template Strings的最好的例子,是当你正在处理用户生成的字符串时。
举个例子,用户是有可能通过格式化字符串来获得程序中的任意变量的。也就是,如果一个恶意用户能提供一个格式化字符串,他们也能泄露密钥或者其他敏感信息。

The more complex formatting mini-languages of other string format-
ting techniques might introduce security vulnerabilities to your pro-
grams. For example, it’s possible for format strings to access arbitrary
variables in your program.
That means, if a malicious user can supply a format string they can
also potentially leak secret keys and other sensible information!
Here’s a simple proof of concept of how this attack might be used:

>>> SECRET = 'this-is-a-secret'
>>> class Error:
... 	def __init__(self):
... 		pass
>>> err = Error()
>>> user_input = '{error.__init__.__globals__[SECRET]}'
# Uh-oh...
>>> user_input.format(error=err)
'this-is-a-secret'
See how the hypothetical attacker was able to

使用 Template 能够阻止上述事情的发生。

>>> user_input = '${error.__init__.__globals__[SECRET]}'
>>> Template(user_input).substitute(error=err)
ValueError:
"Invalid placeholder in string: line 1, col 1"

我应该选择哪一种字符串格式化方法呢?

  1. 如果格式化字符串是用户提供的,就使用Template Strings,来避免安全问题
  2. 如果使用的是python 3.6+,就用字符串插值的方法
  3. 如果使用的版本低于python 3.6,那么使用第二种,也就是新式字符串格式化方法
发布了110 篇原创文章 · 获赞 129 · 访问量 36万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览