Метод сравнения строк, используемый Python

Мне интересно, как Python выполняет сравнение строк, а точнее, как он определяет результат, когда используется оператор меньше (<) или больше (>).

Например, если я поместил print('abc' < 'bac') я получу True. Я понимаю, что он сравнивает соответствующие символы в строке, однако неясно, почему существует больше, из-за отсутствия лучшего термина, "вес", установленный на том, что a меньше, чем b (первая позиция) в первой строке, а не тот факт, что а меньше второй во второй строке (вторая позиция).

Ответ 1

Из docs:

В сравнении используются лексикографические заказ: сначала первые два пункта сравниваются, и если они отличаются определяет результат сравнение; если они равны, сравниваются следующие два элемента, и поэтому, пока не будет истощены.

также:

Лексикографическое упорядочение для строк использует номер кодовой точки Юникода для заказа отдельных символов.

или на Python 2:

Лексикографическое упорядочение для строк использует порядок ASCII для отдельных символов.

В качестве примера:

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

Результат False возвращается, как только a оказывается меньше b. Дальнейшие пункты не сравниваются (как вы можете видеть для вторых элементов: b > a is True).

Помните о нижнем и верхнем регистре:

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

Ответ 2

Сравнение строк Python является лексикографическим:

Из документов Python: http://docs.python.org/reference/expressions.html

Строки сравниваются лексикографически с использованием числовых эквивалентов (результат встроенной функции ord()) их символов. Unicode и 8-битные строки полностью совместимы в этом поведении.

Следовательно, в вашем примере 'abc' < 'bac', 'a' встречается раньше (меньше) 'b' численно (в представлениях ASCII и Unicode), поэтому сравнение заканчивается прямо там.

Ответ 3

Python и практически любой другой компьютер используют те же принципы, что и (надеюсь), которые вы использовали бы при поиске слова в печатном словаре:

(1) В зависимости от человеческого языка у вас есть понятие упорядочения символов: 'a' 'b'<'c' и т.д.

(2) Первый символ имеет больший вес, чем второй символ: 'az'<'za' (независимо от того, написан ли язык слева направо или справа налево или в boustrophedon, совершенно не имеет значения)

(3) Если у вас закончились символы для проверки, более короткая строка меньше длинной строки: 'foo'<'Пища'

Как правило, на компьютерном языке "понятие упорядочения символов" довольно примитивно: каждый символ имеет номер, не зависящий от языка ord(character), и символы сравниваются и сортируются с использованием этого числа. Часто это упорядочение не соответствует человеческому языку пользователя, а затем вам нужно попасть в "подборку", интересную тему.

Ответ 5

Посмотрите также на Как отсортировать строки в юникоде по алфавиту в Python?, где обсуждаются правила сортировки, заданные алгоритмом сортировки Unicode (http://www.unicode.org/reports/tr10/).

Чтобы ответить на комментарий

Что? Как еще можно упорядочить порядок, кроме левого права?

by S.Lott, есть знаменитый контрастный пример при сортировке французского языка. Он включает в себя акценты: действительно, можно сказать, что по-французски буквы сортируются слева направо и акценты справа налево. Вот контрпример: мы имеем e < é и o < ô, так что вы ожидаете, что слова cote, coté, côte, côté будут отсортированы как cote < coté < côte < côté. Ну, это не то, что происходит, на самом деле у вас есть: cote < côte < coté < côté, то есть, если мы удалим "c" и "t", получим oe < ôe < oé < ôé, что является точно упорядочением справа налево.

И последнее замечание: вы не должны говорить о сортировке слева направо и справа налево, а скорее о сортировке вперед и назад.

Действительно, есть языки, написанные справа налево, и если вы считаете, что арабский и иврит отсортированы справа налево, вы можете быть правы с графической точки зрения, но вы ошибаетесь на логическом уровне!

Действительно, Unicode рассматривает символьные строки, закодированные в логическом порядке, а направление записи - это явление, происходящее на уровне глифа. Другими словами, даже если в слове שלום буквенная шина появляется справа от lamed, логически она встречается перед ней. Чтобы отсортировать это слово, сначала рассмотрим голень, затем lamed, затем vav, затем mem, и это форвардное распоряжение (хотя иврит написан справа налево), в то время как французские акценты сортируются назад (хотя французский язык написано слева направо).

Ответ 6

Чистым эквивалентом Python для сравнения строк будет:

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 smaller we're finished and can return True
        elif ordinal1 < ordinal2:
            return True
        # If it 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

Эта функция выполняет эквивалент реального метода (Python 3.6 и Python 2.7) намного медленнее. Также обратите внимание, что реализация не является точно "pythonic" и работает только для сравнений <. Это просто, чтобы проиллюстрировать, как это работает. Я не проверял, работает ли это как сравнение Pythons для комбинированных символов Юникода.

Более общий вариант:

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

Ответ 7

Строки сравниваются лексикографически с использованием числовых эквивалентов ( результат встроенной функции ord()) их символов. Unicode и 8-битные строки полностью совместимы в этом поведении.

Ответ 8

Вот пример кода, который сравнивает две строки лексикографически.

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

для разных входов выходы -

1- abcdefg
   abcdeff
   1

2- abc
   Abc
   0

3- abs
   AbZ
  -1