web-dev-qa-db-ja.com

大文字と小文字を区別しないで文字列を比較する方法

Pythonで大文字と小文字を区別しない文字列比較を行うにはどうすればいいですか?

通常の文字列とリポジトリ文字列の比較を、非常に単純でPythonicの方法でカプセル化したいと思います。私はまた、通常のpython文字列を使って文字列でハッシュされた辞書内の値を検索する機能を持ちたいです。

462
Kozyarchuk

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)")
492
Harley Holcombe

大文字と小文字を区別しない方法で文字列を比較するのは簡単なことのようですが、違います。ここではPython 2の開発が遅れているので、Python 3を使用します。

最初に注意しなければならないのは、Unicodeでの大文字小文字の区別のない変換は簡単なことではないということです。 "ß"のようなtext.lower() != text.upper().lower()のテキストがあります。

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

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

しかし、"BUSSE""Buße"を大文字と小文字を区別せずに比較したいとしましょう。ねえ、あなたはおそらく"BUSSE""BUẞE" equalを比較したいでしょう - それは新しい大文字の形式です。推奨される方法はcasefoldを使うことです。

help(str.casefold)
#>>> Help on method_descriptor:
#>>>
#>>> casefold(...)
#>>>     S.casefold() -> str
#>>>     
#>>>     Return a version of S suitable for caseless comparisons.
#>>>

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 _ 正規化を使用したいと思うかもしれませんが、気軽に文書をチェックしてください。それから一つ

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)
406
Veedrac

Python 2を使用して、各文字列またはUnicodeオブジェクトに対して.lower()を呼び出す.

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

...ほとんどの場合動作しますが、@tchristが説明した の状況では実際には動作しません

unicode.txtΣίσυφοςの2つの文字列を含むΣΊΣΥΦΟΣというファイルがあるとします。 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

Σ文字は2つの小文字形式、σとσを持ち、.lower()は大文字小文字を区別せずにそれらを比較するのを助けません。

ただし、Python 3では、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

ですから、ギリシャ語の3つのシグマのようなEdge-caseが気になる場合は、Python 3を使用してください。

(参考のために、Python 2.7.3とPython 3.3.0b1は上記のインタプリタの出力に示されています。)

57
Nathan Craike

Unicode規格のセクション3.13 は、大文字と小文字を区別しないマッチングのためのアルゴリズムを定義します。

Python 3のX.casefold() == Y.casefold()は "デフォルトの大文字と小文字を区別しないマッチング"(D144)を実装しています。

Casefoldingはすべてのインスタンスで文字列の正規化を保存するわけではないため、正規化を行う必要があります('å''å')。 D145では「正規のケースレスマッチング」が導入されています。

import unicodedata

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

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

NFD()は、U + 0345文字を含む非常にまれなEdgeの場合に2回呼び出されます。

例:

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

'㎒'U + 3392)や簡素化し最適化するための "identifier caseless matching"などのケースに対する互換性のあるcaseless matching(D146)もあります(identifierのcaselessマッチング

26
jfs

私はこの解決策を見ました ここ using regex

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)
....:
7
Shiwangi

最初に小文字に変換するのはどうですか。 string.lower()を使うことができます。

3

通常のアプローチは、検索と比較のために文字列を大文字にするか小文字にすることです。例えば:

>>> "hello".upper() == "HELLO".upper()
True
>>> 
2
Andru Luvisi

これは先週の間に私が愛/憎しみを持つことを学んだもう一つの正規表現です。通常の関数を作成します。入力を要求してから、.... something = re.compile(r'foo * | spam * '、yes.I)...... re.I(yes.I)を使用します。下記)はIGNORECASEと同じですが、あなたはそれを書くのと同じくらい多くの間違いをすることはできません!

それからregexを使ってあなたのメッセージを検索しますが、正直なところそれはそれ自身で数ページであるべきですが、ポイントはfooかスパムが一緒にパイプでつながれて大文字小文字の区別が無視されることです。その後、どちらかが見つかった場合、lost_n_foundはそれらのうちの1つを表示します。どちらでもない場合、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")
0
Ali Paul