当前位置:  开发笔记 > 编程语言 > 正文

如何进行不区分大小写的字符串比较?

如何解决《如何进行不区分大小写的字符串比较?》经验,为你挑选了5个好方法。

如何在Python中进行不区分大小写的字符串比较?

我想以一种非常简单和Pythonic的方式将常规字符串的比较封装到存储库字符串中.我还希望能够使用常规python字符串在字符串中查找值.



1> Harley Holco..:

假设ASCII字符串:

string1 = 'Hello'
string2 = 'hello'

if string1.lower() == string2.lower():
    print("The strings are the same (case insensitive)")
else:
    print("The strings are NOT the same (case insensitive)")


这并不总是奏效.考虑一下,有两个希腊西格玛,一个只在最后使用.字符串*Σίσυφος*("Sísyphos",或更好的"Sísyphos")有三个:前面是大写,末尾是小写,最后是第三个小写.如果你的两个字符串是`Σίσυφος`和`ΣΊΣΥΦΟΣ`,那么你的方法就会失败,因为它们应该是不相同的情况.
@最后两位评论者:我认为假设两个字符串都是ascii字符串是公平的.如果你正在寻找一些更令人兴奋的答案我肯定它在那里(或者你可以问它).
@HarleyHolcombe假设字符串是ascii是安全(或公平)的?问题没有说明,如果字符串是在用户输入或显示给用户的任何点,那么你应该支持国际化.无论如何,新的程序员将阅读这个,我们应该给他们真正正确的答案.
问题:''ß'.lower()=='SS'.lower()`是假的.
希腊字母不是唯一的特例!在美国英语中,字符"i"(\ u0069)是字符"I"(\ u0049)的小写版本.然而,土耳其语("tr-TR")字母表包括"I with a dot"字符"İ"(\ u0130),这是"i"的首字版本,"I"是"我没有"的captical版本点"字符",ı"(\ u0131).
.lower()方法将在Python 3中使用,至少对于上面提到的两个希腊字符串.有关详细信息,请参阅我的回答
@exic,维基百科的文章非常清楚,根据大多数德国人的说法,"资本Eszett"不是真正的信件.它以Unicode编码,因此可以表示某些印刷的好奇心,但这与KennyTM的观点无关.(也就是说,你认为德语和土耳其语应该改变他们的写作系统,以便用Python语义更好地发挥作用,但更常见的是反过来说:Python应该找到一种处理德语和土耳其语系统的方法,因为它们被用于真正的德国和土耳其人.)
@Rhymoid是的.它甚至不能用于"专用英语"文本,例如,"fi sh".casefold()=="Fish".casefold()`工作,而`.lower()`在这里失败.虽然可能存在[甚至`.casefold()`还不够](http://stackoverflow.com/a/40551443/4279)
@ user3932000换句话说,这个答案只适用于处理真正完全是英语的文本.对于大多数人来说,即母语不是英语的人,必须处理l10n/i18n问题的人,以及必须处理Unicode输入卫生的人,这意味着这个答案是错误的**.
@ user3932000那么在任何专业背景下答案都毫无意义.这不是以不区分大小写的方式比较字符串的正确方法.这是一种在某些特定情况下不会中断的解决方法.

2> Veedrac..:

以不区分大小写的方式比较字符串似乎是微不足道的,但事实并非如此.我将使用Python 3,因为Python 2在这里不发达.

首先要注意的是,在unicode中删除大小写的转换并非易事.有文字text.lower() != text.upper().lower(),例如"ß":

"ß".lower()
#>>> 'ß'

"ß".upper().lower()
#>>> 'ss'

但是,让我们说你想无谓地比较"BUSSE""Buße".哎呀,你可能也想比较"BUSSE""BU?E"平等 - 这是更新的资本形式.推荐的方法是使用casefold:

"ê" == "e?"
#>>> False

不要只是使用lower.如果casefold不可用,做.upper().lower()帮助(但只是有点).

那你应该考虑口音.如果您的字体渲染器很好,您可能会想"ê" == "e?"- 但它不是:

import unicodedata

[unicodedata.name(char) for char in "ê"]
#>>> ['LATIN SMALL LETTER E WITH CIRCUMFLEX']

[unicodedata.name(char) for char in "e?"]
#>>> ['LATIN SMALL LETTER E', 'COMBINING CIRCUMFLEX ACCENT']

这是因为它们实际上是

unicodedata.normalize("NFKD", "ê") == unicodedata.normalize("NFKD", "e?")
#>>> True

解决这个问题最简单的方法是unicodedata.normalize.您可能想要使用NFKD规范化,但请随时查看文档.然后一个人

import unicodedata

def normalize_caseless(text):
    return unicodedata.normalize("NFKD", text.casefold())

def caseless_equal(left, right):
    return normalize_caseless(left) == normalize_caseless(right)

最后,这里用函数表示:

"ß".lower()
#>>> 'ß'

"ß".upper().lower()
#>>> 'ss'


Unicode标准第3.13节有两个其他无外壳比较的定义:(D146,规范)`NFD(toCasefold(NFD(str)))`两边和(D147,兼容性)`NFKD(toCasefold(NFKD(toCasefold)(NFD(X) )))))``两边.它声明内部的"NFD"仅仅是为了处理某种希腊口音特征.我想这都是边缘情况.
一个更好的解决方案是在摄取时规范化所有字符串,然后你可以做`x.casefold()== y.casefold()`进行不区分大小写的比较(更重要的是,`x == y`表示情况-敏感).
@abarnert确实,根据上下文 - 有时最好保持源完整,但前期规范化也可以使后面的代码更简单.
@Veedrac:你是对的,并不总是合适的; 如果你需要能够输出原始来源不变(例如,因为你在Linux上处理文件名,其中NKFC和NKFD都被允许并明确地认为是不同的),显然你不能在输入上转换它...
切诺基字母有点有趣,其中casefold()变为大写:>>>“ᏚᎢᎵᎬᎢᎬᏒ”。upper()'ᏚᎢᎵᎬᎢᎬᏒ'>>>“ᏚᎢᎵᎬᎢᎬᏒ”。lower()'ꮪꭲꮅꭼꭲꭼꮢ'>>>“ᏚᎢᎵᎬᎢᎬᏒ” .casefold()'ᏚᎢᎵᎬᎢᎬᏒ'>>>

3> Nathan Craik..:

使用Python 2,调用.lower()每个字符串或Unicode对象......

string1.lower() == string2.lower()

......大部分时间都会工作,但在@tchrist描述的情况下确实不起作用.

假设我们有一个名为unicode.txt包含两个字符串??????????????.使用Python 2:

>>> utf8_bytes = open("unicode.txt", 'r').read()
>>> print repr(utf8_bytes)
'\xce\xa3\xce\xaf\xcf\x83\xcf\x85\xcf\x86\xce\xbf\xcf\x82\n\xce\xa3\xce\x8a\xce\xa3\xce\xa5\xce\xa6\xce\x9f\xce\xa3\n'
>>> u = utf8_bytes.decode('utf8')
>>> print u
???????
???????

>>> first, second = u.splitlines()
>>> print first.lower()
???????
>>> print second.lower()
???????
>>> first.lower() == second.lower()
False
>>> first.upper() == second.upper()
True

Σ字符有两个小写形式,ς和σ,并且.lower()无助于比较它们不区分大小写.

但是,从Python 3开始,所有三种形式都将解析为ς,并且在两个字符串上调用lower()将正常工作:

>>> s = open('unicode.txt', encoding='utf8').read()
>>> print(s)
???????
???????

>>> first, second = s.splitlines()
>>> print(first.lower())
???????
>>> print(second.lower())
???????
>>> first.lower() == second.lower()
True
>>> first.upper() == second.upper()
True

因此,如果您关注像希腊语中的三个sigma这样的边缘情况,请使用Python 3.

(作为参考,Python 2.7.3和Python 3.3.0b1显示在上面的解释器打印输出中.)


为了使比较更加健壮,从Python 3.3开始,您可以使用casefold(例如,first.casefold()== second.casefold()).对于Python 2,您可以使用PyICU(另请参阅:http://icu-project.org/apiref/icu4c/classicu_1_1UnicodeString.html#a76f9027fbe4aa6f5b863c2a4a7148078)

4> jfs..:

Unicode标准的第3.13节定义了无壳匹配的算法.

X.casefold() == Y.casefold() 在Python 3中实现了"默认的无壳匹配"(D144).

Casefolding不保留所有实例中字符串的规范化,因此需要进行规范化('å'vs. 'a?').D145引入了"规范无壳匹配":

import unicodedata

def NFD(text):
    return unicodedata.normalize('NFD', text)

def canonical_caseless(text):
    return NFD(NFD(text).casefold())

NFD() 对于涉及U + 0345字符的非常罕见的边缘情况,会被调用两次.

例:

>>> 'å'.casefold() == 'a?'.casefold()
False
>>> canonical_caseless('å') == canonical_caseless('a?')
True

对于诸如'?'(U + 3392)和"标识符无标记匹配"的情况,还存在兼容性无情况匹配(D146),以简化和优化标识符的无边界匹配.


这是Python 3的最佳答案,因为Python 3使用Unicode字符串,答案描述了Unicode标准如何定义无外壳字符串匹配.

5> 小智..:

我看到这个解决方案在这里使用正则表达式.

import re
if re.search('mandy', 'Mandy Pande', re.IGNORECASE):
# is True

它适用于重音

In [42]: if re.search("ê","ê", re.IGNORECASE):
....:        print(1)
....:
1

但是,它不适用于不区分大小写的unicode字符.谢谢你@Rhymoid指出,因为我的理解是它需要精确的符号,因为情况是真的.输出如下:

In [36]: "ß".lower()
Out[36]: 'ß'
In [37]: "ß".upper()
Out[37]: 'SS'
In [38]: "ß".upper().lower()
Out[38]: 'ss'
In [39]: if re.search("ß","ßß", re.IGNORECASE):
....:        print(1)
....:
1
In [40]: if re.search("SS","ßß", re.IGNORECASE):
....:        print(1)
....:
In [41]: if re.search("ß","SS", re.IGNORECASE):
....:        print(1)
....:


使用不区分大小写的搜索在`SS`中找不到`ß`的事实证明它**不起作用**完全使用**字符**.
推荐阅读
家具销售_903
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有