development

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

big-blog 2020. 2. 12. 23:38
반응형

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


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

매우 간단하고 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() Python 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().


이것은 지난 주에 사랑 / 증오하는 법을 배운 또 다른 정규 표현식이므로 일반적으로 임 느낌을 반영하는 것으로 가져옵니다 (이 경우 예). 정상적인 기능을 만드십시오 .... 입력을 요청한 다음 .... 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")

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

문자열이있는 목록이 있고 다른 목록의 문자열을 대소 문자를 구분하지 않고 비교하려는 경우. 여기 내 해결책이 있습니다.

list1 = map(lambda each:each.lower(), list1)
list2 = map(lambda each:each.lower(), list2)

그런 다음 문자열 비교를 쉽게 할 수 있습니다.


나는 이것을 사용하여 두 문자열을 비교하는 데 더 유용한 것을 달성했습니다.

def strings_iequal(first, second):
    try:
        return first.upper() == second.upper()
    except AttributeError:
        if not first:
            if not second:
                return True

업데이트 : gerrit 에서 언급 했듯이이 답변에는 몇 가지 버그가 있습니다. 이것은 몇 년 전이었고 더 이상 내가 사용한 것을 기억하지 못합니다. 작문 시험을 기억하지만 지금은 좋은 점이 있습니다!

참고 URL : https://stackoverflow.com/questions/319426/how-do-i-do-a-case-insensitive-string-comparison



반응형