ChatGPT解决这个技术问题 Extra ChatGPT

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

如何在 Python 中以不区分大小写的方式比较字符串?

我想使用简单的 Pythonic 代码封装常规字符串与存储库字符串的比较。我还希望能够在使用常规 python 字符串的字符串散列的字典中查找值。


k
kevinpo

假设 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)")

从 Python 3.3 开始,casefold() 是更好的选择:

string1 = 'Hello'
string2 = 'hello'

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

如果您想要一个更全面的解决方案来处理更复杂的 unicode 比较,请参阅其他答案。


这并不总是有效的。例如,考虑有两个希腊 sigma,一个仅在末尾使用。字符串 Σίσυφος(“Sísyphos”,或者更好的“Síſyphos”)具有所有三个:前面的大写字母、结尾的小写字母以及第三个位置的小写 nonfinal。如果您的两个字符串是 ΣίσυφοςΣΊΣΥΦΟΣ,那么您的方法将失败,因为它们应该是不区分大小写的。
@最后两位评论者:我认为假设两个字符串都是ascii字符串是公平的。如果您正在寻找更令人兴奋的事情的答案,我相信它就在那里(或者您可以问它)。
问题:'ß'.lower() == 'SS'.lower() 为假。
希腊字母不是唯一的特例!在美国英语中,字符“i”(\u0069)是字符“I”(\u0049)的小写版本。然而,土耳其语(“tr-TR”)字母表包含一个“I with a dot”字符“İ”(\u0130),它是“i”的大写版本,“I”是“i without一个点”字符,“ı”(\u0131)。
@HarleyHolcombe 假设字符串是ascii如何安全(或公平)?问题没有具体说明,如果字符串在任何时候由用户输入或显示给用户,那么您应该支持国际化。无论如何,新程序员都会阅读这篇文章,我们应该给他们真正正确的答案。
w
wjandrea

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

首先要注意的是,Unicode 中的大小写转换并非微不足道。有 text.lower() != text.upper().lower() 的文本,例如 "ß"

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

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

但是,假设您想不区分大小写地比较 "BUSSE""Buße"。哎呀,您可能还想比较 "BUSSE""BUẞE" 相等 - 这是较新的大写形式。推荐的方法是使用 casefold

str.casefold() 返回字符串的大小写副本。大小写字符串可用于无大小写匹配。大小写折叠类似于小写,但更具侵略性,因为它旨在删除字符串中的所有大小写区别。 [...]

不要只使用 lower。如果 casefold 不可用,则执行 .upper().lower() 会有所帮助(但仅在一定程度上)。

然后你应该考虑重音。如果您的字体渲染器很好,您可能会认为 "ê" == "ê" - 但它没有:

"ê" == "ê"
#>>> False

这是因为后者的重音是一个组合字符。

import unicodedata

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

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

处理此问题的最简单方法是 unicodedata.normalize。您可能想使用 NFKD normalization,但请随时查看文档。然后一个

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

最后,这里用函数表示:

import unicodedata

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

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

更好的解决方案是在输入时对所有字符串进行规范化,然后您只需执行 x.casefold() == y.casefold() 进行不区分大小写的比较(更重要的是,x == y 表示区分大小写)。
@abarnert确实,取决于上下文-有时最好保留源代码不变,但前期规范化也可以使以后的代码更简单。
@Veedrac:你说得对,这并不总是合适的;如果您需要能够以不变的方式输出原始源(例如,因为您正在处理 Linux 上的文件名,其中 NKFC 和 NKFD 都被允许并且明确地应该是不同的),显然您不能在输入时对其进行转换......
Unicode 标准第 3.13 节对无大小写比较有两个其他定义:(D146, canonical) NFD(toCasefold(NFD(str))) 两边和 (D147, compatibility) NFKD(toCasefold(NFKD(toCasefold(NFD(X))))) 两边。它声明内部 NFD 仅用于处理某个希腊重音字符。我想这都是关于边缘情况的。
Casefold()进入大写:>>>“ꮪꭲꮅꭼꭲꭼꮢ”。上()'ꮪꭲꮅꭼꭲꭼꮢ'>>>“ꮪꭲꮅꭼꭲꭼꮢ”。下()'>>'>>>“ꮪꭲꮅꭼꭲꭼꮢ”, .casefold() 'ᏚᎢᎵᎬᎢᎬᏒ' >>>
K
Kaushik NP

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

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

...大部分时间都可以使用,但在 situations @tchrist has described 中确实不起作用。

假设我们有一个名为 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(另请参见:icu-project.org/apiref/icu4c/…
j
jfs

Section 3.13 of the Unicode standard 定义了无大小写匹配的算法。

Python 3 中的 X.casefold() == Y.casefold() 实现了“默认无大小写匹配”(D144)。

大小写折叠不会在所有实例中保留字符串的规范化,因此需要进行规范化('å''å')。 D145 引入了“规范无大小写匹配”:

import unicodedata

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

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

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

例子:

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

对于 '㎒' (U+3392) 和“标识符无大小写匹配”等情况,还有兼容性无大小写匹配 (D146),以简化和优化 caseless matching of identifiers


这是 Python 3 的最佳答案,因为 Python 3 使用 Unicode 字符串,并且答案描述了 Unicode 标准如何定义无大小写字符串匹配。
不幸的是,从 Python 3.6 开始,casefold() 函数没有实现 Case Folding Properties 中描述的大写 I 和带点大写 I 的特殊情况处理。因此,对于包含这些字母的突厥语单词,比较可能会失败。例如,canonical_caseless('LİMANI') == canonical_caseless('limanı') 必须返回 True,但它返回 False。目前,在 Python 中处理此问题的唯一方法是编写 casefold 包装器或使用外部 Unicode 库,例如 PyICU。
@SergiyKolesnikov .casefold() 据我所知,它的行为应该如此。来自标准:“默认大小写操作旨在用于在缺少为特定语言和环境进行剪裁的情况下”。土耳其点状大写字母 I 和无点小写字母 i 的大小写规则在 SpecialCasing.txt 中。 “对于非突厥语言,通常不使用此映射。” 来自 Unicode 常见问题解答:Q: Why aren't there extra characters encoded to support locale-independent casing for Turkish?
@jf-sebastian 我没有说 casefold() 行为不端。如果它实现了一个可选参数来启用对大写和点大写 I 的特殊处理,这将是实用的。例如,the foldCase() in the ICU library does it 的方式:“大小写折叠与语言环境无关且不区分上下文,但有一个是否包含或排除在 CaseFolding.txt 中标记为“T”的点 I 和无点 i 的映射的选项。”
@jfs 感谢您分享此解决方案。它对我有用。
C
Community

我使用 regex 看到了这个解决方案 here

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 中找不到 ß 的事实证明它不起作用根本无法处理 Unicode 字符
m
mpriya

您可以使用 casefold() 方法。 casefold() 方法在比较时会忽略大小写。

firstString = "Hi EVERYONE"
secondString = "Hi everyone"

if firstString.casefold() == secondString.casefold():
    print('The strings are equal.')
else:
    print('The strings are not equal.')

输出:

The strings are equal.

A
Andru Luvisi

通常的方法是将字符串大写或小写以进行查找和比较。例如:

>>> "hello".upper() == "HELLO".upper()
True
>>> 

C
Camilo Díaz Repka

先转换成小写怎么样?您可以使用 string.lower()


您无法比较它们的小写映射:ΣίσυφοςΣΊΣΥΦΟΣ 不会测试等效,但应该。
m
mpriya

您可以在 str.contains() 中提及 case=False

data['Column_name'].str.contains('abcd', case=False)

z
zackakshay
def search_specificword(key, stng):
    key = key.lower()
    stng = stng.lower()
    flag_present = False
    if stng.startswith(key+" "):
        flag_present = True
    symb = [',','.']
    for i in symb:
        if stng.find(" "+key+i) != -1:
            flag_present = True
    if key == stng:
        flag_present = True
    if stng.endswith(" "+key):
        flag_present = True
    if stng.find(" "+key+" ") != -1:
        flag_present = True
    print(flag_present)
    return flag_present

输出:search_specificword("经济适用房", "到欧洲经济适用房的核心") False

search_specificword("经济适用房", "到经济适用房的核心,在欧洲") True


P
Patrick Harrington
def insenStringCompare(s1, s2):
    """ Method that takes two strings and returns True or False, based
        on if they are equal, regardless of case."""
    try:
        return s1.lower() == s2.lower()
    except AttributeError:
        print "Please only pass strings into this method."
        print "You passed a %s and %s" % (s1.__class__, s2.__class__)

您正在用打印到标准输出的消息替换异常,然后返回 None,即 False。这在实践中是非常无益的。
A
Ali Paul

这是我在上周学会爱/恨的另一个正则表达式,所以通常导入(在这种情况下是的)反映我感觉的东西!做一个正常的功能....请求输入,然后使用 ....something = re.compile(r'foo*|spam*', yes.I)...... re.I (yes.I下面)与 IGNORECASE 相同,但你不能在编写它时犯尽可能多的错误!

然后,您使用正则表达式搜索您的消息,但老实说,这应该是它自己的几页,但关键是 foo 或垃圾邮件被一起传送并且忽略大小写。然后,如果找到其中任何一个,则 lost_n_found 将显示其中一个。如果两者都没有,那么 lost_n_found 等于 None。如果它不等于 none,则使用“return lost_n_found.lower()”以小写形式返回 user_input

这使您可以更轻松地匹配任何区分大小写的内容。最后(NCS)代表“没有人认真对待......!”或不区分大小写....无论哪个

如果有人有任何问题,请告诉我这个..

    import re as yes

    def bar_or_spam():

        message = raw_input("\nEnter FoO for BaR or SpaM for EgGs (NCS): ") 

        message_in_coconut = yes.compile(r'foo*|spam*',  yes.I)

        lost_n_found = message_in_coconut.search(message).group()

        if lost_n_found != None:
            return lost_n_found.lower()
        else:
            print ("Make tea not love")
            return

    whatz_for_breakfast = bar_or_spam()

    if whatz_for_breakfast == foo:
        print ("BaR")

    elif whatz_for_breakfast == spam:
        print ("EgGs")