字符串是如何比较的?

How are strings compared?

提问人:davelupt 提问时间:1/27/2011 最后编辑:Karl Knechteldavelupt 更新时间:5/19/2023 访问量:158763

问:

我想知道 Python 如何进行字符串比较,更具体地说,当使用小于或大于运算符时,它如何确定结果。<>

例如,如果我把我得到.我知道它比较了字符串中的相应字符,但是由于缺乏更好的术语,为什么不清楚为什么在第一个字符串中小于(第一个位置)的事实上放置了更多的“权重”,而不是小于第二个字符串(第二个位置)的事实。print('abc' < 'bac')Trueabab


当字符串包含数字的表示形式时,许多人会问这个问题,并希望通过数值比较数字。直接的解决方案是首先转换值。请参阅 如何将字符串解析为 float 或 int?。如果列表或其他集合中有多个数字,请参阅如何在列表、字典等中收集重复计算的结果(或复制修改了每个元素的列表)?

如果您尝试比较包含数字序列的字符串,将数字视为数字(有时称为“自然排序”),请参阅是否有用于字符串自然排序的内置函数?

Python 字符串 比较

评论

7赞 S.Lott 1/27/2011
什么?除了从左到右之外,还可以如何定义排序?
9赞 Katriel 1/27/2011
@S.Lott:从右到左。并不是说任何人都会这样做,但这不是唯一的可能性。
1赞 S.Lott 1/27/2011
@katrielalex:如果你允许这样做,你就必须允许随机的、只有偶数的、只有奇数的,以及其他所有的可能性。然后,您必须“参数化”运算符以选择哪个排序。如果要有默认值,除了从左到右之外,还有什么其他呢?
7赞 Katriel 1/27/2011
@S.Lott:我同意——lex 是唯一合理的使用顺序。我只是吹毛求疵,这当然不是唯一可能的订单!
3赞 Noctis Skytower 11/16/2012
@S.Lott:要回答你的问题,你可以用数字或文本。它们是明确的(如果没有帮助的)顺序。sorted(range(10), key=lambda i: i ^ 123)sorted('How else can ordering be defined other than left-to-right?'.split(), key= lambda s: s[::-1])

答:

124赞 user225312 1/27/2011 #1

文档中:

比较使用词典 排序:先订购前两件 进行比较,如果它们不同,则 确定 比较;如果它们相等,则 接下来的两个项目进行比较,依此类推 on,直到任一序列 用尽。

也:

字符串的词典排序使用 Unicode 码位编号对单个字符进行排序。

或在 Python 2 上:

字符串的词典排序对单个字符使用 ASCII 排序。

举个例子:

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

一旦发现小于 ,将立即返回结果。其他项目不进行比较(如第二项所示:> 是 )。FalseabbaTrue

请注意小写和大写:

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

具体来说,这会产生 、 等的结果,包括所有计算结果,因为从 a 到 z 的所有小写字符的码位数都高于所有大写字符。'a' > 'A''b' > 'B''a' > 'Z'True

评论

21赞 Noumenon 5/6/2016
只是想补充一点,如果一个序列用尽了,则该序列更少:.'abc' < 'abcd'
2赞 rustysys-dev 2/21/2018
谢谢你,补充一下它也适用于数字字符串可能会很有用。我只是遇到了这个问题=由于"24" > 40Trueord("2") = 50
1赞 Rörd 5/20/2019
@vaultah:为了让其他人在阅读您的评论时无需阅读您链接到的问题,Python 2 的相关规则是“当您对数字和非数字类型进行排序时,数字类型排在第一位。(顺便说一句,Python 3 会引发 TypeError 异常。
13赞 wkl 1/27/2011 #2

Python 字符串比较是字典式的:

来自 Python 文档: http://docs.python.org/reference/expressions.html

使用字符串字符的数字等价物(内置函数 ord() 的结果)对字符串进行字典比较。Unicode 和 8 位字符串在此行为中是完全可互操作的。

因此,在您的示例中,“a”在数字上位于(小于)“b”之前(在 ASCII 和 Unicode 表示中),因此比较就到此结束。'abc' < 'bac'

评论

0赞 davelupt 1/27/2011
那么,一旦发现其中一个字符小于它对应的字符,它是否会立即结束比较?
0赞 user225312 1/27/2011
@David:是的。小于或大于。如果它们相等,则比较接下来的项目。
4赞 Michael J. Barber 1/27/2011 #3

这是词典排序。它只是按字典顺序排列。

评论

0赞 seb 7/11/2017
这实际上是错误的,因为字典在小写字母和大写字母之间没有区别,例如 is while is'a' > 'z'True'a' > 'Z'False
2赞 Senthil Kumaran 1/27/2011 #4

使用字符串字符的数字等价物(内置函数 ord() 的结果)对字符串进行字典比较。Unicode 和 8 位字符串在此行为中是完全可互操作的。

8赞 John Machin 1/27/2011 #5

Python 和几乎所有其他计算机语言都使用与在印刷字典中查找单词时相同的原则(我希望):

(1) 根据所涉及的人类语言,您有一个字符顺序的概念:“a”<“b”<“c”等

(2)第一个字符比第二个字符更重要:“az”<“za”(语言是从左到右还是从右到左书写或从左书写无关紧要)

(3) 如果要测试的字符用完,则较短的字符串小于较长的字符串:“foo”<“food”

通常,在计算机语言中,“字符排序的概念”是相当原始的:每个字符都有一个与人类语言无关的数字,并使用该数字对字符进行比较和排序。通常,这种排序不适合用户的人类语言,然后你需要进入“整理”,一个有趣的话题。ord(character)

6赞 yannis 2/19/2014 #6

另请看如何在 Python 中按字母顺序对 unicode 字符串进行排序?其中讨论的是 Unicode 排序规则算法 (http://www.unicode.org/reports/tr10/) 给出的排序规则。

回复评论

什么?除了从左到右之外,还可以如何定义排序?

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 考虑的是按逻辑顺序编码的字符串,而书写方向是发生在字形级别的现象。换句话说,即使在单词 שלום 中,字母 shin 出现在跛脚的右侧,从逻辑上讲,它出现在它之前。要对这个词进行排序,首先要考虑胫骨,然后是跛脚,然后是 vav,然后是 mem,这是向前排序(尽管希伯来语是从右到左写的),而法语口音是向后排序的(尽管法语是从左到右写的)。

4赞 MSeifert 9/11/2017 #7

字符串比较的纯 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
        # It's not equal so we're finished at this index and can evaluate which is smaller.
        else:
            return ordinal1 < ordinal2
    # We're out of characters and all were equal, so the result depends on the length
    # of the strings.
    return len(string1) < len(string2)

这个函数相当于真正的方法(Python 3.6 和 Python 2.7),只是速度慢得多。另请注意,该实现并不完全是“pythonic”,仅适用于比较。这只是为了说明它是如何工作的。我还没有检查它是否像 Python 比较组合的 unicode 字符一样工作。<

更一般的变体是:

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(char2)
        if ordinal1 == ordinal2:
            continue
        else:
            return op(ordinal1, ordinal2)
    return op(len(string1), len(string2))

评论

0赞 JonBrave 2/26/2019
在这两种情况下,循环都会在最短的字符串末尾终止。然后你不能无条件地返回,如果长于(例如 & ),您需要检查...。Falsestring1string2doggydog
0赞 MSeifert 2/26/2019
@JonBrave 你说的似乎是正确的。你的意思是在决赛前添加一个?我目前不在电脑前,所以我无法检查。稍后会做:)if len(string1) < len(string2): return Truereturn False
0赞 JonBrave 2/27/2019
是的,您需要在最后进行一些测试,以决定是否返回或根据您已经到达两个字符串的末尾(因为它们相等)、更长(也)或更长()。整个事情可以编码为 .FalseTrueFalsestring1Falsestring2Truereturn len(string1) < len(string2)
0赞 Géry Ogam 9/28/2020
为什么不直接代替?else: return op(ordinal1, ordinal2)elif op(ordinal1, ordinal2): return True else: return False
0赞 MSeifert 9/29/2020
@Maggyero 这主要是因为等效的 C 实现有一个,但你的建议是等效的、更短的,而且在我看来也是更好的风格。感谢您指出这一点。else if