파이썬
기본 데이터 타입
문자열
비교

파이썬 문자열 비교: __eq__(), 부등호, 알고리즘, 시간 복잡도, 대소문자 무시, 리스트 비교

이번 포스팅은 파이썬 문자열 비교 와 관련해서 자주 찾는 내용을 정리해보았습니다.

1. __eq__() 메서드

__eq__()메서드는 파이썬의 특수 메서드 중 하나로, 두 객체가 같은지 여부를 비교하는 데 사용됩니다. 이 메서드는 ==연산자를 사용하여 두 객체를 비교할 때 알아서 호출됩니다. 파이썬 문자열 비교 연산도 ==연산자를 사용하므로 이 메서드를 호출합니다.

즉, "Hello" == "hello"를 실행하면 파이썬은 사실 내부적으로 "Hello".__eq__("hello")를 호출하는 것입니다.

만약, 위 코드처럼 실행하면, 다음과 같이 두 문자열은 다르다는 결과가 나옵니다.

str1 = 'Hello'
str2 = 'hello'
 
print(str1 == str2)  # 출력: False

그 이유는, 파이썬의 문자열을 나타내는 내장 클래스 str내부에 정의한 __eq__()메서드가 대소문자를 구분하기 때문입니다.

이처럼 ==연산자를 사용하는 모든 파이썬 내장 클래스는 __eq__()메서드를 클래스 내부에 정의했다고 볼 수 있습니다. 우리도 어떤 클래스의 __eq__()메서드를 새롭게 정의해서 ==연산자의 동작을 커스텀할 수 있고요. 만약, 이 메서드가 없는 경우, 파이썬은 기본적으로 두 객체의 메모리 주소를 비교합니다.

다음 예제에서는 대소문자를 구분하지 않고 비교하는 새로운 문자열 클래스 CaseInsensitiveStr를 정의합니다. __eq__()메서드가 어떻게 정의되었는지 확인해보세요.

class CaseInsensitiveStr:
 
    def __init__(self, str_):
        self.str_ = str_.lower()
 
    def __eq__(self, other):
        if isinstance(other, CaseInsensitiveStr):
            return self.str_ == other.str_
        elif isinstance(other, str):
            return self.str_ == other.lower()
        return False
 
str1 = CaseInsensitiveStr('Hello')
str2 = CaseInsensitiveStr('hello')
 
print(str1 == str2)  # 출력: True

2. 문자열 비교 시, 부등호 사용

파이썬에서 문자열을 비교할 때, 부등호는 다음의 2가지 용도로 사용할 수 있습니다.

  • 사전식 순서를 나타낸다
  • 포함관계를 나타낸다

2.1. 사전식 순서를 나타내는 부등호

첫 번째부터 알아보겠습니다. 파이썬은 영문자 비교를 위해서 ASCII 값, 한글 비교를 위해서는 유니코드 값 (주로, utf-8) 에 기반합니다.

만약 다음과 같이 알파벳 ab를 비교한다면, 사실은 이 두 문자의 아스키 값을 비교하는 것입니다. ord()함수는 특정 문자의 (아스키코드를 포함한) 유니코드 코드 포인트를 반환하는 내장 함수로 모든 문자의 숫자값을 알 수 있습니다.

print("a" == "b") # 이 비교는 사실
print(ord("a") == ord("a"))  # 이 비교입니다.

이와 동일한 원리로, 문자열 비교에 부등호 >, <를 사용한다면, 유니코드 코드 포인트의 값을 비교하게 됩니다. 이 값은 알파벳, 한글 둘 다 사전순으로 크기가 커집니다. a보다 z가 크고, 대문자보다 소문자가 크며, 보다 이 큽니다.

print("a" < "z") # 출력: True
print("A" < "a") # 출력: True
print("강" < "한") # 출력: True

특히 한글은 자모음 하나하나가 유니코드를 갖기도 하고, 조합된 문자 하나가 유니코드를 갖기도 합니다. 즉, 같은 "한"이라는 글자라도 유니코드 값이 다를 수 있습니다. 이 점 유의해주세요.

ord("ㅎ")  # 출력: 12622
ord("한")  # 출력: 54620

2.2. 포함 관계를 나타내는 부등호

두 번째 용도는 문자열 간의 포함관계입니다.

파이썬에서 둘 이상의 문자로 이루어진 문자열을 서로 비교하면, 가장 앞 요소부터 차례대로 하나씩 비교하게 됩니다. 만약, 한 문자열이 다른 문자열의 부분 문자열일 경우, 어느 순간 문자와 공백을 비교할 일이 생깁니다. 이 때, 길이가 더 긴 문자열이 큰 것으로 판별됩니다.

코드로 확인해봅니다.

print("나무" > "나") 출력: True

"나""나무의 부분 문자열이기 때문에 항상 작은 값으로 판별됩니다.

이 내용을 언급하는 이유는 문자열 포함 관계에 부등호를 사용하라는 것이 아니라,파이썬의 문자열 비교 원리를 알 수 있기 때문입니다. 우리에겐 포함 여부를 판별하는 in이라는 강력한 키워드가 있습니다.

3. 파이썬의 문자열 비교 알고리즘과 시간복잡도

파이썬 문자열 비교 알고리즘은 직관적입니다. 두 개의 문자열을 비교하기 위해서, 파이썬은 같은 인덱스에 위치한 문자 2개를 앞에서부터 비교합니다.

이 때문에 만약, "안녕하세요" == "안녕하세유"처럼 최대한의 연산이 필요한 경우에 시간복잡도 O(n)을 갖습니다.

4. 대소문자를 무시하거나, 무시하지 않는 비교 연산

섹션 1에서 언급했듯이, 파이썬의 str클래스는 대소문자를 구분하도록 __eq__()메서드를 구현해놓았습니다. 만약, 두 문자열의 대소문자를 구분하지 않고 비교하고자 하면 str클래스의 upper()메서드나 lower()메서드를 활용할 수 있습니다.

이름 그대로 upper()메서드는 특정 문자열의 문자를 모두 대문자로, lower()메서드는 특정 문자열의 문자를 소문자로 변환한 새 문자열을 반환합니다. 이 때문에, 대소문자를 무시하고 비교하기에 용이합니다.

예제 코드로 확인해보겠습니다.

lower_case = "happy"
mixed_case = "HaPPy"
 
print(lower_case == mixed_case) # 출력: False
print(lower_case.upper() == mixed_case.upper()) # 출력: True

이렇게 대소문자 구분 없이 파이썬 문자열 비교 결과를 얻을 수 있습니다.

5. 문자열 리스트 비교

파이썬 문자열과 리스트는 서로 데이터 타입이 다릅니다. 그래서, 그대로 비교하면 언제나 False 값이 나옵니다.

print(["a", "b", "c"] == "abc") # 출력: False

두 데이터 타입의 내용이 일치하는지 비교하기 위해서는 데이터 타입을 일치시켜줘야 합니다. 이를 위해, 다음 2가지 방법을 사용할 수 있습니다.

5.1. 문자열을 리스트로 변환하는 list() 함수

첫 번째 방법은 문자열을 리스트로 변환합니다. 파이썬의 list()함수는 다양한 데이터 타입을 리스트로 변환하는 간편한 함수입니다.

다음과 같이 사용합니다.

print(list("abc")) # 출력: ["a", "b", "c"]
print(["a", "b", "c"] == list("abc")) # 출력: True

데이터 타입이 같아졌기 때문에, 두 리스트의 요소를 비교해서 True값을 반환했습니다.

5.2. 리스트를 문자열로 변환하는 join() 메서드

또 다른 방법으로, 리스트를 문자열로 변환한 후 비교합니다.

이를 위해서는, join()메서드를 사용합니다. 이 메서드는 리스트의 모든 요소를 하나의 문자열로 합칩니다.

print("".join(["a", "b", "c"])) # 출력: "abc"
print("".join(["a", "b", "c"]) == "abc") # 출력: True

같은 문자열 타입이 되어서, 내용을 비교할 수 있었습니다.

6. 마치며

지금까지 파이썬 문자열 비교 관련 자주 찾는 내용 5가지를 살펴보았습니다. 이 포스팅을 통해 궁금한 부분을 해결하길 바랍니다.

copyright for Python string find

© 2023 All rights reserved.