[python] 대소 문자를 구분하지 않는 ‘입력’

나는 표현을 좋아한다

if 'MICHAEL89' in USERNAMES:
    ...

USERNAMES목록은 어디에 있습니까 ?


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



답변

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

또는

if username.upper() 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)한 번만 계산 하여 클래스에 저장할 수 있습니다.


답변

str.casefold대소 문자를 구분하지 않는 문자열 일치에 권장됩니다. @nmichaels의 솔루션 은 사소하게 적용될 수 있습니다.

다음 중 하나를 사용하십시오.

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

또는:

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

당으로 문서 :

케이스 폴딩은 소문자와 비슷하지만 문자열에서 모든 케이스 구별을 제거하기 때문에 더 공격적입니다. 예를 들어 독일어 소문자 ‘ß’는 “ss”와 같습니다. 이미 소문자이므로 lower()‘ß’에는 아무 것도하지 않습니다. casefold()
“ss”로 변환합니다.


답변

한 가지 방법이 있습니다.

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

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


답변

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

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

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

최신 정보

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


답변

넌 할 수있어

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

업데이트 : 조금 놀았고 다음을 사용하여 더 나은 단락 유형 접근법을 얻을 수 있다고 생각합니다

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

ifilter함수는 파이썬에서 내가 가장 좋아하는 모듈 중 하나 인 itertools에서 온 것입니다. 생성기보다 빠르지 만 호출 될 때 목록의 다음 항목 만 작성합니다.