如何在 Python 中反转字符串?
- 2024-11-20 08:43:00
- admin 原创
- 7
问题描述:
reverse
Python 的对象没有内置方法str
。如何反转字符串?
解决方案 1:
使用切片:
>>> 'hello world'[::-1]
'dlrow olleh'
切片符号采用 的形式[start:stop:step]
。在本例中,我们省略了start
和stop
位置,因为我们想要整个字符串。我们还使用step = -1
,这意味着“从右向左反复移动 1 个字符”。
解决方案 2:
实现字符串反向函数的最佳方法是什么?
我自己对这个问题的经验是学术性的。但是,如果你是一个寻求快速答案的专业人士,请使用以下步骤-1
:
>>> 'a string'[::-1]
'gnirts a'
或者更易读(但由于方法名称查找和 join 在给定迭代器时形成列表的事实,速度较慢)str.join
,:
>>> ''.join(reversed('a string'))
'gnirts a'
或者为了提高可读性和可重用性,将切片放在函数中
def reversed_string(a_string):
return a_string[::-1]
进而:
>>> reversed_string('a_string')
'gnirts_a'
详细解释
如果您对学术论述感兴趣,请继续阅读。
Python 的 str 对象中没有内置的反向函数。
以下是关于 Python 字符串你应该知道的几件事:
在 Python 中,字符串是不可变的。更改字符串并不会修改该字符串。它会创建一个新的字符串。
字符串是可切片的。切片字符串会以给定的增量从字符串中的一个点向后或向前到另一个点生成一个新的字符串。它们采用切片符号或下标中的切片对象:
string[subscript]
下标通过在括号内包含冒号来创建切片:
string[start:stop:step]
要在括号外创建切片,您需要创建一个切片对象:
slice_obj = slice(start, stop, step)
string[slice_obj]
一种可读的方法:
虽然''.join(reversed('foo'))
可读性强,但它需要在另一个被调用函数上调用字符串方法str.join
,这可能相对较慢。让我们把它放在一个函数中——我们稍后再讨论它:
def reverse_string_readable_answer(string):
return ''.join(reversed(string))
最高效的方法:
使用反向切片会更快:
'foo'[::-1]
但是,对于不太熟悉切片或原作者意图的人来说,我们如何才能使其更具可读性和可理解性呢?让我们在下标符号之外创建一个切片对象,给它一个描述性的名称,并将其传递给下标符号。
start = stop = None
step = -1
reverse_slice = slice(start, stop, step)
'foo'[reverse_slice]
作为函数实现
为了真正将其实现为一个函数,我认为只需使用一个描述性名称在语义上就足够清楚了:
def reversed_string(a_string):
return a_string[::-1]
使用方法很简单:
reversed_string('foo')
你的老师可能想要的是:
如果您有一位导师,他们可能希望您从一个空字符串开始,然后从旧字符串构建一个新字符串。您可以使用 while 循环通过纯语法和文字来执行此操作:
def reverse_a_string_slowly(a_string):
new_string = ''
index = len(a_string)
while index:
index -= 1 # index = index - 1
new_string += a_string[index] # new_string = new_string + character
return new_string
从理论上讲,这是不好的,因为请记住,字符串是不可变的- 因此每次当你在 上添加一个字符时new_string
,理论上每次都会创建一个新的字符串!但是,CPython 知道如何在某些情况下优化这一点,这个简单的例子就是其中之一。
最佳实践
理论上更好的方法是将子字符串收集到一个列表中,然后稍后再将它们加入:
def reverse_a_string_more_slowly(a_string):
new_strings = []
index = len(a_string)
while index:
index -= 1
new_strings.append(a_string[index])
return ''.join(new_strings)
但是,正如我们将在下面的 CPython 时间中看到的,这实际上需要更长的时间,因为 CPython 可以优化字符串连接。
时间安排
具体时间如下:
>>> a_string = 'amanaplanacanalpanama' * 10
>>> min(timeit.repeat(lambda: reverse_string_readable_answer(a_string)))
10.38789987564087
>>> min(timeit.repeat(lambda: reversed_string(a_string)))
0.6622700691223145
>>> min(timeit.repeat(lambda: reverse_a_string_slowly(a_string)))
25.756799936294556
>>> min(timeit.repeat(lambda: reverse_a_string_more_slowly(a_string)))
38.73570013046265
CPython 优化了字符串连接,而其他实现可能不会:
... 对于 a += b 或 a = a + b 形式的语句,不要依赖 CPython 就地字符串连接的有效实现。这种优化即使在 CPython 中也很脆弱(它只适用于某些类型),并且在未使用引用计数的实现中根本不存在。在库的性能敏感部分,应改用 ''.join() 形式。这将确保连接在各种实现中以线性时间发生。
解决方案 3:
@Paolo 的s[::-1]
方法最快;较慢的方法(可能更具可读性,但这是有争议的)是''.join(reversed(s))
。
解决方案 4:
这个答案有点长,包含 3 个部分:现有解决方案的基准、为什么这里的大多数解决方案是错误的、我的解决方案。
现有的答案只有在忽略 Unicode 修饰符/字素簇的情况下才是正确的。我稍后会处理这个问题,但首先看一下一些反转算法的速度:
注意:我所说的list_comprehension
应该称为slicing
slicing : min: 0.6μs, mean: 0.6μs, max: 2.2μs
reverse_func : min: 1.9μs, mean: 2.0μs, max: 7.9μs
reverse_reduce : min: 5.7μs, mean: 5.9μs, max: 10.2μs
reverse_loop : min: 3.0μs, mean: 3.1μs, max: 6.8μs
slicing : min: 4.2μs, mean: 4.5μs, max: 31.7μs
reverse_func : min: 75.4μs, mean: 76.6μs, max: 109.5μs
reverse_reduce : min: 749.2μs, mean: 882.4μs, max: 2310.4μs
reverse_loop : min: 469.7μs, mean: 577.2μs, max: 1227.6μs
您可以看到,切片(reversed = string[::-1]
)的时间在所有情况下都是最短的(即使在修复我的拼写错误之后)。
字符串反转
如果你真的想以常识性的方式反转一个字符串,那么它要复杂得多。例如,以下面的字符串为例(棕色手指指向左边,黄色手指指向上面)。这是两个字素,但有 3 个 unicode 码点。额外的一个是皮肤修饰符。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件