Comparando cadenas usando Python

En Python, las cadenas son secuencias de caracteres que se almacenan efectivamente en la memoria como un objeto. Cada objeto se puede identificar utilizando el método id(), ya que...

En Python, las cadenas son secuencias de caracteres que se almacenan efectivamente en la memoria como un objeto. Cada objeto se puede identificar utilizando el método id(), como puede ver a continuación. Python intenta reutilizar objetos en la memoria que tienen el mismo valor, lo que también hace que la comparación de objetos sea muy rápida en Python:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ python
Python 2.7.9 (default, Jun 29 2016, 13:08:31)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a = "abc"
>>> b = "abc"
>>> c = "def"
>>> print (id(a), id(b), id(c))
(139949123041320, 139949123041320, 139949122390576)
>>> quit()

Para comparar cadenas, Python ofrece algunos operadores diferentes para hacerlo. Primero, los explicaremos con más detalle a continuación. En segundo lugar, repasaremos los módulos string y re, que contienen métodos para manejar coincidencias inexactas y que no distinguen entre mayúsculas y minúsculas. En tercer lugar, para manejar cadenas de varias líneas, el modulo difflib es muy útil. Una serie de ejemplos le ayudarán a entender cómo usarlos.

Los operadores == y !=

Como operador de comparación básico querrás usar == y !=. Funcionan exactamente de la misma manera que con valores enteros y flotantes. El operador == devuelve Verdadero si hay una coincidencia exacta; de lo contrario, se devolverá Falso. Por el contrario, el operador != devuelve Verdadero si no hay ninguna coincidencia y, de lo contrario, devuelve Falso. Listado 1 demuestra esto.

En un bucle for, una cadena que contiene el nombre de la ciudad suiza "Lausana" se compara con una entrada de una lista de otros lugares, y el resultado de la comparación se imprime en la salida estándar.

Listado 1:

1
2
3
4
5
6
# define strings
listOfPlaces = ["Berlin", "Paris", "Lausanne"]
currentCity = "Lausanne"

for place in listOfPlaces:
    print ("comparing %s with %s: %s" % (place, currentCity, place == currentCity))

Al ejecutar el script de Python desde arriba, el resultado es el siguiente:

1
2
3
4
$ python3 comparing-strings.py
comparing Berlin with Lausanne: False
comparing Paris with Lausanne: False
comparing Lausanne with Lausanne: True

Los operadores == y is

Python tiene los dos operadores de comparación == y is. A primera vista parecen lo mismo, pero en realidad no lo son. == compara dos variables en función de su valor real. Por el contrario, el operador es compara dos variables en función del ID del objeto y devuelve Verdadero si las dos variables se refieren al mismo objeto.

El siguiente ejemplo demuestra que para tres variables con valores enteros. Las dos variables a y b tienen el mismo valor, y Python hace referencia al mismo objeto para minimizar el uso de la memoria.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
>>> a = 1
>>> b = 1
>>> c = 2
>>> a is b
True
>>> a is c
False
>>> id(a)
10771520
>>> id(b)
10771520

Tan pronto como cambie el valor, Python volverá a crear una instancia del objeto y asignará la variable. En el siguiente fragmento de código, b obtiene el valor de 2 y, posteriormente, b y c se refieren al mismo objeto.

1
2
3
4
5
>>> b = 2
>>> id(b)
10771552
>>> id(c)
10771552

Una regla general a seguir es usar == al comparar tipos inmutables (como ints) y is al comparar objetos.

Más operadores de comparación

Para una comparación con respecto a un orden lexicográfico, puede usar los operadores de comparación <, >, <= y >=. La comparación en sí se hace carácter por carácter. El orden depende del orden de los caracteres en el alfabeto. Este orden depende de la tabla de caracteres que esté en uso en su máquina mientras ejecuta el código de Python.

Tenga en cuenta que el orden distingue entre mayúsculas y minúsculas. Como ejemplo del alfabeto latino, "Autobús" viene antes de "autobús". Listado 2 muestra cómo estos operadores de comparación funcionan en la práctica.

Listado 2:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# define the strings
listOfPlaces = ["Berlin", "Paris", "Lausanne"]
currentCity = "Lausanne"

for place in listOfPlaces:
    if place < currentCity:
            print ("%s comes before %s" % (place, currentCity))
    elif place > currentCity:
            print ("%s comes after %s" % (place, currentCity))
    else:
            print ("%s is similar to %s" % (place, currentCity))

Al ejecutar el script de Python desde arriba, el resultado es el siguiente:

1
2
3
4
$ python3 comparing-strings-order.py
Berlin comes before Lausanne
Paris comes after Lausanne
Lausanne is similar to Lausanne

Comparaciones que no distinguen entre mayúsculas y minúsculas {#comparaciones entre mayúsculas y minúsculas}

Los ejemplos anteriores se centraron en coincidencias exactas entre cadenas. Para permitir comparaciones que no distinguen entre mayúsculas y minúsculas, Python ofrece métodos de cadena especiales como upper() y lower(). Ambos están directamente disponibles como métodos del objeto de cadena correspondiente.

upper() convierte la cadena completa en letras mayúsculas y lower() en letras minúsculas, respectivamente. Basado en el Listado 1, el siguiente listado muestra cómo usar el método lower().

Listado 3:

1
2
3
4
5
6
# using the == operator
listOfPlaces = ["Berlin", "Paris", "Lausanne"]
currentCity = "lausANne"

for place in listOfPlaces:
    print ("comparing %s with %s: %s" % (place, currentCity, place.lower() == currentCity.lower()))

La salida es la siguiente:

1
2
3
4
$ python3 comparing-strings-case-insensitive.py
comparing Berlin with lausANne: False
comparing Paris with lausANne: False
comparing Lausanne with lausANne: True

Usar una expresión regular

A Expresión regular - or "regex" for short - defines a specific pattern of characters. Regarding this topic, Jeffrey Friedl wrote an excellent book titled Dominar las expresiones regulares, which I'd highly recommend.

Para hacer uso de este mecanismo en Python importa primero el re módulo y luego define un patrón específico. De nuevo, el siguiente ejemplo se basa en el Listado 1. El patrón de búsqueda coincide con "bahía", y comienza con una letra minúscula o mayúscula. Precisamente, el siguiente código de Python encuentra todas las cadenas en las que se produce el patrón de búsqueda sin importar en qué posición de la cadena: al principio, en el medio o al final.

Listado 4:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# import the additional module
import re

# define list of places
listOfPlaces = ["Bayswater", "Table Bay", "Bejing", "Bombay"]

# define search string
pattern = re.compile("[Bb]ay")

for place in listOfPlaces:
    if pattern.search(place):
        print ("%s matches the search pattern" % place)

El resultado es el siguiente y coincide con "Bayswater", "Table Bay" y "Bombay" de la lista de lugares:

1
2
3
4
$ python3 comparing-strings-re.py
Bayswater matches the search pattern
Table Bay matches the search pattern
Bombay matches the search pattern

Comparaciones de listas y líneas múltiples {#comparaciones de listas y líneas múltiples}

Hasta ahora, nuestras comparaciones solo se han basado en unas pocas palabras. Usando el módulo difflib, Python también ofrece una forma de comparar cadenas de varias líneas y listas completas de palabras. La salida se puede configurar de acuerdo con varios formatos de herramientas diff.

El siguiente ejemplo (Listado 5) compara dos cadenas de varias líneas línea por línea y muestra tanto las eliminaciones como las adiciones. Después de la inicialización del objeto Differ en la línea 12, la comparación se realiza utilizando el método compare() en la línea 15. El resultado se imprime en la salida estándar (línea 18).

Listado 5:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# import the additional module
import difflib
 
# define original text
# taken from: https://en.wikipedia.org/wiki/Internet_Information_Services
original = ["About the IIS", "", "IIS 8.5 has several improvements related", "to performance in large-scale scenarios, such", "as those used by commercial hosting providers and Microsoft's", "own cloud offerings."]

# define modified text
edited = ["About the IIS", "", "It has several improvements related", "to performance in large-scale scenarios."]

# initiate the Differ object
d = difflib.Differ()
 
# calculate the difference between the two texts
diff = d.compare(original, edited)
 
# output the result
print ('\n'.join(diff))

Ejecutar el script crea la salida como se ve a continuación. Las líneas con eliminaciones se indican con signos - mientras que las líneas con adiciones comienzan con un signo +. Además, las líneas con cambios comienzan con un signo de interrogación. Los cambios se indican mediante signos ^ en la posición correspondiente. Las líneas sin indicador siguen siendo las mismas.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
$ python comparing-strings-difflib.py
  About the IIS
  
- IIS 8.5 has several improvements related
?  ^^^^^^

+ It has several improvements related
?  ^

- to performance in large-scale scenarios, such
?                                        ^^^^^^

+ to performance in large-scale scenarios.
?                                        ^

- as those used by commercial hosting providers and Microsoft's
- own cloud offerings.

Conclusión

En este artículo, ha aprendido varias formas de comparar cadenas en Python. Esperamos que esta descripción general lo ayude a programar de manera efectiva en la vida de su desarrollador.

Agradecimientos

El autor quisiera agradecer a Mandy Neumeyer por su apoyo mientras preparaba el artículo. ulo.