Invertir una cadena en Python


1351

No hay una reversefunción integrada para el strobjeto de Python . ¿Cuál es la mejor manera de implementar este método?

Si proporciona una respuesta muy concisa, explique su eficiencia. Por ejemplo, si el strobjeto se convierte en un objeto diferente, etc.


1
use la cadena "tacocat"
JonPizza

Respuestas:


2654

Qué tal si:

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

Esta es una sintaxis de corte extendida . Funciona haciendo [begin:end:step]: al dejar de comenzar y terminar y al especificar un paso de -1, invierte una cadena.


29
Sin embargo, eso no funciona para utf8 ... Necesitaba hacer esto también, ¡ b = a.decode('utf8')[::-1].encode('utf8')pero gracias por la dirección correcta!
Ricky Levi

14
@RickyLevi Si .decode('utf8')es necesario, significa aque no contiene ningún objeto de cadena, sino bytes.
Shiplu Mokaddim

256

@ Paolo s[::-1]es el más rápido; es un enfoque más lento (quizás más legible, pero eso es discutible) ''.join(reversed(s)).


14
Esto es aproximadamente 3 veces más lento.
uno mismo

2
¡Y un comentario rápido para decir lo que hace lo explicará mejor que usar esta versión más lenta!
tburrows13

44
es más lento porque join tiene que construir la lista de todos modos para poder obtener el tamaño. ''.join(list(reversed(s)))puede ser un poco más rápido
Jean-François Fabre

¿Tienes alguna información sobre por qué [:: - 1] es más rápido? Me gustaría profundizar más.
Tanner

@Tanner [:: - 1] es el más rápido porque no llama a ninguna función externa, sino que usa el corte, que está altamente optimizado en python. '' .join (list (reverse (s))) realiza 3 llamadas a funciones.
hd1

217

¿Cuál es la mejor manera de implementar una función inversa para cadenas?

Mi propia experiencia con esta pregunta es académica. Sin embargo, si eres un profesional en busca de la respuesta rápida, usa un segmento que paso por -1:

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

o más legible (pero más lento debido a las búsquedas de nombres de métodos y al hecho de que join forma una lista cuando se le da un iterador) str.join:

>>> ''.join(reversed('a string'))
'gnirts a'

o para facilitar la lectura y la reutilización, coloque el sector en una función

def reversed_string(a_string):
    return a_string[::-1]

y entonces:

>>> reversed_string('a_string')
'gnirts_a'

Explicación más larga

Si estás interesado en la exposición académica, sigue leyendo.

No hay una función inversa incorporada en el objeto str de Python.

Aquí hay un par de cosas sobre las cadenas de Python que debes saber:

  1. En Python, las cadenas son inmutables . Cambiar una cadena no modifica la cadena. Crea uno nuevo.

  2. Las cuerdas son cortables. Al cortar una cadena se obtiene una nueva cadena desde un punto de la cadena, hacia atrás o hacia adelante, a otro punto, en incrementos dados. Toman notación de corte o un objeto de corte en un subíndice:

    string[subscript]

El subíndice crea un corte al incluir dos puntos dentro de las llaves:

    string[start:stop:step]

Para crear un corte fuera de los corchetes, deberá crear un objeto de corte:

    slice_obj = slice(start, stop, step)
    string[slice_obj]

Un enfoque legible:

Si bien ''.join(reversed('foo'))es legible, requiere llamar a un método de cadena str.join, en otra función llamada, que puede ser bastante lenta. Pongamos esto en una función, volveremos a ello:

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

Enfoque más eficaz:

Mucho más rápido está usando un corte inverso:

'foo'[::-1]

Pero, ¿cómo podemos hacer que esto sea más legible y comprensible para alguien menos familiarizado con las rebanadas o la intención del autor original? Creemos un objeto de corte fuera de la notación de subíndice, asígnele un nombre descriptivo y páselo a la notación de subíndice.

start = stop = None
step = -1
reverse_slice = slice(start, stop, step)
'foo'[reverse_slice]

Implementar como función

Para implementar esto realmente como una función, creo que es semánticamente lo suficientemente claro como para usar simplemente un nombre descriptivo:

def reversed_string(a_string):
    return a_string[::-1]

Y el uso es simplemente:

reversed_string('foo')

Lo que tu maestro probablemente quiere:

Si tiene un instructor, probablemente quieran que comience con una cadena vacía y que cree una nueva cadena a partir de la anterior. Puede hacer esto con sintaxis pura y literales usando un ciclo 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

Esto es teóricamente malo porque, recuerde, las cadenas son inmutables , por lo que cada vez que parece que está agregando un carácter a su nombre new_string, teóricamente está creando una nueva cadena cada vez. Sin embargo, CPython sabe cómo optimizar esto en ciertos casos, de los cuales este caso trivial es uno.

Mejores prácticas

Teóricamente mejor es recopilar sus subcadenas en una lista y unirlas más tarde:

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)

Sin embargo, como veremos en los tiempos siguientes para CPython, esto en realidad lleva más tiempo, porque CPython puede optimizar la concatenación de cadenas.

Tiempos

Aquí están los horarios:

>>> 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 optimiza la concatenación de cadenas, mientras que otras implementaciones pueden no :

... no confíe en la implementación eficiente de CPython de la concatenación de cadenas in situ para sentencias en la forma a + = b o a = a + b. Esta optimización es frágil incluso en CPython (solo funciona para algunos tipos) y no está presente en absoluto en implementaciones que no utilizan el recuento. En las partes sensibles de rendimiento de la biblioteca, se debe utilizar el formulario '' .join () Esto asegurará que la concatenación ocurra en tiempo lineal en varias implementaciones.


55
Me encanta esta respuesta, explicaciones sobre optimizaciones, legibilidad frente a optimización, consejos sobre lo que quiere el profesor. No estoy seguro acerca de la sección de las mejores prácticas con el whiley disminuyendo el índice, aunque quizás esto es menos legible: for i in range(len(a_string)-1, -1, -1): . Sobre todo, me encanta que la cadena de ejemplo que has elegido es el único caso en el que nunca necesitarías revertirla, y no podrías saber si lo hubieras hecho :)
Davos

37

Respuesta rápida (TL; DR)

Ejemplo

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

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

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

Respuesta detallada

Antecedentes

Esta respuesta se proporciona para abordar la siguiente preocupación de @odigity:

Guau. Al principio me horrorizó la solución que propuso Paolo, pero eso quedó en segundo plano ante el horror que sentí al leer el primer comentario: "Eso es muy pitónico. ¡Buen trabajo!" Estoy tan perturbado que una comunidad tan brillante piensa que usar métodos tan crípticos para algo tan básico es una buena idea. ¿Por qué no es solo en reversa ()?

Problema

  • Contexto
    • Python 2.x
    • Python 3.x
  • Guión:
    • El desarrollador quiere transformar una cadena
    • La transformación es invertir el orden de todos los personajes.

Solución

Trampas

  • El desarrollador puede esperar algo como string.reverse()
  • La solución idiomática nativa (también conocida como " pitón ") puede no ser legible para los desarrolladores más nuevos.
  • El desarrollador puede verse tentado a implementar su propia versión de string.reverse()para evitar la notación de corte.
  • La salida de la notación de corte puede ser contra intuitiva en algunos casos:
    • ver por ejemplo, ejemplo02
      • print 'coup_ate_grouping'[-4:] ## => 'ping'
      • comparado con
      • print 'coup_ate_grouping'[-4:-1] ## => 'pin'
      • comparado con
      • print 'coup_ate_grouping'[-1] ## => 'g'
    • los diferentes resultados de la indexación [-1]pueden desanimar a algunos desarrolladores

Razón fundamental

Python tiene una circunstancia especial a tener en cuenta: una cadena es un tipo iterable .

Una razón para excluir un string.reverse()método es incentivar a los desarrolladores de Python a aprovechar el poder de esta circunstancia especial.

En términos simplificados, esto simplemente significa que cada carácter individual en una cadena se puede operar fácilmente como parte de una disposición secuencial de elementos, al igual que las matrices en otros lenguajes de programación.

Para comprender cómo funciona esto, revisar example02 puede proporcionar una buena visión general.

Ejemplo02

### 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'

Conclusión

La carga cognitiva asociada con la comprensión de cómo funciona la notación de corte en Python puede ser demasiado para algunos adoptantes y desarrolladores que no desean invertir mucho tiempo en aprender el idioma.

Sin embargo, una vez que se entienden los principios básicos, el poder de este enfoque sobre los métodos de manipulación de cadenas fijas puede ser bastante favorable.

Para aquellos que piensan lo contrario, existen enfoques alternativos, como funciones lambda, iteradores o declaraciones simples de funciones únicas.

Si lo desea, un desarrollador puede implementar su propio método string.reverse (), sin embargo, es bueno entender la razón detrás de este aspecto de Python.

Ver también


17

Las respuestas existentes solo son correctas si se ignoran los modificadores Unicode / grupos de grafemas. Me ocuparé de eso más tarde, pero primero eche un vistazo a la velocidad de algunos algoritmos de inversión:

ingrese la descripción de la imagen aquí

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

ingrese la descripción de la imagen aquí

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

Puede ver que el tiempo para la comprensión de la lista (reversed = string[::-1] ) es en todos los casos el más bajo (incluso después de corregir mi error tipográfico).

Inversión de cuerdas

Si realmente quieres invertir una cadena en el sentido común, es MUCHO más complicado. Por ejemplo, tome la siguiente cadena ( dedo marrón apuntando hacia la izquierda , dedo amarillo apuntando hacia arriba ). Esos son dos grafemas, pero 3 puntos de código unicode. El adicional es un modificador de piel .

example = "👈🏾👆"

Pero si lo invierte con cualquiera de los métodos dados, obtendrá el dedo marrón apuntando hacia arriba , el dedo amarillo apuntando hacia la izquierda . La razón de esto es que el modificador de color "marrón" todavía está en el medio y se aplica a lo que esté antes. Entonces tenemos

  • U: dedo apuntando hacia arriba
  • M: modificador marrón
  • L: dedo apuntando a la izquierda

y

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

Los clústeres de grafemas Unicode son un poco más complicados que solo los puntos de código modificador. Afortunadamente, hay una biblioteca para manejar grafemas :

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

y por lo tanto la respuesta correcta sería

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

que también es, con mucho, el más lento:

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

El código

#!/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()

10

1. usando notación de corte

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

2. utilizando la función invertida ()

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

3. utilizando recursividad

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

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

1
Tengo que ver la solución de recursión, si la cadena tiene una longitud decente, te encontrarás RecursionError: maximum recursion depth exceeded while calling a Python object. Ej:rev_string("abcdef"*1000)
Adam Parkin

9

Una forma menos desconcertante de verlo sería:

string = 'happy'
print(string)

'contento'

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

'yppah'

En inglés [-1 :: - 1] se lee como:

"Comenzando en -1, vaya hasta el final, tomando pasos de -1"


2
Sin -1embargo, todavía no es necesario.
Eric Duminil

7

Invierta una cadena en python sin usar reverse () o [:: - 1]

def reverse(test):
    n = len(test)
    x=""
    for i in range(n-1,-1,-1):
        x += test[i]
    return x

1
¿No deberías usar xrange ya que no necesitas la lista, en python 2?
UnitasBrooks

5

Esta también es una forma interesante:

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

o similar:

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

Otra forma más 'exótica' usando byterarray que admite .reverse ()

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

Producirá:

'!siht esreveR'

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

3
Hice clic a favor, porque me gusta esta expresión lambda. Desafortunadamente, es la solución menos eficiente de todas las mencionadas anteriormente (prueba: Gist palindrome.py )
oski86

2
original = "string"

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

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

1
Si bien este código puede responder a la pregunta, es mejor explicar cómo resolver el problema y proporcionar el código como ejemplo o referencia. Las respuestas de solo código pueden ser confusas y carecen de contexto.
Robert Columbia

1
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"

Esto funciona al recorrer una cadena y asignar sus valores en orden inverso a otra cadena.


0

Aquí hay uno no lujoso:

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!")

0

Aquí hay uno sin [::-1]o reversed(para fines de aprendizaje):

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")

puedes usar +=para concatenar cadenas pero join()es más rápido.


0

Método recursivo:

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

ejemplo:

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

0

Todas las soluciones anteriores son perfectas, pero si estamos tratando de revertir una cadena usando for loop en python se volverá un poco complicado, así que aquí es cómo podemos revertir una cadena usando for loop

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

Espero que este sea útil para alguien.


0

Esa es mi manera:

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

0

Hay muchas formas de invertir una cadena, pero también creé otra solo por diversión. Creo que este enfoque no es tan malo.

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"))

0

Esta clase usa funciones mágicas de python para invertir una cadena:

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)  

Salida

dlrow olleh

Referencia


0

Para resolver esto en forma programada para la entrevista

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)

Salida:

dlrow olleh

-1

Con Python 3 puede invertir la cadena en el lugar, lo que significa que no se asignará a otra variable. Primero debe convertir la cadena en una lista y luego aprovechar la reverse()función.

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

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

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

    if __name__ == "__main__":
        main()

-2

Esta es una función inversa simple y significativa, fácil de entender y codificar

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

Si bien esto podría responder a la pregunta de los autores, carece de algunas palabras explicativas y / o enlaces a la documentación. Los fragmentos de código sin formato no son muy útiles sin algunas frases a su alrededor. También puede encontrar cómo escribir una buena respuesta muy útil. Por favor edite su respuesta.
hola

-3

Aquí es simplemente:

imprimir "loremipsum" [- 1 :: - 1]

y algunos lógicamente:

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()

salida:

muspimerol


-4

Invierte una cuerda sin magia de pitón.

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

Imprimir una cadena en reversa es algo diferente a invertir una cadena
Martin Thoma

-5

Claro, en Python puedes hacer cosas muy elegantes de 1 línea. :)
Aquí hay una solución simple y completa que podría funcionar en cualquier lenguaje de programación.

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)

1
No es una buena solución tener un código tan largo para una tarea tan trivial.
Hunter_71

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

SALIDA

o l l e h

-7

Puede usar la función invertida con una lista completa. Pero no entiendo por qué este método fue eliminado en Python 3, fue innecesariamente.

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

La pregunta pide el reverso de una cadena, y en su lugar le da una lista?
user21820

necesita una .joino algo para que sea una respuesta válida
AsheKetchum

1
Por cierto, [c for c in string]es equivalente a list(string).
Pierna derecha el
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.