Метод сравнения строк, используемый 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)
, и символы сравниваются и сортируются с использованием этого числа. Часто это упорядочение не соответствует человеческому языку пользователя, а затем вам нужно попасть в "подборку", интересную тему.
Ответ 4
Это лексикографическое упорядочение. Он просто ставит вещи в порядке словаря.
Ответ 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