Je me demande comment Python compare les chaînes, en particulier comment il détermine le résultat lorsqu'un opérateur inférieur à (<
) ou supérieur à (>
) est utilisé.
Par exemple, si je mets print('abc' < 'bac')
, j'obtiens True
. Je comprends qu’il compare les caractères correspondants dans la chaîne, mais on ne voit pas bien pourquoi, faute de meilleur terme, "poids" est attribué au fait que a est inférieur à b (première position) dans la première chaîne plutôt que le fait que a soit inférieur à b dans la deuxième chaîne (deuxième position).
De la docs :
La comparaison utilise le lexicographique commande: d'abord les deux premiers articles sont comparés, et s'ils diffèrent ceci détermine le résultat de la Comparaison; si elles sont égales, le les deux éléments suivants sont comparés, et ainsi allumé, jusqu'à ce que l'une des séquences soit épuisé.
Également:
Le classement lexicographique des chaînes utilise le numéro de point de code Unicode pour ordonner des caractères individuels.
ou sur Python 2 :
L'ordre lexicographique pour les chaînes utilise l'ordre ASCII pour les caractères individuels.
Par exemple:
>>> 'abc' > 'bac'
False
>>> ord('a'), ord('b')
(97, 98)
Le résultat False
est renvoyé dès que a
est inférieur à b
. Les autres éléments ne sont pas comparés (comme vous pouvez le constater pour le deuxième élément: b
> a
est True
).
Attention aux lettres minuscules et majuscules:
>>> [(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)]
La comparaison de chaînes Python est lexicographique:
De la documentation Python: http://docs.python.org/reference/expressions.html
Les chaînes sont comparées lexicographiquement en utilisant les équivalents numériques (le résultat de la fonction intégrée ord ()) de leurs caractères. Les chaînes Unicode et 8 bits sont totalement interopérables dans ce comportement.
Ainsi, dans votre exemple, 'abc' < 'bac'
, 'a' vient avant (inférieur à) 'b' numériquement (dans ASCII et représentations Unicode), la comparaison se termine donc ici.
Python et pratiquement tous les autres langages informatiques utilisent les mêmes principes que (j'espère) que vous utiliseriez pour trouver un mot dans un dictionnaire imprimé:
(1) En fonction du langage humain impliqué, vous avez une notion d'ordre des caractères: 'a' <'b' <'c' etc.
(2) Le premier caractère a plus de poids que le deuxième: "az" <"za" (que la langue soit écrite de gauche à droite, de droite à gauche ou de boustrophédon n'a aucune pertinence)
(3) Si vous manquez de caractères à tester, la chaîne la plus courte est inférieure à la chaîne la plus longue: 'foo' <'food'
Typiquement, dans un langage informatique, la "notion de classement des caractères" est plutôt primitive: chaque caractère a un numéro indépendant du langage humain ord(character)
et les caractères sont comparés et triés à l'aide de ce nombre. Souvent, cet ordre n'est pas adapté au langage humain de l'utilisateur et vous devez ensuite vous lancer dans la "compilation", un sujet amusant.
Regardez aussi Comment trier les chaînes Unicode par ordre alphabétique en Python? où la discussion porte sur le tri des règles données par l'algorithme de classement Unicode ( http://www.unicode.org/reports/tr10/ ).
Répondre au commentaire
Quoi? Comment définir autrement une commande autre que de gauche à droite?
par S.Lott, il existe un contre-exemple célèbre lors du tri de la langue française. Cela implique des accents: en effet, on pourrait dire qu'en français, les lettres sont triées de gauche à droite et les accents de droite à gauche. Voici le contre-exemple: Nous avons e <é et o <ô, vous voudriez donc que les mots cote, coté, côte, côté soient triés par côte <coté <côte <côté>. Eh bien, ce n’est pas ce qui se passe, c’est en fait que vous avez: cote <côte <coté <côté, c’est-à-dire que si nous supprimons "c" et "t", nous obtenons oe <ôe <oé <ôé, ce qui est exactement correct -left commande.
Et une dernière remarque: vous ne devriez pas parler de triage de gauche à droite et de droite à gauche mais plutôt de triage en avant et en arrière.
En effet, il existe des langues écrites de droite à gauche et si vous pensez que l'arabe et l'hébreu sont triés de droite à gauche, vous avez peut-être raison d'un point de vue graphique, mais vous vous trompez au niveau logique!
En effet, Unicode considère les chaînes de caractères codées dans ordre logique, et le sens d'écriture est un phénomène se produisant au niveau des glyphes. En d'autres termes, même si dans le mot שלום, la lettre shin apparaît à droite du caractère, logiquement, elle survient avant. Pour trier ce mot, on considérera d’abord le tibia, puis le mousseux, puis le vav, puis le mem, et c’est forward ordering (bien que l’hébreu soit écrit de droite à gauche), tandis que les accents français sont triés en arrière (bien que le français soit écrit de gauche à droite).
Ceci est un ordre lexicographique . Cela met simplement les choses dans l'ordre du dictionnaire.
Un pur équivalent en Python pour les comparaisons de chaînes serait:
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 depends on the length
# of the strings.
return len(string1) < len(string2)
Cette fonction fait l'équivalent de la méthode réelle ( Python 3.6 et Python 2.7 ) beaucoup plus lentement. Notez également que l'implémentation n'est pas exactement "Pythonic" et ne fonctionne que pour les comparaisons <
. C'est juste pour illustrer comment cela fonctionne. Je n'ai pas vérifié si cela fonctionne comme la comparaison Pythons pour caractères Unicode combinés .
Une variante plus générale serait:
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 op(len(string1), len(string2))
Les chaînes sont comparées lexicographiquement en utilisant les équivalents numériques (résultat de la fonction intégrée ord ()) de leurs caractères. Les chaînes Unicode et 8 bits sont totalement interopérables dans ce comportement.
Voici un exemple de code comparant deux chaînes lexicographiquement.
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')
pour différentes entrées les sorties sont-
1- abcdefg
abcdeff
1
2- abc
Abc
0
3- abs
AbZ
-1