it-swarm-ko.tech

Python 문자열에서 대소 문자 무시

대소 문자를 무시하고 파이썬에서 문자열을 비교하는 가장 쉬운 방법은 무엇입니까?

물론 (str1.lower () <= str2.lower ()) 등을 수행 할 수는 있지만 두 개의 추가 임시 문자열 (명백한 alloc/g-c 오버 헤드 포함)이 생성되었습니다.

나는 C의 stricmp ()와 동등한 것을 찾고 있다고 생각합니다.

[더 많은 컨텍스트가 요청되었으므로 간단한 예를 들어 설명하겠습니다.]

빈 문자열 목록을 정렬하려고한다고 가정하십시오. 간단히 List.sort ()를 수행하십시오. 이것은 O (n * log (n)) 문자열 비교이며 메모리 관리가 없습니다 (모든 문자열과 목록 요소가 일종의 스마트 포인터이므로). 당신은 행복하다.

이제는 똑같이하고 싶지만 사례를 무시하십시오 (간단히 말하고 모든 문자열이 ASCII이므로 로케일 문제는 무시할 수 있음). List.sort (key = lambda s : s.lower ())를 수행 할 수 있지만 비교 당 두 개의 새로운 할당이 발생하고 가비지 수집기에는 중복 된 (낮은) 문자열이 필요합니다. 이러한 메모리 관리 노이즈는 단순한 문자열 비교보다 수십 배 느립니다.

이제는 stricmp ()와 같은 함수를 사용하여 theList.sort (cmp = stricmp)를 수행하면 List.sort ()와 같이 빠르고 메모리 친화적입니다. 당신은 다시 행복합니다.

문제는 파이썬 기반의 대소 문자를 구분하지 않는 비교에 암시 적 문자열 복제가 포함되므로 C 기반 비교 (모듈 문자열에 있음)를 찾을 것으로 기대했습니다.

그런 것을 찾을 수 없으므로 여기서 질문하십시오. (이것이 질문을 분명히하기를 바랍니다).

51
Paul Oyster

다음은 str.lower 사용이 허용 된 답변의 제안 된 방법 (libc.strcasecmp)보다 빠르다는 것을 보여주는 벤치 마크입니다.

#!/usr/bin/env python2.7
import random
import timeit

from ctypes import *
libc = CDLL('libc.dylib') # change to 'libc.so.6' on linux

with open('/usr/share/dict/words', 'r') as wordlist:
    words = wordlist.read().splitlines()
random.shuffle(words)
print '%i words in list' % len(words)

setup = 'from __main__ import words, libc; gc.enable()'
stmts = [
    ('simple sort', 'sorted(words)'),
    ('sort with key=str.lower', 'sorted(words, key=str.lower)'),
    ('sort with cmp=libc.strcasecmp', 'sorted(words, cmp=libc.strcasecmp)'),
]

for (comment, stmt) in stmts:
    t = timeit.Timer(stmt=stmt, setup=setup)
    print '%s: %.2f msec/pass' % (comment, (1000*t.timeit(10)/10))

내 컴퓨터의 일반적인 시간 :

235886 words in list
simple sort: 483.59 msec/pass
sort with key=str.lower: 1064.70 msec/pass
sort with cmp=libc.strcasecmp: 5487.86 msec/pass

따라서 str.lower가 포함 된 버전은 지금까지 가장 빠를뿐만 아니라 여기에 제안 된 모든 솔루션 중에서 가장 이식성이 뛰어나고 Pythonic입니다. 메모리 사용량을 프로파일 링하지는 않았지만 원래 포스터는 여전히 그것에 대해 걱정할만한 이유가 없습니다. 또한 누가 libc 모듈에 대한 호출이 문자열을 복제하지 않는다고 말합니까?

NB : lower() 문자열 메소드는 로케일 종속적 인 장점도 있습니다. 자신 만의 "최적화 된"솔루션을 작성할 때 아마도 제대로되지 않을 것입니다. 그럼에도 불구하고 파이썬의 버그와 누락 된 기능으로 인해 이러한 종류의 비교는 유니 코드 컨텍스트에서 잘못된 결과를 줄 수 있습니다.

75
user3850

성능이 중요한 응용 프로그램의 자주 실행되는 경로에서이 비교를 사용하고 있습니까? 또는 메가 바이트 크기의 문자열에서 이것을 실행하고 있습니까? 그렇지 않은 경우 성능에 대해 걱정하지 말고 .lower () 메서드를 사용하십시오.

다음 코드는 1.8MB 데스크톱 컴퓨터에서 크기가 각각 거의 메가 바이트 인 두 문자열에서 .lower ()를 호출하여 대소 문자를 구분하지 않는 비교를 수행하는 방법을 보여줍니다.

from timeit import Timer

s1 = "1234567890" * 100000 + "a"
s2 = "1234567890" * 100000 + "B"

code = "s1.lower() < s2.lower()"
time = Timer(code, "from __main__ import s1, s2").timeit(1000)
print time / 1000   # 0.00920499992371 on my machine

실제로 이것이 매우 중요하고 성능이 중요한 코드 섹션 인 경우 C로 함수를 작성하고 Python 코드에서 호출하는 것이 좋습니다. 대소 문자를 구분하지 않는 검색 C 확장 모듈 작성에 대한 자세한 내용은 다음을 참조하십시오. https://docs.python.org/extending/extending.html

7
Eli Courtwright

귀하의 질문은 유니 코드가 필요하지 않다는 것을 암시합니다. 다음 코드 스 니펫을 사용해보십시오. 그것이 당신을 위해 일하면, 당신은 끝났습니다 :

Python 2.5.2 (r252:60911, Aug 22 2008, 02:34:17)
[GCC 4.3.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import locale
>>> locale.setlocale(locale.LC_COLLATE, "en_US")
'en_US'
>>> sorted("ABCabc", key=locale.strxfrm)
['a', 'A', 'b', 'B', 'c', 'C']
>>> sorted("ABCabc", cmp=locale.strcoll)
['a', 'A', 'b', 'B', 'c', 'C']

설명 : 첫눈에 명확하지 않은 경우 locale.strcoll은 str.lower 또는 locale.strxfrm "중복"문자열을 피하면서 필요한 기능인 것 같습니다.

7
tzot

대소 문자를 구분하지 않는 비교를 수행하는 다른 기본 제공 방법을 찾을 수 없습니다. python cook-book recipe uses lower ().

그러나 터키 식 I 문제 때문에 비교에 더 낮은 값을 사용할 때는주의해야합니다. 불행히도 Python의 Turkish Is 처리는 좋지 않습니다. ı는 I로 변환되지만 ı로 변환되지는 않습니다. İ는 i로 변환되지만 i는 İ로 변환되지 않습니다.

5
Douglas Leeder

원하는 기능과 동등한 기능이 내장되어 있지 않습니다.

두 문자열이 중복되는 것을 피하기 위해 한 번에 각 문자를 .lower ()로 변환하는 자체 함수를 작성할 수는 있지만 CPU 집약적이며 비효율적이라고 확신합니다.

매우 긴 문자열로 작업하지 않는 한 (중복되면 메모리 문제가 발생할 수 있음) 간단하게 유지하고

str1.lower() == str2.lower()

당신은 괜찮을거야

3
Ricardo Reyes

이 질문은 매우 다른 두 가지를 요구합니다.

  1. 대소 문자를 무시하고 파이썬에서 문자열을 비교하는 가장 쉬운 방법은 무엇입니까?
  2. 나는 C의 stricmp ()와 동등한 것을 찾고 있다고 생각합니다.

# 1이 이미 잘 응답되었으므로 (예 : str1.lower () <str2.lower ()) # 2에 대답하겠습니다.

def strincmp(str1, str2, numchars=None):
    result = 0
    len1 = len(str1)
    len2 = len(str2)
    if numchars is not None:
        minlen = min(len1,len2,numchars)
    else:
        minlen = min(len1,len2)
    #end if
    orda = ord('a')
    ordz = ord('z')

    i = 0
    while i < minlen and 0 == result:
        ord1 = ord(str1[i])
        ord2 = ord(str2[i])
        if ord1 >= orda and ord1 <= ordz:
            ord1 = ord1-32
        #end if
        if ord2 >= orda and ord2 <= ordz:
            ord2 = ord2-32
        #end if
        result = cmp(ord1, ord2)
        i += 1
    #end while

    if 0 == result and minlen != numchars:
        if len1 < len2:
            result = -1
        Elif len2 < len1:
            result = 1
        #end if
    #end if

    return result
#end def

대부분의 경우 소문자 기술이 우수하므로이 기능을 사용해야합니다.

나는 ASCII 문자열로만 작업하고 이것이 유니 코드로 어떻게 작동하는지 잘 모르겠습니다.

2
trevorcroft

표준 라이브러리에서 무언가가 잘 지원되지 않으면 항상 PyPI 패키지를 찾습니다. 가상화와 최신 Linux 배포판의 유비쿼터스를 사용하면 더 이상 Python 확장명을 피할 수 없습니다. PyICU는 다음과 같이 계산합니다. https://stackoverflow.com/a/1098160/3461

순수한 파이썬 옵션도 있습니다. 잘 테스트되었습니다 : https://github.com/jtauber/pyuca


오래된 답변 :

나는 정규식 솔루션을 좋아합니다. 다음은 파이썬의 블록 구조 지원 덕분에 모든 함수에 복사하여 붙여 넣을 수있는 함수입니다.

def equals_ignore_case(str1, str2):
    import re
    return re.match(re.escape(str1) + r'\Z', str2, re.I) is not None

검색 대신 일치를 사용했기 때문에 정규 표현식에 캐럿 (^)을 추가 할 필요가 없었습니다.

참고 : 평등 만 검사하며 때로는 필요한 것입니다. 나는 또한 내가 그것을 좋아한다고 말하지 않을 것입니다.

2
Benjamin Atkin

값 비싼 계산 키를 사용하여 값 목록을 정렬하는 데 권장되는 관용구는 소위 "장식 패턴"입니다. 원래 목록에서 (키, 값) 튜플 목록을 작성하고 해당 목록을 정렬하는 것만으로 구성됩니다. 그런 다음 키를 제거하고 정렬 된 값 목록을 얻는 것이 간단합니다.

>>> original_list = ['a', 'b', 'A', 'B']
>>> decorated = [(s.lower(), s) for s in original_list]
>>> decorated.sort()
>>> sorted_list = [s[1] for s in decorated]
>>> sorted_list
['A', 'a', 'B', 'b']

또는 원 라이너를 좋아하는 경우 :

>>> sorted_list = [s[1] for s in sorted((s.lower(), s) for s in original_list)]
>>> sorted_list
['A', 'a', 'B', 'b']

Lower () 호출 비용에 대해 정말로 걱정한다면 어디서나 (낮은 문자열, 원래 문자열) 튜플을 저장할 수 있습니다. 튜플은 파이썬에서 가장 저렴한 종류의 컨테이너이며 해시 가능하므로 사전 키, 집합 멤버 등으로 사용할 수 있습니다.

1
Antoine P.

이것은 re와 함께하는 방법입니다.

import re
p = re.compile('^hello$', re.I)
p.match('Hello')
p.match('hello')
p.match('HELLO')
1
Moses Ting

때때로 또는 반복적 인 비교를 위해 코어 코드의 가장 안쪽 루프에서 발생하지 않거나 실제로 성능에 영향을 줄만큼 충분한 데이터가없는 한 몇 개의 추가 문자열 객체는 중요하지 않습니다. "멍청한"방식으로 일을하는 것이 덜 어리석은 경우 훨씬 덜 어리 석습니다.

대소 문자를 구분하지 않고 많은 텍스트를 비교하는 것을 진지하게 원한다면 마무리 및 재 작성을 피하기 위해 소문자 버전의 문자열을 그대로 유지하거나 전체 데이터 세트를 소문자로 정규화 할 수 있습니다. 이것은 물론 데이터 세트의 크기에 따라 다릅니다. 바늘이 비교적 적고 건초 더미가 큰 경우 바늘을 컴파일 된 정규식 객체로 바꾸는 것이 하나의 솔루션입니다. 구체적인 예를 보지 않고 말하기가 어렵다면.

0
yason

각 문자열을 소문자로 한 번만 번역하면 필요할 때만 느리게 또는 전체 문자열 컬렉션을 정렬 할 경우 정렬의 프리 패스로 변환 할 수 있습니다. 이 비교 키를 정렬되는 실제 데이터에 연결하는 방법에는 여러 가지가 있지만 이러한 기술은 별도의 문제로 해결해야합니다.

이 기술은 대문자/소문자 문제를 처리 할뿐만 아니라 로케일 별 정렬 또는 선행 기사를 무시하고 정렬하기 전에 데이터를 정규화하는 "라이브러리 스타일"제목 정렬과 같은 다른 유형의 정렬에 사용할 수 있습니다.

0
Dale Wilson

고성능이 중요하지 않은 한 str().lower() 메소드 만 사용하십시오.이 경우 해당 정렬 메소드를 C 확장으로 작성하십시오.

"Python 확장명" 작성법은 괜찮은 소개처럼 보입니다 ..

더 흥미롭게도 이 가이드 는 ctypes 라이브러리를 사용하는 것과 외부 C 모듈을 쓰는 것을 비교합니다 (ctype은 C 확장보다 상당히 느립니다).

0
dbr
import re
if re.match('tEXT', 'text', re.IGNORECASE):
    # is True
0
Venkatesh Bachu

.lower ()를 사용하거나 정규식을 사용해야한다고 확신합니다. 대소 문자를 구분하지 않는 내장 문자열 비교 기능을 알지 못합니다.

0
Mark Biek