python - 줄바꿈 - 파이썬 문자열 찾기



그 문자열을 파이썬에서 하나의 문자로 효율적으로 검사 (6)

내장 함수 all 사용해보십시오.

all(c == 'A' for c in s)

파이썬에서 문자열 s 이 단 하나의 문자, 'A' 로 구성되어 있는지 확인하는 효율적인 방법은 무엇입니까? 다음과 같이 동작하는 all_equal(s, 'A') 와 같은 것 :

all_equal("AAAAA", "A") = True

all_equal("AAAAAAAAAAA", "A") = True

all_equal("AAAAAfAAAAA", "A") = False

겉으로는 비효율적 인 두 가지 방법은 먼저 문자열을 목록으로 변환하고 각 요소를 확인하거나 정규 표현식을 사용하는 것입니다. 더 효율적인 방법이 있습니까, 아니면 파이썬에서 할 수있는 최선의 방법입니까? 감사.


Answer #1

문자열의 모든 문자가 동일하고 주어진 문자와 같은지 확인해야하는 경우 모든 중복을 제거하고 최종 결과가 단일 문자와 같은지 확인해야합니다.

>>> set("AAAAA") == set("A")
True

중복이 있는지 찾아 보려면 길이를 확인하십시오.

>>> len(set("AAAAA")) == 1
True

Answer #2

이 문제에 다른 해결책 추가하기

>>> not "AAAAAA".translate(None,"A")
True

Answer #3

이것은 count() 보다 몇 배 빠르며 가장 빠릅니다. 훌륭한 mgilson의 타이밍 슈트로 시간을 정하십시오.

s == len(s) * s[0]

여기 모든 검사는 Python C 코드 내에서 수행됩니다.

  • len (s) 문자를 할당합니다.
  • 첫 번째 문자로 공백을 채 웁니다.
  • 두 문자열을 비교합니다.

문자열이 길수록 시간 보너스가 더 큽니다. 그러나 mgilson이 쓰는 것처럼 문자열의 복사본을 만듭니다. 따라서 문자열 길이가 수백만 개의 기호라면 문제가 될 수 있습니다.

타이밍 결과에서 볼 수 있듯이 일반적으로 작업을 해결하는 가장 빠른 방법은 각 심볼에 대해 파이썬 코드를 실행하지 않습니다. 그러나 set() 솔루션은 파이썬 라이브러리의 C 코드 안에있는 모든 작업도 수행하지만 파이썬 객체 인터페이스를 통한 문자열 조작으로 인해 여전히 느립니다.

UPD : 빈 문자열의 경우. 그것으로 무엇을 할 것인가는 작업에 강하게 의존합니다. 작업이 "문자열의 모든 기호가 같은지 확인하십시오."인 경우 s == len(s) * s[0] 은 유효한 대답입니다. 기호는 오류를 나타내지 않으며 예외는 괜찮습니다. 작업이 "정확히 하나의 고유 한 심볼이 있는지 확인"하는 경우 빈 문자열은 False를 제공하고 대답은 s and s == len(s) * s[0] 또는 bool(s) and s == len(s) * s[0] boolean 값을 받기를 원한다면 bool(s) and s == len(s) * s[0] . 마지막으로, "다른 기호가 없는지 확인"으로 작업을 이해하면 빈 문자열에 대한 결과는 True이고 대답은 not s or s == len(s) * s[0]not s or s == len(s) * s[0] .


Answer #4
not len("AAAAAAAAA".replace('A', ''))

Answer #5
>>> s = 'AAAAAAAAAAAAAAAAAAA'
>>> s.count(s[0]) == len(s)
True

이것은 단락되지 않습니다. 단락을 일으키는 버전은 다음과 같습니다.

>>> all(x == s[0] for x in s)
True

그러나, 나는 최적화 된 C 구현으로 인해 비 - 단락 버전이 아마도 일부 문자열 (크기 등에 따라)에서 더 잘 수행 될 것이라고 생각합니다.

다음은 게시 된 다른 옵션 중 일부를 테스트하기위한 간단한 timeit 스크립트입니다.

import timeit
import re

def test_regex(s,regex=re.compile(r'^(.)\1*$')):
    return bool(regex.match(s))

def test_all(s):
    return all(x == s[0] for x in s)

def test_count(s):
    return s.count(s[0]) == len(s)

def test_set(s):
    return len(set(s)) == 1

def test_replace(s):
    return not s.replace(s[0],'')

def test_translate(s):
    return not s.translate(None,s[0])

def test_strmul(s):
    return s == s[0]*len(s)

tests = ('test_all','test_count','test_set','test_replace','test_translate','test_strmul','test_regex')

print "WITH ALL EQUAL"
for test in tests:
    print test, timeit.timeit('%s(s)'%test,'from __main__ import %s; s="AAAAAAAAAAAAAAAAA"'%test)
    if globals()[test]("AAAAAAAAAAAAAAAAA") != True:
        print globals()[test]("AAAAAAAAAAAAAAAAA")
        raise AssertionError

print
print "WITH FIRST NON-EQUAL"
for test in tests:
    print test, timeit.timeit('%s(s)'%test,'from __main__ import %s; s="FAAAAAAAAAAAAAAAA"'%test)
    if globals()[test]("FAAAAAAAAAAAAAAAA") != False:
        print globals()[test]("FAAAAAAAAAAAAAAAA")
        raise AssertionError

이 짧은 문자열을 가진 내 컴퓨터 (OS-X 10.5.8, core2duo, python2.7.3)에서 str.count set 있고 all str.count 하고 str.count 약간 str.translate 하지만 str.translate 의해 str.translate strmul 은 현재 좋은 마진으로 선두에 있습니다 :

WITH ALL EQUAL
test_all 5.83863711357
test_count 0.947771072388
test_set 2.01028490067
test_replace 1.24682998657
test_translate 0.941282987595
test_strmul 0.629556179047
test_regex 2.52913498878

WITH FIRST NON-EQUAL
test_all 2.41147494316
test_count 0.942595005035
test_set 2.00480484962
test_replace 0.960338115692
test_translate 0.924381017685
test_strmul 0.622269153595
test_regex 1.36632800102

타이밍은 다른 시스템과 다른 문자열간에 약간 (또는 심지어 현저하게) 다를 수 있으므로 통과 할 예정인 실제 문자열로 조사 할 가치가 있습니다.

결국, 최선의 결과를 얻었고 문자열의 길이가 충분하다면, 고려해야 할 사항이 있습니다. 그것은 더 나은 알고리즘입니다 ... 비록 그것이 가능성이 count 솔루션을 이길 수있는 모든 경우를 보지 못했지만 내가 set 솔루션을 피할 것입니다.

메모리가 문제가 될 수 있다면 str.translate , strmulstrmul 은 두 번째 문자열을 만드는 것과 같이 피할 필요가 있지만 요즘에는 일반적으로 문제가되지 않습니다.





string