Bir dizenin alfabeden HERHANGİ bir harf içerip içermediğini nasıl kontrol edebilirim?


86

Bir dizenin alfabeden HERHANGİ bir harf içerip içermediğini kontrol etmek için en iyi saf Python uygulaması nedir?

string_1 = "(555).555-5555"
string_2 = "(555) 555 - 5555 ext. 5555

Nerede string_1dönecekti Falseo alfabenin hiçbir harflerini sahibi olmak için ve string_2dönecekti Truemektup sahibi olmak için.


2
Bu sadece ingilizce a / z alfabesiyle mi sınırlandırılmalıdır? Almanca gibi diğer alfabelerden 'özel' karakterler dikkate alınmalı mı?
Kotch

Unicode alma şansınız var mı? Veya sadece ascii roma harfleri
KobeJohn

Güzel zamanlama :) Her neyse, unicode karakterleri olan dizeleri test etmek için yardıma ihtiyacınız varsa bu benzer soruyu kontrol edin.
KobeJohn

1
Yalnızca İngilizce a / z alfabesiyle sınırlıdır ve yalnızca düz ascii roma harfleri :)
Justin Papez

Yanıtlar:


125

Normal ifade hızlı bir yaklaşım olmalıdır:

re.search('[a-zA-Z]', the_string)

1
Teşekkürler JBernado, sonunda yaptığım şey bu ve yapmam gereken şey için kusursuz çalışıyor.
Justin Papez

36
Regex kesinlikle biraz abartılı görünüyor. any(c.isalpha() for c in string_1)nefis Pythonic.
Jollywatt

5
@Joseph Hayır, öyle değil. Bu normal ifade, ifadenizden çok daha okunabilir. Ayrıca, isalphahatta ne anlama geliyor? Python 2'yi Python 3 ile karşılaştırırken bunun tamamen farklı davranışları olacaktır. Çince alfabenin bir parçası mı? Değilse, onu Python 3'teki jeneratörünüzle körü körüne eşleştiriyorsunuz (veya unicode dizeleri için Python 2!). İsterseniz Pythonic , işte burada: Simple is better than complex.. Ve yukarıdaki OP'nin yorumunu kontrol edin: Yalnızca roma alfabesinin eşleşmesini istiyor.
JBernardo

1
Joseph'in cevabının mükemmel bir şekilde okunabilir olduğunu ve kesinlikle ek bir içe aktarmadan daha hızlı olduğunu düşünüyorum; ayrıca araştırmadaki argümanların sırasını hatırlamak zorunda değilsiniz
Hinton

11
Başka birinin dönüş değerinin ne olduğunu merak etmesi Matchdurumunda, bir eşleşme Nonevarsa veya yoksa bir nesne alırsınız . Yani bu bir if re.search(...modelle uyumludur .
Srini

78

Peki ya:

>>> string_1 = "(555).555-5555"
>>> string_2 = "(555) 555 - 5555 ext. 5555"
>>> any(c.isalpha() for c in string_1)
False
>>> any(c.isalpha() for c in string_2)
True

Misiniz set(string_1)daha verimli olacak?
Rik Poggi

1
@Rik. String_1'i test etmeden önce bir kümeye dönüştürmeyi mi kastediyorsunuz? Hayır, daha verimli olmayacak. Herhangi bir işlevin ilk yanlışla karşılaştığında kısa devre yapacağına (duracağına) inanıyorum.
KobeJohn

Bu kod, karakter başına bir işlev çağrısı gerektirdiğinden biraz yavaş olacaktır. Dönüştürülüyor setmayıs veya işlev çağrıları azaltmak olmayabilir, ama bazı ek yükü ekler.
JBernardo

2
@JBernardo: timeit, derlenmiş bir normal ifadeden daha yavaş bir büyüklük sırası olduğunu ve derlenmemiş bir normalden yalnızca yaklaşık% 66 daha fazla zaman aldığını öne sürüyor. Bu, benim "Normal ifadelerden nefret ediyorum" sınırlarım dahilinde.
DSM

1
Elbette: ve "(555) .555-5555 ext. 5555" * 1000 kullanırsanız, kısa devre nedeniyle benzer hızlara geri dönersiniz. Python'da yazmayı, önemsiz olmadıkça hata ayıklamayı zor bulduğum normal ifadeler yazmaya tercih ederim ve performans gereksinimleri gerektirmedikçe temiz Python yazmaktan vazgeçmeyeceğim.
DSM

27

islower()Dizenizde bazı küçük harfler (diğer karakterlerin yanı sıra) içerip içermediğini görmek için kullanabilirsiniz . oronunlaisupper() bazı büyük harf içeriyorsa da kontrol etmek:

aşağıda: dizedeki harfler: test doğru sonucu verir

>>> z = "(555) 555 - 5555 ext. 5555"
>>> z.isupper() or z.islower()
True

aşağıda: dizede harf yok: test yanlış verir.

>>> z= "(555).555-5555"
>>> z.isupper() or z.islower()
False
>>> 

isalpha()Hangi geri dönüşlerle karıştırılmamalıdırTrueYalnızca tüm karakterler harf ise , istediğiniz şey bu değil.

Benimki karışık durumu iyi idare edemediği için Barm'ın cevabının benimkini güzelce tamamladığını unutmayın .


3
Bunun sadece girişin TÜM harf olup olmadığını test etmekle kalmayıp, harf İÇERİR olup olmadığını test etmesini seviyorum.
Cornbeetle

@Cornbeetle evet, bunca yıldan sonra soruyu gerçekten cevaplayan bu tür, teşekkürler
Jean-François Fabre

Bunu söylemenin çok güzel bir yolu. Verimlilik açısından nasıl? normal ifadeden daha iyi?
pnv

hiçbir python döngüsü yoktur, bu nedenle verimlilik iyidir. Normal ifadeyle karşılaştırmadım ama sanırım biraz daha hızlı, özellikle başlatma aşaması için çünkü derlenecek bir normal ifade yok
Jean-François Fabre

13

@ Jean-françois-fabre tarafından sağlanan cevabı beğendim , ancak eksik.
Yaklaşımı işe yarayacaktır, ancak yalnızca metin tamamen küçük veya büyük harf içeriyorsa:

>>> text = "(555).555-5555 extA. 5555"
>>> text.islower()
False
>>> text.isupper()
False

Daha iyi bir yaklaşım, önce dizenizi büyük veya küçük harflerle yazmak ve ardından kontrol etmektir.

>>> string1 = "(555).555-5555 extA. 5555"
>>> string2 = '555 (234) - 123.32   21'

>>> string1.upper().isupper()
True
>>> string2.upper().isupper()
False

8

Normal ifadeyi şu şekilde kullanabilirsiniz:

import re

print re.search('[a-zA-Z]+',string)

2

Belirli bir dizede herhangi bir alfabenin bulunup bulunmadığını bulmak için yukarıdaki yöntemlerin her birini test ettim ve standart bir bilgisayarda dizge başına ortalama işlem süresini buldum.

~ 250 ns için

import re

~ 3 µs için

re.search('[a-zA-Z]', string)

~ 6 µs için

any(c.isalpha() for c in string)

~ 850 ns için

string.upper().isupper()


İddianın aksine , yeniden içe aktarma ihmal edilebilir bir süre alır ve re ile arama, nispeten küçük bir dizge için bile isalpha () yinelemesine kıyasla yaklaşık yarı zaman alır . Bu nedenle, daha büyük dizeler ve daha büyük sayılar için yeniden önemli ölçüde daha verimli olacaktır. Ancak dizeyi bir duruma dönüştürmek ve durumu kontrol etmek (yani, üst (). İsupper () veya daha düşük (). İslower () ) burada kazanır . Her döngüde re.search () ' den önemli ölçüde daha hızlıdır ve herhangi bir ek ithalat gerektirmez.



1
Daha ileri optimizasyon için regex'i de derleyebilirsiniz. alpha_regex = re.compile ('[a-zA-Z]') sonra alpha_regex.search (string)
Behdad Forghani

İsalpha () birden çok dil için iyi çalışmıyor. Bunu arıyordum çünkü Korece olması beklenen bir dizenin herhangi bir İngilizce harf içerip içermediğini ve isalpha () yönteminin her Kore dizesi için True döndürüp döndürmediğini kontrol etmek istedim.
Chan Woo

0

Bunu ek olarak da yapabilirsiniz

import re
string='24234ww'
val = re.search('[a-zA-Z]+',string) 
val[0].isalpha() # returns True if the variable is an alphabet
print(val[0]) # this will print the first instance of the matching value

Ayrıca val değişkeninin None döndürdüğünü unutmayın . Bu, aramanın bir eşleşme bulamadığı anlamına gelir

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.