it-swarm-tr.com

Python karakterlerinde yoksay

Python'da dizeleri karşılaştırmanın en basit yolu, yoksayma durumu nedir?

Elbette bir kişi (str1.lower () <= str2.lower ()), vb. Yapabilir, ancak bu iki ek geçici dizi (bariz tahsis/g-c ek yükler ile) yarattı.

Sanırım C'nin stricmp () eşdeğeri için arıyorum.

[Daha fazla içerik talep edildi, bu yüzden önemsiz bir örnekle göstereceğim:]

Looong dizelerinin listesini sıralamak istediğinizi varsayalım. Basitçe, List.sort () ..__ yapın. Bu, O (n * log (n)) string karşılaştırmalarıdır ve hafıza yönetimi yoktur (çünkü tüm Karakter dizileri ve liste öğeleri bir tür akıllı işaretçidir). Sen mutlusun.

Şimdi, sen de aynısını yapmak istiyorsun, ama davayı görmezden gelelim (sadeleştirelim ve diyelim. Tüm dizeler asciidir, bu yüzden yerel meseleler göz ardı edilebilir) . .lower ()), ancak daha sonra karşılaştırma başına iki yeni ayırmaya neden olursunuz, ayrıca çöp toplayıcıyı çoğaltılmış (indirilmiş) dizelerle yüklersiniz. Her bir bellek yönetimi gürültüsü, basit dize karşılaştırmasından daha yavaş gerçekleşir.

Şimdi, yerinde bir stricmp () benzeri bir işleve sahip olursunuz: theList.sort (cmp = stricmp) Ve en az List.sort () kadar hafıza dostudur. Yine mutlusun.

Sorun, Python tabanlı herhangi bir büyük/küçük harf duyarlı olmayan karşılaştırmanın örtük string Yinelemelerini içermesidir, bu nedenle C tabanlı bir karşılaştırma bulmayı bekliyordum (belki modül dizgisinde).

Böyle bir şey bulunamadı, bu yüzden burada soru var . (Umarım bu soruyu açıklığa kavuşturur).

51
Paul Oyster

İşte str.lower kullanmanın, kabul edilen cevap verenin önerdiği yöntemden (libc.strcasecmp) daha hızlı olduğunu gösteren bir ölçüt:

#!/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))

makinemdeki tipik zamanlar:

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

Bu nedenle, str.lower olan sürüm yalnızca en hızlı değil, aynı zamanda önerilen tüm çözümlerin en taşınabilir ve Pythonic'idir Bellek kullanımını profillendirmedim, ancak orijinal poster hala çekici bir sebep vermedi Endişelen. Ayrıca, libc modülüne yapılan bir çağrının herhangi bir dizgiyi kopyalamadığını kim söylüyor?

Not: lower() string yöntemi ayrıca yerel bağımlı olma avantajına da sahiptir. Kendi "optimize edilmiş" çözümünüzü yazarken muhtemelen doğru olmayacağınız bir şey. Öyle olsa bile, Python'daki hatalar ve eksik özellikler nedeniyle, bu tür bir karşılaştırma size unicode bağlamda yanlış sonuçlar verebilir.

74
user3850

Bu karşılaştırmayı, yüksek performanslı bir uygulamanın çok sık yürütülen bir yolunda mı kullanıyorsunuz? Alternatif olarak, bunu megabayt boyutunda olan dizelerde mi çalıştırıyorsunuz? Değilse, performans hakkında endişelenmemeli ve sadece .lower () metodunu kullanmalısınız.

Aşağıdaki kod, her biri neredeyse bir megabayt boyutunda olan iki dizgide .lower () öğesini çağırarak büyük/küçük harf duyarlı bir karşılaştırma yapmanın 1.8GHz masaüstü bilgisayarımda yaklaşık 0.009 saniye sürdüğünü gösteriyor:

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

Gerçekten de bu, kodun son derece önemli, performans açısından kritik bir kısmıysa, C'ye bir işlev yazmanızı ve Python kodunuzdan çağırmanızı öneririm, çünkü bu gerçekten etkili bir büyük/küçük harf duyarlı arama yapmanızı sağlar. C uzatma modülleri yazma ile ilgili detaylar burada bulunabilir: https://docs.python.org/extending/extending.html

7
Eli Courtwright

Sorunuz Unicode'a ihtiyacınız olmadığı anlamına geliyor. Aşağıdaki kod parçasını deneyin; eğer sizin için işe yararsa, bitirdiniz:

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']

Açıklama: ilk görüşte açık olmadığı takdirde, locale.strcoll, str.lower veya locale.strxfrm "duplicate" dizgilerinden kaçınarak, ihtiyacınız olan fonksiyon gibi görünmektedir.

7
tzot

Büyük/küçük harfe duyarsız karşılaştırma yapmanın başka bir yolunu bulamıyorum: python yemek kitabı tarifi lower () kullanır.

Ancak karşılaştırmalar için Türkçe I problemi nedeniyle daha düşük kullanırken dikkatli olmalısınız . Maalesef Python'un Türk İşleri'ni ele alması iyi değil. ı dönüştürülür, ancak ı dönüştürülür. İ, İ'ye dönüştürülür, ancak İ'ye dönüştürülmez. 

5
Douglas Leeder

İstediğiniz işleve eşdeğer bir yerleşik yoktur.

Her iki diziyi de kopyalamaktan kaçınmak için her karakterde .lower () işlevine dönüşen kendi işlevinizi yazabilirsiniz, ancak çok cpu yoğun ve son derece verimsiz olacağından eminim. 

Çok uzun dizelerle çalışmadığınız sürece (çoğaltılırsa hafıza sorununa neden olabilecek kadar uzun) o zaman basit tutar ve kullanırdım 

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

İyi olacaksın

3
Ricardo Reyes

Bu soru 2 farklı şey soruyor:

  1. Python'da dizeleri karşılaştırmanın en basit yolu, yoksayma durumu nedir?
  2. Sanırım C'nin stricmp () eşdeğeri için arıyorum.

# 1 zaten çok iyi cevaplandığından (yani: str1.lower () <str2.lower ()) # 2 cevaplayacağım.

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

Bu işlevi sadece küçük harf tekniğinin üstün olacağı kadar mantıklı olduğunda kullanın.

Yalnızca ascii dizelerle çalışıyorum, bunun unicode ile nasıl davranacağından emin değilim.

2
trevorcroft

Bir şey standart kütüphanede iyi desteklenmiyorsa, daima bir PyPI paketi ararım. Sanallaştırma ve modern Linux dağıtımlarının yaygınlığı ile Python eklentilerinden artık kaçınmıyorum. PyICU tasarıya uygun görünüyor: https://stackoverflow.com/a/1098160/3461

Şimdi de saf python olan bir seçenek var. İyi bir şekilde test edildi: https://github.com/jtauber/pyuca


Eski cevap:

Düzenli ifade çözümünü seviyorum. İşte python blok yapı desteği sayesinde, herhangi bir işleve kopyalayıp yapıştırabileceğiniz bir işlev.

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

Arama yapmak yerine eşleşmeyi kullandığım için normal ifadeye bir harf (^) eklememe gerek yoktu.

Not: Bu sadece eşitliği kontrol eder, ki bu bazen ihtiyaç duyulan şeydir. Ayrıca hoşuma gittiğini söyleyecek kadar ileri gitmezdim.

2
Benjamin Atkin

Hesaplamak için pahalı tuşları kullanarak değer listelerini sıralamak için önerilen deyim, "dekore edilmiş desen" olarak adlandırılır. Basitçe, orijinal listeden bir (anahtar, değer) tupel listesi oluşturmaya ve bu listeyi sıralamaya dayanır. Ardından, anahtarları kaldırmak ve sıralanan değerlerin listesini almak çok önemlidir:

>>> 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']

Veya tek gömlekleri seviyorsanız:

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

Lower () 'nin çağrılmasının maliyeti konusunda gerçekten endişeleniyorsanız, her yerde (indirilmiş dize, orijinal dize) kayıtlarını saklayabilirsiniz. Tote'ler Python'daki en ucuz konteyner türüdür, aynı zamanda hasastırlar, böylece sözlük anahtarları, set üyeleri vb. Olarak kullanılabilirler.

1
Antoine P.

Bu şekilde yeniden yapmak nasıl:

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

Arada sırada ve hatta tekrarlanan karşılaştırmalar için, birkaç ekstra dize nesnesi, çekirdek kodunuzun en iç döngüsünde gerçekleşmeyeceği sürece ya da performans etkisini gerçekten fark edecek kadar veriye sahip olmadığınız sürece önemli olmamalıdır. Yapıp yapmadığınızı görün: bir şeyi "aptalca" bir şekilde yapmak, eğer daha az yaparsanız çok daha az aptaldır.

Büyük ve çok sayıda metni büyük/küçük harfleri duyarsızca karşılaştırmaya devam etmek istiyorsanız, sonuçlandırmayı ve yeniden oluşturmayı önlemek veya tüm verilerin küçük harfe dönüştürülmesini önlemek için dizelerin küçük harflerini el altında tutabilirsiniz. Bu, elbette, veri kümesinin boyutuna bağlıdır. Nispeten az sayıda iğne ve büyük bir samanlık varsa, iğneleri derlenmiş regexp nesnelerle değiştirmek tek bir çözümdür. Somut bir örnek görmeden söylemek zor.

0
yason

Her dizgiyi bir kez küçük harfe çevirebilirsiniz --- yalnızca ihtiyacınız olduğunda tembel bir şekilde veya dizgelerin tüm koleksiyonunu sıralayacağınızı biliyorsanız sıralama için bir hazırlayıcı olarak. Bu karşılaştırma anahtarını sıralanan gerçek verilere eklemenin birkaç yolu vardır, ancak bu teknikler ayrı bir konuda ele alınmalıdır.

Bu tekniğin yalnızca büyük/küçük harf sorunlarını işlemek için değil, aynı zamanda yerel olarak özel sıralama veya önde gelen makaleleri yok sayan ve sıralamadan önce verileri normalleştiren "Kitaplık stili" başlıklı sıralama gibi diğer sıralama türleri için kullanılabileceğini unutmayın.

0
Dale Wilson

Yüksek performanslı önemli olmadığı sürece, sadece str().lower() yöntemini kullanın - bu durumda bu sıralama yöntemini bir C uzantısı olarak yazın.

"Python Eklentisi nasıl yazılır" düzgün bir giriş gibi gözüküyor ..

Daha ilginç olarak, Bu kılavuz , harici bir C modülü yazmak yerine ctypes kütüphanesini kullanarak karşılaştırır (ctype, C uzantısından oldukça yavaştır).

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

Ya. (Low) () kullanmanız ya da düzenli ifade kullanmanız gerektiğinden eminim. Yerleşik bir büyük küçük harf duyarlı dize karşılaştırma işlevinin farkında değilim.

0
Mark Biek