[python] 대소 문자를 구분하지 않는 문자열 비교는 어떻게합니까?

파이썬에서 대소 문자를 구분하지 않는 문자열 비교를 어떻게 할 수 있습니까?

매우 간단하고 Pythonic 방식으로 일반 문자열과 저장소 문자열의 비교를 캡슐화하고 싶습니다. 또한 일반 파이썬 문자열을 사용하여 문자열로 해시 된 dict에서 값을 조회 할 수 있기를 원합니다.



답변

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


답변

대소 문자를 구분하지 않는 방식으로 문자열을 비교하는 것은 사소한 것처럼 보이지만 그렇지 않습니다. 파이썬 2는 여기서 개발되지 않았기 때문에 파이썬 3을 사용할 것입니다.

가장 먼저 알아 두어야 할 것은 유니 코드로 대 / 소문자를 변환하는 변환은 쉽지 않다는 것입니다. 다음 text.lower() != text.upper().lower()과 같은 텍스트가 있습니다 "ß".

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

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

그러나 대소 문자를 비교 "BUSSE"하고 싶었다고 가정 해 봅시다 "Buße". 도대체 아마도 당신은 아마도 비교 "BUSSE"하고 "BUẞE"평등 하기를 원할 것입니다 -그것이 새로운 자본 형태입니다. 권장되는 방법은 다음을 사용하는 것입니다 casefold.

str. 케이스 ()

문자열의 대소 문자를 복사하십시오. 대소 문자를 구분하는 문자열은 대소 문자를 구분하기 위해 사용할 수 있습니다.

케이스 폴딩은 소문자와 비슷하지만 문자열에서 모든 케이스 구별을 제거하기 때문에 더 공격적입니다. […]

그냥 사용하지 마십시오 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)


답변

Python 2를 사용하여 .lower()각 문자열 또는 유니 코드 객체를 호출 합니다 …

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

… 대부분의 시간 동안 작동하지만 실제로 @tchrist가 설명한 상황 에서는 작동하지 않습니다 .

unicode.txt두 개의 문자열 Σίσυφος과를 포함 하는 파일이 있다고 가정합니다 ΣΊΣΥΦΟΣ. 파이썬 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

따라서 그리스어로 된 세 시그마와 같은 엣지 케이스에 관심이 있다면 Python 3을 사용하십시오.

(참고로 Python 2.7.3 및 Python 3.3.0b1은 위의 인터프리터 출력물에 표시되어 있습니다.)


답변

유니 코드 표준의 섹션 3.13은 대소 문자를 구분하지 않는 알고리즘을 정의합니다.

X.casefold() == Y.casefold() 파이썬 3에서는 “기본 대소 문자 일치하지 않음”(D144)을 구현합니다.

케이스 폴딩은 모든 경우에 문자열 정규화를 유지하지 않으므로 정규화를 수행해야합니다 ( 'å'vs 'å'). D145는 “정규 사례없는 일치”를 소개합니다.

import unicodedata

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

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

NFD() U + 0345 문자와 관련된 매우 드문 경우에 대해 두 번 호출됩니다.

예:

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

'㎒'(U + 3392) 및 “식별자 케이스리스 매칭”과 같은 경우에 대한 케이스리스 매칭 (D146) 호환성이있어 식별자의 케이스리스 매칭을 단순화하고 최적화 할 있습니다.


답변

나는이 솔루션을보고 여기에 사용 정규식 .

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

악센트와 잘 어울립니다.

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

그러나 대소 문자를 구분하지 않는 유니 코드 문자에는 작동하지 않습니다. 사실을 이해하기 위해서는 정확한 기호가 필요하다는 것을 이해했기 때문에 @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)
....:


답변

조회 및 비교를 위해 문자열을 대문자 또는 소문자로 사용하는 것이 일반적입니다. 예를 들면 다음과 같습니다.

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


답변

먼저 소문자로 변환하는 것은 어떻습니까? 사용할 수 있습니다 string.lower().