2011-01-26 6 views
36

Me pregunto cómo Python realiza la comparación de cadenas, más específicamente cómo determina el resultado cuando se usa un signo menor que (<) o mayor que (>).Técnica de comparación de cadenas utilizada por Python

Por ejemplo, si pongo impresión ('abc' < 'bac') me hago cierto. Entiendo que compara los caracteres correspondientes en la cadena, pero no está claro por qué hay más, por falta de un término mejor, "peso" puesto en el hecho de que a es menor que b (primera posición) en la primera cadena en lugar de el hecho de que a es menor que b en la segunda cuerda (segunda posición).

+5

¿Qué? ¿De qué otro modo se puede ordenar de otra forma que no sea de izquierda a derecha? –

+3

@ S.Lott: de derecha a izquierda. No es que alguien lo haga, pero no es la única posibilidad. – katrielalex

+0

@katrielalex: si permite eso, debe permitir las posibilidades al azar e incluso solo e impar y todas las demás. Entonces tendría que "parametrizar" al operador para elegir qué orden. Si va a haber un valor predeterminado, ¿cómo podría ser distinto de izquierda a derecha? –

Respuesta

62

Desde el docs:

La comparación utiliza lexicográfico orden: primero los dos primeros artículos se comparan, y si difieren esta determina el resultado de la comparación ; si son iguales, se comparan los siguientes dos artículos de , y por lo tanto en adelante, hasta que cualquier secuencia sea agotada.

también:

orden lexicográfico de cuerdas utiliza el número de puntos de código Unicode para ordenar caracteres individuales.

o en Python 2:

orden lexicográfico de cuerdas utiliza el ordenamiento ASCII para caracteres individuales.

Como un ejemplo:

>>> 'abc' > 'bac' 
False 
>>> ord('a'), ord('b') 
(97, 98) 

El resultado False se devuelve tan pronto como a resulta ser menos de b. Los elementos adicionales no se comparan (como puede ver para los segundos artículos: b>a es True).

ser consciente de mayúsculas y las minúsculas:

>>> [(x, ord(x)) for x in abc] 
[('a', 97), ('b', 98), ('c', 99), ('d', 100), ('e', 101), ('f', 102), ('g', 103), ('h', 104), ('i', 105), ('j', 106), ('k', 107), ('l', 108), ('m', 109), ('n', 110), ('o', 111), ('p', 112), ('q', 113), ('r', 114), ('s', 115), ('t', 116), ('u', 117), ('v', 118), ('w', 119), ('x', 120), ('y', 121), ('z', 122)] 
>>> [(x, ord(x)) for x in abc.upper()] 
[('A', 65), ('B', 66), ('C', 67), ('D', 68), ('E', 69), ('F', 70), ('G', 71), ('H', 72), ('I', 73), ('J', 74), ('K', 75), ('L', 76), ('M', 77), ('N', 78), ('O', 79), ('P', 80), ('Q', 81), ('R', 82), ('S', 83), ('T', 84), ('U', 85), ('V', 86), ('W', 87), ('X', 88), ('Y', 89), ('Z', 90)] 
+7

Solo quería agregar que si una secuencia se agota, esa secuencia es menor: ''abc' <'abcd''. – Noumenon

+0

Gracias por esto, podría ser útil agregar que también funciona con cadenas de números. Solo estaba teniendo este problema '' 24 "> 40' =' True' debido a 'ord (" 2 ")' = '50' – Procyclinsur

+1

@Procyclinsur no, eso no es lo que realmente sucede. Solo puede comparar cadenas y números enteros en Python 2, y [la lógica de comparación es diferente] (https://stackoverflow.com/q/3270680). '" 24 ">" 40 "' (tenga en cuenta las comillas) devuelve 'False'. – vaultah

8

Python comparación de cadenas es lexicográfico:

De Python Docs: http://docs.python.org/reference/expressions.html

cadenas se comparan lexicográfico utilizando los equivalentes numéricos (el resultado de la función incorporada ord()) de sus caracteres. Las cadenas Unicode y de 8 bits son completamente interoperables en este comportamiento.

Por lo tanto en su ejemplo, 'abc' < 'bac', 'a' viene antes (menos-que) 'b' numéricamente (en ASCII y representaciones Unicode), por lo que la comparación termina justo allí.

+0

Entonces, ¿finaliza la comparación tan pronto como descubre que uno de los caracteres es menor que el que corresponde? – davelupt

+0

@David: Sí. O menos que o más que. Si son iguales, los siguientes elementos se comparan. – user225312

3

Esto es lexicographical ordering. Simplemente pone las cosas en orden de diccionario.

+0

Esto es realmente incorrecto, porque un diccionario no marca la diferencia entre letras minúsculas y mayúsculas, por ejemplo ''a '>' z'' es 'Verdadero', mientras que''a '>' Z''es 'Falso' – seb

1

Strings se comparan lexicographically utilizando los equivalentes numéricos (el resultado de la función incorporada ord()) de sus caracteres. Las cadenas Unicode y de 8 bits son completamente interoperables en este comportamiento.

6

Python y casi todos los demás lenguaje informático utilizar los mismos principios que (espero) que usaría la hora de encontrar una palabra en un diccionario impreso:

(1) Según el idioma humano involucrado, que tienen una noción de orden de los caracteres 'a' < 'b' < 'c', etc.

(2) en primer personaje tiene más peso que el segundo personaje: 'az' < 'za' (si el idioma está escrito-a-izquierda derecha o derecha a izquierda o boustrophedon es bastante irrelevante)

(3) Si se queda sin f caracteres para probar, la cadena más corta es menor que la cadena más larga: 'foo' < 'comida'

Por lo general, en un lenguaje informático la "noción de ordenación de caracteres" es bastante primitiva: cada personaje tiene un lenguaje humano -el número independiente ord(character) y los caracteres se comparan y ordenan usando ese número. A menudo ese orden no es apropiado para el lenguaje humano del usuario, y luego tiene que entrar en "cotejo", un tema divertido.

3

Eche un vistazo también en How do I sort unicode strings alphabetically in Python? donde la discusión es acerca de las reglas de clasificación dadas por el Algoritmo de intercalación Unicode (http://www.unicode.org/reports/tr10/).

Para responder al comentario

¿Qué? ¿De qué otro modo se puede ordenar de otra forma que no sea de izquierda a derecha?

por S.Lott, existe un famoso contraejemplo al clasificar el idioma francés. Implica acentos: de hecho, podría decirse que, en francés, las letras se ordenan de izquierda a derecha y los acentos de derecha a izquierda. Aquí está el contraejemplo: tenemos e < é y o < ô, por lo que cabría esperar que las palabras cote, coté, côte, côté se clasifiquen como cote < coté < côte < côté. Bueno, esto no es lo que ocurre, de hecho tiene: cote < Côte < coté < Côté, es decir, si quitamos "c" y "t", obtenemos oe < Oe < oé < Oe, que es exactamente derecho a - dejar de ordenar.

Y una última observación: que no debería estar hablando de izquierda a derecha y derecha a izquierda de clasificación sino más bien de hacia adelante y hacia atrás clasificación.

de hecho hay idiomas escritos de derecha a izquierda y si usted piensa árabe y el hebreo son ordenados de derecha a izquierda puede ser correcto desde un punto de vista gráfico, pero se equivoca en el nivel lógico!

De hecho, Unicode considera cadenas de caracteres codificadas en orden lógico, y la dirección de escritura es un fenómeno que se produce en el nivel de glifo.En otras palabras, incluso si en la palabra שלום la letra shin aparece a la derecha de la lamed, lógicamente ocurre antes de. Para ordenar esta palabra primero se considerará la espinilla, luego lamed, luego la vav, luego la mem, y esto es adelante ordenando (aunque el hebreo se escribe de derecha a izquierda), mientras que los acentos franceses se ordenan hacia atrás (aunque el francés está escrito de izquierda a derecha).

0

Aquí hay un código de ejemplo que compara dos cadenas lexicográficamente.

a = str(input()) 
    b = str(input()) 
    if 1<=len(a)<=100 and 1<=len(b)<=100: 
    a = a.lower() 
    b = b.lower() 
    if a > b: 
     print('1') 
    elif a < b: 
     print('-1') 
    elif a == b: 
     print('0') 

para diferentes entradas las salidas son-

1- abcdefg 
    abcdeff 
    1 

2- abc 
    Abc 
    0 

3- abs 
    AbZ 
    -1 
2

Un equivalente Python puro para las comparaciones de cadenas sería:

def less(string1, string2): 
    # Compare character by character 
    for idx in range(min(len(string1), len(string2))): 
     # Get the "value" of the character 
     ordinal1, ordinal2 = ord(string1[idx]), ord(string2[idx]) 
     # If the "value" is identical check the next characters 
     if ordinal1 == ordinal2: 
      continue 
     # If it's smaller we're finished and can return True 
     elif ordinal1 < ordinal2: 
      return True 
     # If it's bigger we're finished and return False 
     else: 
      return False 
    # We're out of characters and all were equal, so the result is False 
    return False 

Esta función hace el equivalente del método real (y Python 3.6Python 2.7) solo un poco más lento. También tenga en cuenta que la implementación no es exactamente "pitónica" y solo funciona para las comparaciones <. Es solo para ilustrar cómo funciona. No he comprobado si funciona como la comparación de Pitones para combined unicode characters.

Una variante más general sería:

from operator import lt, gt 

def compare(string1, string2, less=True): 
    op = lt if less else gt 
    for char1, char2 in zip(string1, string2): 
     ordinal1, ordinal2 = ord(char1), ord(char1) 
     if ordinal1 == ordinal2: 
      continue 
     elif op(ordinal1, ordinal2): 
      return True 
     else: 
      return False 
    return False 
Cuestiones relacionadas