development

대소 문자를 구분하지 않는 'in'-Python

big-blog 2020. 6. 27. 10:12
반응형

대소 문자를 구분하지 않는 'in'-Python


나는 표현을 좋아한다

if 'MICHAEL89' in USERNAMES:
    ...

USERNAMES목록이 어디 있어요


대소 문자를 구분하지 않는 항목을 일치시키는 방법이 있습니까? 아니면 사용자 지정 방법을 사용해야합니까? 이를 위해 추가 코드를 작성해야하는지 궁금합니다.

모두에게 감사 드려요!


if 'MICHAEL89' in (name.upper() for name in USERNAMES):
    ...

또는

if 'MICHAEL89' in map(str.upper, USERNAMES):
    ...

또는 사용자 정의 방법을 만들 수 있습니다.


당신이 비 침습적 수 있도록 래퍼를 만들 것 입니다. 최소한, 예를 들어 ... :

class CaseInsensitively(object):
    def __init__(self, s):
        self.__s = s.lower()
    def __hash__(self):
        return hash(self.__s)
    def __eq__(self, other):
        # ensure proper comparison between instances of this class
        try:
           other = other.__s
        except (TypeError, AttributeError):
          try:
             other = other.lower()
          except:
             pass
        return self.__s == other

이제 if CaseInsensitively('MICHAEL89') in whatever:필요에 따라 동작해야합니다 (오른쪽이 목록, dict 또는 set인지 여부). (문자열 포함에 대해 비슷한 결과를 얻으려면 더 많은 노력이 필요할 수 있습니다 unicode.


일반적으로 (적어도 적어도) 원하는 방식으로 동작하도록 객체를 형성합니다. name in USERNAMES대소 문자를 구분하지 않으므로 USERNAMES변경해야합니다.

class NameList(object):
    def __init__(self, names):
        self.names = names

    def __contains__(self, name): # implements `in`
        return name.lower() in (n.lower() for n in self.names)

    def add(self, name):
        self.names.append(name)

# now this works
usernames = NameList(USERNAMES)
print someone in usernames

이것에 대한 좋은 점은 클래스 외부의 코드를 변경하지 않고도 많은 개선을위한 길을 열었다는 것입니다. 예를 들어 self.names빠른 조회를 위해 세트를 변경 하거나 (n.lower() for n in self.names)한 번만 계산 하여 클래스에 저장할 수 있습니다.


추가 코드를 작성해야한다고 생각합니다. 예를 들면 다음과 같습니다.

if 'MICHAEL89' in map(lambda name: name.upper(), USERNAMES):
   ...

이 경우 모든 항목 USERNAMES을 대문자 변환하여 새 목록을 만든 다음이 새 목록과 비교합니다.

최신 정보

으로 @viraptor는 말한다, 대신의 발전기를 사용하는 것이 더 나은 것입니다 map. @Nathon답변을 참조하십시오 .


한 가지 방법이 있습니다.

if string1.lower() in string2.lower(): 
    ...

이것이 작동 하려면 string1string2객체 유형이 모두 이어야합니다 string.


str.casefold is recommended for case-insensitive string matching. @nmichaels's solution can trivially be adapted.

Use either:

if 'MICHAEL89'.casefold() in (name.casefold() for name in USERNAMES):

Or:

if 'MICHAEL89'.casefold() in map(str.casefold, USERNAMES):

As per the docs:

Casefolding is similar to lowercasing but more aggressive because it is intended to remove all case distinctions in a string. For example, the German lowercase letter 'ß' is equivalent to "ss". Since it is already lowercase, lower() would do nothing to 'ß'; casefold() converts it to "ss".


You could do

matcher = re.compile('MICHAEL89', re.IGNORECASE)
filter(matcher.match, USERNAMES) 

Update: played around a bit and am thinking you could get a better short-circuit type approach using

matcher = re.compile('MICHAEL89', re.IGNORECASE)
if any( ifilter( matcher.match, USERNAMES ) ):
    #your code here

The ifilter function is from itertools, one of my favorite modules within Python. It's faster than a generator but only creates the next item of the list when called upon.


My 5 (wrong) cents

'a' in "".join(['A']).lower()

UPDATE

Ouch, totally agree @jpp, I'll keep as an example of bad practice :(

참고URL : https://stackoverflow.com/questions/3627784/case-insensitive-in-python

반응형