Esta solução combinará strings de comprimento zero. use + em vez de * para fazer a correspondência de strings de 1 ou mais caracteres.
Jerub de
10
@Prestaul: \winclui \de _, portanto isvalid = re.match(r'[\w-]+$', astr)ou isinvalid = re.search(r'[^\w-]', astr). A possível presença de locale.setlocalestrings ou Unicode requer consideração adicional.
jfs
1
Correção: isvalid = re.match(r'[\w-]*$', astr)- strings vazias são válidas.
jfs
Como você também pode permitir um ponto / ponto (.) Nessa regex? Edite, veja como: ^ [a-zA-Z0-9 -_ \ s \.] + $
fredrik
24
[Editar] Há outra solução não mencionada ainda, e parece superar as outras fornecidas até agora na maioria dos casos.
Use string.translate para substituir todos os caracteres válidos na string e veja se há algum inválido restante. Isso é muito rápido porque usa a função C subjacente para fazer o trabalho, com muito pouco bytecode python envolvido.
Obviamente, desempenho não é tudo - buscar as soluções mais legíveis é provavelmente a melhor abordagem quando não em um codepath crítico de desempenho, mas apenas para ver como as soluções se comparam, aqui está uma comparação de desempenho de todos os métodos propostos até agora. check_trans é aquele que usa o método string.translate.
Código de teste:
import string, re, timeit
pat = re.compile('[\w-]*$')
pat_inv = re.compile ('[^\w-]')
allowed_chars=string.ascii_letters + string.digits + '_-'
allowed_set = set(allowed_chars)
trans_table = string.maketrans('','')
defcheck_set_diff(s):returnnot set(s) - allowed_set
defcheck_set_all(s):return all(x in allowed_set for x in s)
defcheck_set_subset(s):return set(s).issubset(allowed_set)
defcheck_re_match(s):return pat.match(s)
defcheck_re_inverse(s):# Search for non-matching character.returnnot pat_inv.search(s)
defcheck_trans(s):returnnot s.translate(trans_table,allowed_chars)
test_long_almost_valid='a_very_long_string_that_is_mostly_valid_except_for_last_char'*99 + '!'
test_long_valid='a_very_long_string_that_is_completely_valid_' * 99
test_short_valid='short_valid_string'
test_short_invalid='/$%$%&'
test_long_invalid='/$%$%&' * 99
test_empty=''defmain():
funcs = sorted(f for f in globals() if f.startswith('check_'))
tests = sorted(f for f in globals() if f.startswith('test_'))
for test in tests:
print"Test %-15s (length = %d):" % (test, len(globals()[test]))
for func in funcs:
print" %-20s : %.3f" % (func,
timeit.Timer('%s(%s)' % (func, test), 'from __main__ import pat,allowed_set,%s' % ','.join(funcs+tests)).timeit(10000))
printif __name__=='__main__': main()
A abordagem de tradução parece melhor na maioria dos casos, dramaticamente com longas strings válidas, mas é superada por regexes em test_long_invalid (presumivelmente porque a regex pode sair imediatamente, mas a tradução sempre precisa verificar toda a string). As abordagens de conjunto são geralmente piores, superando as regexes apenas para o caso de string vazia.
Usar all (x em allowed_set para x em s) tem um bom desempenho se falhar cedo, mas pode ser ruim se tiver que iterar em todos os caracteres. isSubSet e set diferença são comparáveis e são consistentemente proporcionais ao comprimento da string, independentemente dos dados.
Há uma diferença semelhante entre os métodos regex que combinam todos os caracteres válidos e procuram por caracteres inválidos. A correspondência tem um desempenho um pouco melhor ao verificar uma string longa, mas totalmente válida, mas pior para caracteres inválidos próximos ao final da string.
Use em string.ascii_lettersvez de string.lettersse você não usar o sinalizador re.LOCALE para regexps (caso contrário, você pode obter resultados falsos positivos em check_trans(). string.maketrans()Não funcionará para strings Unicode.
jfs
Para Python 3 / Unicode / from __future__ import unicode_literals), use trans_table3 = dict((ord(char), '') for char in allowed_chars)e def check_trans(s): return not s.translate(trans_table3). Mas, em geral, ele tem um desempenho pior do que as versões RE.
Hugo
14
Existem várias maneiras de atingir esse objetivo, algumas são mais claras do que outras. Para cada um dos meus exemplos, 'True' significa que a string passada é válida, 'False' significa que contém caracteres inválidos.
Em primeiro lugar, existe a abordagem ingênua:
import string
allowed = string.letters + string.digits + '_' + '-'defcheck_naive(mystring):return all(c in allowed for c in mystring)
Depois, há o uso de uma expressão regular, você pode fazer isso com re.match (). Observe que '-' deve estar no final de [], caso contrário, será usado como um delimitador de 'intervalo'. Observe também o $ que significa 'fim da string'. Outras respostas observadas nesta pergunta usam uma classe de caractere especial, '\ w', eu sempre prefiro usar um intervalo de classe de caractere explícito usando [] porque é mais fácil de entender sem ter que procurar um guia de referência rápida e mais fácil de especial- caso.
import re
CHECK_RE = re.compile('[a-zA-Z0-9_-]+$')
defcheck_re(mystring):return CHECK_RE.match(mystring)
Outra solução observou que você pode fazer uma correspondência inversa com expressões regulares, eu incluí isso aqui agora. Observe que [^ ...] inverte a classe de caractere porque o ^ é usado:
Você também pode fazer algo complicado com o objeto 'set'. Dê uma olhada neste exemplo, que remove da string original todos os caracteres permitidos, deixando-nos com um conjunto que contém a) nada ou b) os caracteres ofensivos da string:
Em seu primeiro teste de regex, "[a-zA-Z0-9 _-] + $" não deve ser "[a-zA-Z0-9 _-] * $". A string vazia provavelmente deve ser considerada como correspondente.
Brian de
Use string.ascii_lettersse você usar expressões regulares '[a-zA-Z]'.
jfs
12
Se não fosse pelos travessões e sublinhados, a solução mais fácil seria
Como alternativa ao uso de regex, você pode fazer isso em conjuntos:
from sets import Set
allowed_chars = Set('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-')
if Set(my_little_sting).issubset(allowed_chars):
# your actionprintTrue
import re;
re.fullmatch("^[\w-]+$", target_string) # fullmatch looks also workable for python 3.4
\w: Somente [a-zA-Z0-9_]
Então você precisa adicionar -char para justificar o hífen char.
+: Corresponde a uma ou mais repetições do caractere anterior. Eu acho que você não aceita entrada em branco. Mas se você fizer isso, mude para *.
^: Corresponde ao início da string.
$: Corresponde ao final da string.
Você precisa desses dois caracteres especiais, pois precisa evitar o caso a seguir. Os caracteres indesejados como &aqui podem aparecer entre o padrão correspondente.
Bem, você pode pedir a ajuda do regex, o ótimo aqui :)
código:
import re
string = 'adsfg34wrtwe4r2_()'#your string that needs to be matched.
regex = r'^[\w\d_()]*$'# you can also add a space in regex if u want to allow it in the string if re.match(regex,string):
print'yes'else:
print'false'
Você sempre pode usar uma compreensão de lista e verificar os resultados com todos, seria um pouco menos intensivo de recursos do que usar um regex: all([c in string.letters + string.digits + ["_", "-"] for c in mystring])
Teste seu código antes de postar. Uma solução baseada em sua resposta quebrada que funciona é: all (c em string.letters + string.digits + "_" para c em mystring)
Jerub
2
Isso vai exigir muito mais recursos do que uma regex. Ele está fazendo uma varredura linear para cada caractere (melhor construir um conjunto com antecedência) e você está construindo desnecessariamente uma lista quando a compreensão do gerador seria mais leve.
Brian de
-1
Aqui está algo baseado na "abordagem ingênua" de Jerub (ingênuo são as palavras dele, não minhas!):
import string
ALLOWED = frozenset(string.ascii_letters + string.digits + '_' + '-')
defcheck(mystring):return all(c in ALLOWED for c in mystring)
Se ALLOWEDfosse uma string, acho c in ALLOWEDque envolveria a iteração de cada caractere na string até encontrar uma correspondência ou chegar ao fim. Que, para citar Joel Spolsky, é uma espécie de algoritmo Shlemiel, o Pintor .
Mas testar a existência em um conjunto deve ser mais eficiente, ou pelo menos menos dependente do número de caracteres permitidos. Certamente, essa abordagem é um pouco mais rápida na minha máquina. É claro e acho que funciona muito bem para a maioria dos casos (na minha máquina lenta, posso validar dezenas de milhares de strings curtas em uma fração de segundo). Eu gosto disso.
Na verdade, na minha máquina, um regexp funciona várias vezes mais rápido e é tão simples quanto isso (possivelmente mais simples). Portanto, esse é provavelmente o melhor caminho a seguir.
Todos esses personagens devem estar em uma classe, ou você obterá falsos negativos. Além disso, você se esqueceu de incluir os marcadores de início e fim da string ... assim, sempre corresponderá, desde que um caractere válido esteja presente.
Thomas,
1
Na verdade, isso corresponderá mesmo se não houver caracteres válidos. Correspondência de comprimento zero. Além disso, não está em python.
Respostas:
Uma expressão regular fará o truque com muito pouco código:
import re ... if re.match("^[A-Za-z0-9_-]*$", my_little_string): # do something here
fonte
\w
inclui\d
e_
, portantoisvalid = re.match(r'[\w-]+$', astr)
ouisinvalid = re.search(r'[^\w-]', astr)
. A possível presença delocale.setlocale
strings ou Unicode requer consideração adicional.isvalid = re.match(r'[\w-]*$', astr)
- strings vazias são válidas.[Editar] Há outra solução não mencionada ainda, e parece superar as outras fornecidas até agora na maioria dos casos.
Use string.translate para substituir todos os caracteres válidos na string e veja se há algum inválido restante. Isso é muito rápido porque usa a função C subjacente para fazer o trabalho, com muito pouco bytecode python envolvido.
Obviamente, desempenho não é tudo - buscar as soluções mais legíveis é provavelmente a melhor abordagem quando não em um codepath crítico de desempenho, mas apenas para ver como as soluções se comparam, aqui está uma comparação de desempenho de todos os métodos propostos até agora. check_trans é aquele que usa o método string.translate.
Código de teste:
import string, re, timeit pat = re.compile('[\w-]*$') pat_inv = re.compile ('[^\w-]') allowed_chars=string.ascii_letters + string.digits + '_-' allowed_set = set(allowed_chars) trans_table = string.maketrans('','') def check_set_diff(s): return not set(s) - allowed_set def check_set_all(s): return all(x in allowed_set for x in s) def check_set_subset(s): return set(s).issubset(allowed_set) def check_re_match(s): return pat.match(s) def check_re_inverse(s): # Search for non-matching character. return not pat_inv.search(s) def check_trans(s): return not s.translate(trans_table,allowed_chars) test_long_almost_valid='a_very_long_string_that_is_mostly_valid_except_for_last_char'*99 + '!' test_long_valid='a_very_long_string_that_is_completely_valid_' * 99 test_short_valid='short_valid_string' test_short_invalid='/$%$%&' test_long_invalid='/$%$%&' * 99 test_empty='' def main(): funcs = sorted(f for f in globals() if f.startswith('check_')) tests = sorted(f for f in globals() if f.startswith('test_')) for test in tests: print "Test %-15s (length = %d):" % (test, len(globals()[test])) for func in funcs: print " %-20s : %.3f" % (func, timeit.Timer('%s(%s)' % (func, test), 'from __main__ import pat,allowed_set,%s' % ','.join(funcs+tests)).timeit(10000)) print if __name__=='__main__': main()
Os resultados em meu sistema são:
Test test_empty (length = 0): check_re_inverse : 0.042 check_re_match : 0.030 check_set_all : 0.027 check_set_diff : 0.029 check_set_subset : 0.029 check_trans : 0.014 Test test_long_almost_valid (length = 5941): check_re_inverse : 2.690 check_re_match : 3.037 check_set_all : 18.860 check_set_diff : 2.905 check_set_subset : 2.903 check_trans : 0.182 Test test_long_invalid (length = 594): check_re_inverse : 0.017 check_re_match : 0.015 check_set_all : 0.044 check_set_diff : 0.311 check_set_subset : 0.308 check_trans : 0.034 Test test_long_valid (length = 4356): check_re_inverse : 1.890 check_re_match : 1.010 check_set_all : 14.411 check_set_diff : 2.101 check_set_subset : 2.333 check_trans : 0.140 Test test_short_invalid (length = 6): check_re_inverse : 0.017 check_re_match : 0.019 check_set_all : 0.044 check_set_diff : 0.032 check_set_subset : 0.037 check_trans : 0.015 Test test_short_valid (length = 18): check_re_inverse : 0.125 check_re_match : 0.066 check_set_all : 0.104 check_set_diff : 0.051 check_set_subset : 0.046 check_trans : 0.017
A abordagem de tradução parece melhor na maioria dos casos, dramaticamente com longas strings válidas, mas é superada por regexes em test_long_invalid (presumivelmente porque a regex pode sair imediatamente, mas a tradução sempre precisa verificar toda a string). As abordagens de conjunto são geralmente piores, superando as regexes apenas para o caso de string vazia.
Usar all (x em allowed_set para x em s) tem um bom desempenho se falhar cedo, mas pode ser ruim se tiver que iterar em todos os caracteres. isSubSet e set diferença são comparáveis e são consistentemente proporcionais ao comprimento da string, independentemente dos dados.
Há uma diferença semelhante entre os métodos regex que combinam todos os caracteres válidos e procuram por caracteres inválidos. A correspondência tem um desempenho um pouco melhor ao verificar uma string longa, mas totalmente válida, mas pior para caracteres inválidos próximos ao final da string.
fonte
string.ascii_letters
vez destring.letters
se você não usar o sinalizador re.LOCALE para regexps (caso contrário, você pode obter resultados falsos positivos emcheck_trans()
.string.maketrans()
Não funcionará para strings Unicode.from __future__ import unicode_literals
), usetrans_table3 = dict((ord(char), '') for char in allowed_chars)
e defcheck_trans(s): return not s.translate(trans_table3)
. Mas, em geral, ele tem um desempenho pior do que as versões RE.Existem várias maneiras de atingir esse objetivo, algumas são mais claras do que outras. Para cada um dos meus exemplos, 'True' significa que a string passada é válida, 'False' significa que contém caracteres inválidos.
Em primeiro lugar, existe a abordagem ingênua:
import string allowed = string.letters + string.digits + '_' + '-' def check_naive(mystring): return all(c in allowed for c in mystring)
Depois, há o uso de uma expressão regular, você pode fazer isso com re.match (). Observe que '-' deve estar no final de [], caso contrário, será usado como um delimitador de 'intervalo'. Observe também o $ que significa 'fim da string'. Outras respostas observadas nesta pergunta usam uma classe de caractere especial, '\ w', eu sempre prefiro usar um intervalo de classe de caractere explícito usando [] porque é mais fácil de entender sem ter que procurar um guia de referência rápida e mais fácil de especial- caso.
import re CHECK_RE = re.compile('[a-zA-Z0-9_-]+$') def check_re(mystring): return CHECK_RE.match(mystring)
Outra solução observou que você pode fazer uma correspondência inversa com expressões regulares, eu incluí isso aqui agora. Observe que [^ ...] inverte a classe de caractere porque o ^ é usado:
CHECK_INV_RE = re.compile('[^a-zA-Z0-9_-]') def check_inv_re(mystring): return not CHECK_INV_RE.search(mystring)
Você também pode fazer algo complicado com o objeto 'set'. Dê uma olhada neste exemplo, que remove da string original todos os caracteres permitidos, deixando-nos com um conjunto que contém a) nada ou b) os caracteres ofensivos da string:
def check_set(mystring): return not set(mystring) - set(allowed)
fonte
string.ascii_letters
se você usar expressões regulares '[a-zA-Z]'.Se não fosse pelos travessões e sublinhados, a solução mais fácil seria
(Seção 3.6.1 da Referência da biblioteca Python)
fonte
Como alternativa ao uso de regex, você pode fazer isso em conjuntos:
from sets import Set allowed_chars = Set('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-') if Set(my_little_sting).issubset(allowed_chars): # your action print True
fonte
pat = re.compile ('[^\w-]') def onlyallowed(s): return not pat.search (s)
fonte
A expressão regular pode ser muito flexível.
import re; re.fullmatch("^[\w-]+$", target_string) # fullmatch looks also workable for python 3.4
\w
: Somente[a-zA-Z0-9_]
Então você precisa adicionar
-
char para justificar o hífen char.+
: Corresponde a uma ou mais repetições do caractere anterior. Eu acho que você não aceita entrada em branco. Mas se você fizer isso, mude para*
.^
: Corresponde ao início da string.$
: Corresponde ao final da string.Você precisa desses dois caracteres especiais, pois precisa evitar o caso a seguir. Os caracteres indesejados como
&
aqui podem aparecer entre o padrão correspondente.&&&PATTERN&&PATTERN
fonte
Bem, você pode pedir a ajuda do regex, o ótimo aqui :)
código:
import re string = 'adsfg34wrtwe4r2_()' #your string that needs to be matched. regex = r'^[\w\d_()]*$' # you can also add a space in regex if u want to allow it in the string if re.match(regex,string): print 'yes' else: print 'false'
Resultado:
Espero que isto ajude :)
fonte
Você sempre pode usar uma compreensão de lista e verificar os resultados com todos, seria um pouco menos intensivo de recursos do que usar um regex:
all([c in string.letters + string.digits + ["_", "-"] for c in mystring])
fonte
Aqui está algo baseado na "abordagem ingênua" de Jerub (ingênuo são as palavras dele, não minhas!):
import string ALLOWED = frozenset(string.ascii_letters + string.digits + '_' + '-') def check(mystring): return all(c in ALLOWED for c in mystring)
Se
ALLOWED
fosse uma string, achoc in ALLOWED
que envolveria a iteração de cada caractere na string até encontrar uma correspondência ou chegar ao fim. Que, para citar Joel Spolsky, é uma espécie de algoritmo Shlemiel, o Pintor .Mas testar a existência em um conjunto deve ser mais eficiente, ou pelo menos menos dependente do número de caracteres permitidos. Certamente, essa abordagem é um pouco mais rápida na minha máquina. É claro e acho que funciona muito bem para a maioria dos casos (na minha máquina lenta, posso validar dezenas de milhares de strings curtas em uma fração de segundo). Eu gosto disso.
Na verdade, na minha máquina, um regexp funciona várias vezes mais rápido e é tão simples quanto isso (possivelmente mais simples). Portanto, esse é provavelmente o melhor caminho a seguir.
fonte
use uma regex e veja se ela corresponde!
([a-z][A-Z][0-9]\_\-)*
fonte