在Python中反转一个字符串

时间:2009-05-31 02:10:10

标签: python string

Python的reverse对象没有内置str函数。实现此方法的最佳方法是什么?

如果提供非常简洁的答案,请详细说明其效率。例如,str对象是否转换为其他对象等

30 个答案:

答案 0 :(得分:2478)

怎么样:

>>> 'hello world'[::-1]
'dlrow olleh'

这是extended slice语法。它的工作原理是[begin:end:step] - 通过离开开始和结束并指定步长为-1,它会反转一个字符串。

答案 1 :(得分:239)

@ Paolo的s[::-1]是最快的;一种较慢的方法(可能更具可读性,但这是有争议的)是''.join(reversed(s))

答案 2 :(得分:193)

  

为字符串实现反向函数的最佳方法是什么?

我对这个问题的经验是学术性的。但是,如果您是专业人士正在寻找快速回答,请使用步骤为-1的切片:

>>> 'a string'[::-1]
'gnirts a'

或者更可读(但由于方法名称查找速度较慢,并且在给定迭代器时连接形成列表的事实),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应该知道的字符串的几个方面:

  1. 在Python中,字符串是不可变的。更改字符串不会修改字符串。它会创建一个新的。

  2. 字符串是可切片的。切片字符串会以给定的增量为您提供从字符串中的一个点向后或向前到另一个点的新字符串。它们在下标中采用切片表示法或切片对象:

    string[subscript]
    
  3. 下标通过在大括号中包含冒号来创建切片:

        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优化字符串连接,而其他实现may not

      

    ...不要依赖CPython为a + = b或a = a + b形式的语句高效实现就地字符串连接。即使在CPython中,这种优化也很脆弱(它只适用于某些类型),并且在不使用引用计数的实现中根本不存在。在库的性能敏感部分,应该使用'.join()形式。这将确保在各种实现中以线性时间进行连接。

答案 3 :(得分:36)

快速回答(TL; DR)

实施例

### example01 -------------------
mystring  =   'coup_ate_grouping'
backwards =   mystring[::-1]
print backwards

### ... or even ...
mystring  =   'coup_ate_grouping'[::-1]
print mystring

### result01 -------------------
'''
gnipuorg_eta_puoc
'''

详细答案

背景

提供此答案是为了解决@odigity的以下问题:

  

哇。起初Paolo提出的解决方案让我感到震惊,但那   我在阅读第一篇文章时感到恐惧,退居二线   评论:"那非常pythonic。干得好!"我是如此不安   一个聪明的社区认为使用这种神秘的方法来做某事   基本是个好主意。为什么它不是s.reverse()?

问题

  • 上下文
    • Python 2.x
    • Python 3.x
  • 情景:
    • 开发人员想要转换字符串
    • 转换是为了扭转所有角色的顺序

解决方案

陷阱

  • 开发人员可能需要string.reverse()
  • 之类的内容
  • 本地惯用语(又名" pythonic")解决方案可能无法为较新的开发人员阅读
  • 开发人员可能想要实现自己的string.reverse()版本以避免切片表示法。
  • 在某些情况下,切片表示法的输出可能会违反直觉:
    • 参见例如example02
      • print 'coup_ate_grouping'[-4:] ## => 'ping'
      • 相比
      • print 'coup_ate_grouping'[-4:-1] ## => 'pin'
      • 相比
      • print 'coup_ate_grouping'[-1] ## => 'g'
    • [-1]索引的不同结果可能会让一些开发人员失望

原理

Python有一个特殊情况需要注意:字符串是iterable类型。

排除string.reverse()方法的一个基本原理是让python开发人员有动力利用这种特殊情况的力量。

简单来说,这只是意味着字符串中的每个字符都可以作为元素顺序排列的一部分轻松操作,就像其他编程语言中的数组一样。

要了解其工作原理,查看example02可以提供良好的概述。

Example02

### example02 -------------------
## start (with positive integers)
print 'coup_ate_grouping'[0]  ## => 'c'
print 'coup_ate_grouping'[1]  ## => 'o' 
print 'coup_ate_grouping'[2]  ## => 'u' 

## start (with negative integers)
print 'coup_ate_grouping'[-1]  ## => 'g'
print 'coup_ate_grouping'[-2]  ## => 'n' 
print 'coup_ate_grouping'[-3]  ## => 'i' 

## start:end 
print 'coup_ate_grouping'[0:4]    ## => 'coup'    
print 'coup_ate_grouping'[4:8]    ## => '_ate'    
print 'coup_ate_grouping'[8:12]   ## => '_gro'    

## start:end 
print 'coup_ate_grouping'[-4:]    ## => 'ping' (counter-intuitive)
print 'coup_ate_grouping'[-4:-1]  ## => 'pin'
print 'coup_ate_grouping'[-4:-2]  ## => 'pi'
print 'coup_ate_grouping'[-4:-3]  ## => 'p'
print 'coup_ate_grouping'[-4:-4]  ## => ''
print 'coup_ate_grouping'[0:-1]   ## => 'coup_ate_groupin'
print 'coup_ate_grouping'[0:]     ## => 'coup_ate_grouping' (counter-intuitive)

## start:end:step (or start:end:stride)
print 'coup_ate_grouping'[-1::1]  ## => 'g'   
print 'coup_ate_grouping'[-1::-1] ## => 'gnipuorg_eta_puoc'

## combinations
print 'coup_ate_grouping'[-1::-1][-4:] ## => 'puoc'

结论

与理解切片符号在python中如何工作相关的cognitive load对于那些不希望花费大量时间学习语言的采用者和开发者来说确实太过分了。

然而,一旦理解了基本原则,这种方法相对于固定字符串操作方法的能力就会非常有利。

对于那些不这么认为的人,有其他方法,例如lambda函数,迭代器或简单的一次性函数声明。

如果需要,开发人员可以实现自己的string.reverse()方法,但是理解python这方面的基本原理是很好的。

另见

答案 4 :(得分:10)

看待它的一个较为令人困惑的方式是:

string_reversed = string[-1::-1]
print(string_reversed)
  

'快乐的'

<div style="display:flex";>
    <img src="example.png" />
    <div>example...<div/>
</div>
  

'帕'

英文[-1 :: - 1]读作:

  

“从-1开始,一路走,步数为-1”

答案 5 :(得分:7)

1。使用切片表示法

def rev_string(s): 
    return s[::-1]

2。使用reversed()函数

def rev_string(s): 
    return ''.join(reversed(s))

3。使用递归

def rev_string(s): 
    if len(s) == 1:
        return s

    return s[-1] + rev_string(s[:-1])

答案 6 :(得分:5)

在不使用reverse()或[:: - 1]

的情况下在python中反转一个字符串
def reverse(test):
    n = len(test)
    x=""
    for i in range(n-1,-1,-1):
        x += test[i]
    return x

答案 7 :(得分:5)

这也是一种有趣的方式:

def reverse_words_1(s):
    rev = ''
    for i in range(len(s)):
        j = ~i  # equivalent to j = -(i + 1)
        rev += s[j]
    return rev

或类似的内容:

def reverse_words_2(s):
    rev = ''
    for i in reversed(range(len(s)):
        rev += s[i]
    return rev

使用byterarray支持.reverse()的另一种“异国情调”方式

b = bytearray('Reverse this!', 'UTF-8')
b.reverse()
b.decode('UTF-8')

将产生:

'!siht esreveR'

答案 8 :(得分:3)

def reverse(input):
    return reduce(lambda x,y : y+x, input)

答案 9 :(得分:3)

original = "string"

rev_index = original[::-1]
rev_func = list(reversed(list(original))) #nsfw

print(original)
print(rev_index)
print(''.join(rev_func))

答案 10 :(得分:1)

所有上述解决方案都很完美,但是如果我们试图在python中使用for循环来反转字符串会变得有点棘手,所以这里是我们如何使用for循环来反转字符串

string ="hello,world"
for i in range(-1,-len(string)-1,-1):
    print (string[i],end=(" ")) 

我希望这个会对某人有所帮助。

答案 11 :(得分:1)

以编程方式解决此问题

def reverse_a_string(string: str) -> str:
    """
    This method is used to reverse a string.
    Args:
        string: a string to reverse

    Returns: a reversed string
    """
    if type(string) != str:
        raise TypeError("{0} This not a string, Please provide a string!".format(type(string)))
    string_place_holder = ""
    start = 0
    end = len(string) - 1
    if end >= 1:
        while start <= end:
            string_place_holder = string_place_holder + string[end]
            end -= 1
        return string_place_holder
    else:
        return string


a = "hello world"
rev = reverse_a_string(a)
print(rev)

输出:

dlrow olleh

答案 12 :(得分:1)

仅当忽略Unicode修饰符/字形群集时,现有答案才正确。我将在稍后处理,但是首先看看一些逆向算法的速度:

enter image description here

list_comprehension  : 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

enter image description here

list_comprehension  : 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])的时间在所有情况下都是最低的(即使在修正我的错字之后)。

字符串反转

如果您真的想按常识反转字符串,则方法会更加复杂。例如,采用以下字符串(brown finger pointing leftyellow finger pointing up)。那是两个字素,但有3个unicode码点。另一个是skin modifier

example = ""

但是,如果使用任何给定方法将其反转,则会得到brown finger pointing upyellow finger pointing left。这样做的原因是“棕色”颜色修改器仍在中间,并应用于之前的任何内容。所以我们有

  • U:手指向上
  • M:棕色修饰剂
  • L:手指向左

original: LMU
reversed: UML (above solutions)
reversed: ULM (correct reversal)

Unicode Grapheme Clusters比修饰符代码点要复杂一些。幸运的是,有一个用于处理graphemes的库:

>>> import grapheme
>>> g = grapheme.graphemes("")
>>> list(g)
['', '']

因此正确的答案应该是

def reverse_graphemes(string):
    g = list(grapheme.graphemes(string))
    return ''.join(g[::-1])

这也是迄今为止最慢的:

list_comprehension  : min:    0.5μs, mean:    0.5μs, max:    2.1μs
reverse_func        : min:   68.9μs, mean:   70.3μs, max:  111.4μs
reverse_reduce      : min:  742.7μs, mean:  810.1μs, max: 1821.9μs
reverse_loop        : min:  513.7μs, mean:  552.6μs, max: 1125.8μs
reverse_graphemes   : min: 3882.4μs, mean: 4130.9μs, max: 6416.2μs

代码

#!/usr/bin/env python

import numpy as np
import random
import timeit
from functools import reduce
random.seed(0)


def main():
    longstring = ''.join(random.choices("ABCDEFGHIJKLM", k=2000))
    functions = [(list_comprehension, 'list_comprehension', longstring),
                 (reverse_func, 'reverse_func', longstring),
                 (reverse_reduce, 'reverse_reduce', longstring),
                 (reverse_loop, 'reverse_loop', longstring)
                 ]
    duration_list = {}
    for func, name, params in functions:
        durations = timeit.repeat(lambda: func(params), repeat=100, number=3)
        duration_list[name] = list(np.array(durations) * 1000)
        print('{func:<20}: '
              'min: {min:5.1f}μs, mean: {mean:5.1f}μs, max: {max:6.1f}μs'
              .format(func=name,
                      min=min(durations) * 10**6,
                      mean=np.mean(durations) * 10**6,
                      max=max(durations) * 10**6,
                      ))
        create_boxplot('Reversing a string of length {}'.format(len(longstring)),
                       duration_list)


def list_comprehension(string):
    return string[::-1]


def reverse_func(string):
    return ''.join(reversed(string))


def reverse_reduce(string):
    return reduce(lambda x, y: y + x, string)


def reverse_loop(string):
    reversed_str = ""
    for i in string:
        reversed_str = i + reversed_str
    return reversed_str


def create_boxplot(title, duration_list, showfliers=False):
    import seaborn as sns
    import matplotlib.pyplot as plt
    import operator
    plt.figure(num=None, figsize=(8, 4), dpi=300,
               facecolor='w', edgecolor='k')
    sns.set(style="whitegrid")
    sorted_keys, sorted_vals = zip(*sorted(duration_list.items(),
                                           key=operator.itemgetter(1)))
    flierprops = dict(markerfacecolor='0.75', markersize=1,
                      linestyle='none')
    ax = sns.boxplot(data=sorted_vals, width=.3, orient='h',
                     flierprops=flierprops,
                     showfliers=showfliers)
    ax.set(xlabel="Time in ms", ylabel="")
    plt.yticks(plt.yticks()[0], sorted_keys)
    ax.set_title(title)
    plt.tight_layout()
    plt.savefig("output-string.png")


if __name__ == '__main__':
    main()

答案 13 :(得分:1)

那是我的方式:

def reverse_string(string):
    character_list = []
    for char in string:
        character_list.append(char)
    reversed_string = ""
    for char in reversed(character_list):
        reversed_string += char
    return reversed_string

答案 14 :(得分:1)

递归方法:

def reverse(s): return s[0] if len(s)==1 else s[len(s)-1] + reverse(s[0:len(s)-1])

示例:

print(reverse("Hello!"))    #!olleH

答案 15 :(得分:1)

这是一个不花哨的人:

def reverse(text):
    r_text = ''
    index = len(text) - 1

    while index >= 0:
        r_text += text[index] #string canbe concatenated
        index -= 1

    return r_text

print reverse("hello, world!")

答案 16 :(得分:0)

def reverse_string(string):
    length = len(string)
    temp = ''
    for i in range(length):
        temp += string[length - i - 1]
    return temp

print(reverse_string('foo')) #prints "oof"

这是通过遍历一个字符串并将其值反向分配给另一个字符串来实现的。

答案 17 :(得分:0)

以下是没有[::-1]reversed(用于学习目的)的内容:

def reverse(text):
    new_string = []
    n = len(text)
    while (n > 0):
        new_string.append(text[n-1])
        n -= 1
    return ''.join(new_string)
print reverse("abcd")

您可以使用+=来连接字符串,但join()更快。

答案 18 :(得分:0)

有很多方法可以反转一个字符串,但我也创建了另一个只是为了好玩。我认为这种方法还不错。

def reverse(_str):
    list_char = list(_str) # Create a hypothetical list. because string is immutable

    for i in range(len(list_char)/2): # just t(n/2) to reverse a big string
        list_char[i], list_char[-i - 1] = list_char[-i - 1], list_char[i]

    return ''.join(list_char)

print(reverse("Ehsan"))

答案 19 :(得分:0)

此类使用python魔术函数反转字符串:

class Reverse(object):
    """ Builds a reverse method using magic methods """

    def __init__(self, data):
        self.data = data
        self.index = len(data)


    def __iter__(self):
        return self

    def __next__(self):
        if self.index == 0:
            raise StopIteration

        self.index = self.index - 1
        return self.data[self.index]


REV_INSTANCE = Reverse('hello world')

iter(REV_INSTANCE)

rev_str = ''
for char in REV_INSTANCE:
    rev_str += char

print(rev_str)  

输出

dlrow olleh

Reference

答案 20 :(得分:0)

 a=input()
 print(a[::-1])

上面的代码接收到用户的输入,并通过添加[::-1]来打印与输入相反的输出。

输出:

>>> Happy 
>>> yppaH

但是在句子方面,请查看下面的代码输出:

>>> Have a happy day
>>> yad yppah a evaH

但是如果您只希望反转字符串的字符而不是反转字符串的序列,请尝试以下操作:

a=input().split() #Splits the input on the basis of space (" ")
for b in a: #declares that var (b) is any value in the list (a)
    print(b[::-1], end=" ") #End declares to print the character in its quotes (" ") without a new line.

在上面第2行的代码中,我说**变量b是列表(a)中的任何值**我说var a是一个列表,因为在输入中使用split时,输入的变量成为列表。 还请记住,在int(input())情况下不能使用split

输出:

>>> Have a happy day
>>> evaH a yppah yad

如果我们没有在上面的代码中添加end(“”),则它将如下所示打印:

>>> Have a happy day
>>> evaH
>>> a
>>> yppah
>>> yad

下面是一个了解end()的示例:

代码:

for i in range(1,6):
     print(i) #Without end()

输出:

>>> 1
>>> 2
>>> 3
>>> 4
>>> 5

现在带有end()的代码:

for i in range(1,6):
    print(i, end=" || ")

输出:

>>> 1 || 2 || 3 || 4 || 5 ||

答案 21 :(得分:-1)

这里很简单:

print&#34; loremipsum&#34; [ - 1 :: - 1]

和逻辑上的一些:

def str_reverse_fun():
    empty_list = []
    new_str = 'loremipsum'
    index = len(new_str)
    while index:
        index = index - 1
        empty_list.append(new_str[index])
    return ''.join(empty_list)
print str_reverse_fun()

输出:

muspimerol

答案 22 :(得分:-1)

这是简单而有意义的反向功能,易于理解和编码

def reverse_sentence(text):
    words = text.split(" ")
    reverse =""
    for word in reversed(words):
        reverse += word+ " "
    return reverse

答案 23 :(得分:-1)

在不使用python魔术的情况下反转字符串。

>>> def reversest(st):
    a=len(st)-1
    for i in st:
        print(st[a],end="")
        a=a-1

答案 24 :(得分:-1)

使用python 3,您可以就地反转字符串,这意味着它不会分配给另一个变量。首先,您必须将字符串转换为列表,然后利用reverse()函数。

https://docs.python.org/3/tutorial/datastructures.html

   def main():
        muh_string = ["h","e","l","l","o"]
        print(reverseString(muh_string))

    def reverseString(s):
      print(s)
      s.reverse()
      return s

    if __name__ == "__main__":
        main()

答案 25 :(得分:-1)

结合使用字符串数组和for循环:

s='Banana-Ana'

print(s[0]) #we can access each character of the string this way, where 0 is for the first letter, B in this case.
print(len(s)) #we can see the length of the string

#By combining above with a for loop, we get the reverse printed out, the old fashioned way:
for a in range(len(s)): print(s[len(s)-a-1])

答案 26 :(得分:-2)

s ='Hello world'

S [:: - 1]

在上面的示例中,标签s或变量s是保持包含Hello世界字符串的字符串,在第二步中我打印Hello世界字符串的反向,方法是从所有内容开始,以反向步骤顺序使用-1。

答案 27 :(得分:-4)

s = 'hello'
ln = len(s)
i = 1
while True:
    rev = s[ln-i]
    print rev,
    i = i + 1
    if i == ln + 1 :
        break

输出:

o l l e h

答案 28 :(得分:-4)

当然,在Python中你可以做很花哨的1行内容。 :)
这是一个简单,全面的解决方案,可以在任何编程语言中使用。

def reverse_string(phrase):
    reversed = ""
    length = len(phrase)
    for i in range(length):
        reversed += phrase[length-1-i]
    return reversed

phrase = raw_input("Provide a string: ")
print reverse_string(phrase)

答案 29 :(得分:-5)

您可以使用带有列表复合的反转功能。但是我不明白为什么这个方法在python 3中被消除了,这是不必要的。

string = [ char for char in reversed(string)]