Eu escrevi um regex para ajudar a validar um String para nomes de caracteres de jogos. De alguma forma, ele está transmitindo seqüências aparentemente inválidas e não passando strings aparentemente válidas.
Requisitos:
- Começa com letra maiúscula
- Tem qualquer número de caracteres alfanuméricos depois disso (isso inclui espaços)
Este é o código de trilhos que faz a validação no Modelo de Personagem:
validates :name, format: { with: %r{[A-Z][a-zA-Z0-9s]*} }
Aqui está o teste de unidade que eu estou usando
test "character name should be properly formatted and does not contain any special characters" do
character = get_valid_character
assert character.valid?
character.name = "aBcd"
assert character.invalid?, "#{character.name} should be invalid"
character.name = "Number 1"
assert character.valid?, "#{character.name} should be valid"
character.name = "McDonalds"
assert character.valid?, "#{character.name} should be valid"
character.name = "Abcd."
assert character.invalid?, "#{character.name} should be invalid"
character.name = "Abcd%"
assert character.invalid?, "#{character.name} should be invalid"
end
Os problemas: O regex passa "aBcd", "Abcd." E "Abcd%" quando não deveria. Agora, eu sei que isso funciona porque eu testei isso em Python e funciona exatamente como você esperaria.
O que da?
Obrigado pela ajuda!
Respostas:
6 para resposta № 1Expressões regulares procuram por correspondências em qualquer lugar da string dada, a menos que seja dito o contrário.
Então a string de teste "aBcd"
é inválido, mas contém uma substring válida: "Bcd"
. Mesmo com "Abcd%"
, onde a substring válida é "Abcd"
.
Se você quiser corresponder a string inteira, use isso como seu regex:
# A matches string beginning, z matches string end
%r{A[A-Z][a-zA-Z0-9s]*z}
PS: Algumas pessoas vão dizer para combinar o começo de uma string com ^
e o fim com $
. Em Ruby, esses símbolos correspondem ao começo e ao fim de um linhanão uma string. assim "ABCDn%"
ainda corresponderia se você usou ^
e $
, mas não vai combinar se você usar A
e z
. Veja o Guia de segurança do Rails para mais sobre isso.
0 para resposta № 2
Se você quer apenas combinar a letra maiúscula no começo da string, você precisa colocar o marcador "início da linha" ^
então ficaria assim:
validates :name, format: { with: %r{^[A-Z][a-zA-Z0-9s]*} }
Confira Rubular para brincar com o seu regex