Por que o intervalo não funciona como esperado?

Estou tentando usar o padrão de intervalo [01-12] na regex para corresponder a dois dígitos mm, mas isso não funciona como esperado.

Você parece ter entendido mal como a definição das classs de caracteres funciona na regex.

Para corresponder a qualquer uma das strings 01 , 02 , 03 , 04 , 05 , 06 , 07 , 08 , 09 , 10 , 11 ou 12 , algo como isto funciona:

 0[1-9]|1[0-2] 

Referências

  • regular-expressions.info/Character Classes
    • Faixas Numéricas (tem muitos exemplos em cadeias de caracteres correspondentes interpretadas como intervalos numéricos)

Explicação

Uma class de caractere, por si só, tenta corresponder a um e exatamente um caractere da string de input. [01-12] na verdade define [012] , uma class de caractere que corresponde a um caractere da input contra qualquer um dos 3 caracteres 0 , 1 ou 2 .

A definição - range vai de 1 a 1 , que inclui apenas 1 . Por outro lado, algo como [1-9] inclui 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 .

Iniciantes freqüentemente cometem erros ao definir coisas como [this|that] . Isso não “funciona”. Esta definição de caractere define [this|a] , isto é, ele combina um caractere da input com qualquer um dos 6 caracteres em t , h , i , s , | ou a . Mais do que provável (this|that) é o que se pretende.

Referências

  • regular-expressions.info/Brackets para Agrupamento e Alternação com a barra vertical

Como os intervalos são definidos

Então é óbvio agora que um padrão como between [24-48] hours não “funciona”. A class de caractere neste caso é equivalente a [248] .

Ou seja, - em uma definição de class de caractere não define o intervalo numérico no padrão. Os mecanismos de regex realmente não “entendem” os números no padrão, com exceção da syntax de repetição finita (por exemplo, a{3,5} corresponde entre 3 e 5 a ).

Em vez disso, a definição de intervalo usa a codificação ASCII / Unicode dos caracteres para definir intervalos. O caractere 0 é codificado em ASCII como decimal 48; 9 é 57. Assim, a definição de caractere [0-9] inclui todos os caracteres cujos valores estão entre o decimal 48 e 57 na codificação. De maneira bastante sensata, por design, esses são os caracteres 0 , 1 , …, 9 .

Veja também

  • Wikipedia / ASCII

Outro exemplo: de A a Z

Vamos dar uma olhada em outra definição de class de caractere comum [a-zA-Z]

Em ASCII:

  • A = 65, Z = 90
  • a = 97, z = 122

Isso significa que:

  • [a-zA-Z] e [A-Za-z] são equivalentes
  • Na maioria dos sabores, [aZ] é provável que seja um intervalo de caracteres ilegal
    • porque a (97) é “maior que” que Z (90)
  • [Az] é legal, mas também inclui esses seis caracteres:
    • [ (91), \ (92), ] (93), ^ (94), (95), “ `(96)

Perguntas relacionadas

  • é o regex [aZ] válido e se sim então é o mesmo que [a-zA-Z]

Uma class de caractere em expressões regulares, denotada pela [...] syntax, especifica as regras para corresponder a um único caractere na input. Como tal, tudo o que você escreve entre parênteses especifica como corresponder a um único caractere .

Seu padrão, [01-12] é assim dividido da seguinte forma:

  • 0 – corresponde ao dígito único 0
  • ou, 1-1, corresponde a um único dígito no intervalo de 1 a 1
  • ou, 2, corresponde a um único dígito 2

Então basicamente tudo que você está combinando é 0, 1 ou 2.

Para fazer a correspondência desejada, combinando dois dígitos, variando de 01 a 12 como números, é necessário pensar em como eles serão exibidos como texto.

Você tem:

  • 01-09 (ou seja, o primeiro dígito é 0, o segundo dígito é 1-9)
  • 10-12 (ou seja, o primeiro dígito é 1, o segundo dígito é 0-2)

Você terá que escrever uma expressão regular para isso, que pode ser assim:

  +-- a 0 followed by 1-9 | | +-- a 1 followed by 0-2 | | < -+--> < -+--> 0[1-9]|1[0-2] ^ | +-- vertical bar, this roughly means "OR" in this context 

Observe que tentar combiná-los para obter uma expressão mais curta falhará, fornecendo correspondências falsas positivas para input inválida.

Por exemplo, o padrão [0-1][0-9] basicamente corresponderia aos números 00-19, que é um pouco mais do que você deseja.

Tentei encontrar uma fonte definitiva para obter mais informações sobre as classs de caracteres, mas, por enquanto, tudo o que posso oferecer a você é este Google Query for Regex Character Classes . Espero que você possa encontrar mais informações para ajudá-lo.

Isso também funciona:

^([1-9]|[0-1][0-2])$

[1-9] corresponde a dígitos simples entre 1 e 9

[0-1][0-2] corresponde a dois dígitos entre 10 e 12

Existem alguns bons exemplos aqui

Como poligenelubrants diz que o seu iria procurar por 0 | 1-1 | 2 ao invés do que você deseja, devido ao fato de que classs de caracteres (coisas em []) combinam caracteres ao invés de strings.

O [] s em um regex denota uma class de caractere . Se nenhum intervalo for especificado, implicitamente ou todos os caracteres dentro dele estarão juntos. Assim, [abcde] é o mesmo que (a|b|c|d|e) , exceto que não captura nada; ele corresponderá a qualquer um de a , b , c , d ou e . Tudo o que um intervalo indica é um conjunto de caracteres ; [ac-eg] diz “combine qualquer um de: a ; qualquer caractere entre c e e ; ou g “. Assim, sua correspondência diz “corresponde a qualquer um de: 0 ; qualquer caractere entre 1 e 1 ( ou seja , apenas 1 ) ou 2 .

Seu objective é evidentemente especificar um intervalo de números: qualquer número entre 01 e 12 escritos com dois dígitos. Neste caso específico, você pode combiná-lo com 0[1-9]|1[0-2] : ou 0 seguido de qualquer dígito entre 1 e 9 , ou 1 seguido por qualquer dígito entre 0 e 2 . Em geral, você pode transformar qualquer intervalo numérico em um regex válido de maneira semelhante. Pode haver uma opção melhor que expressões regulares, no entanto, ou uma function ou módulo existente que possa construir o regex para você. Depende do seu idioma.

Usa isto:

 0?[1-9]|1[012] 
  • 07: válido
  • 7: válido
  • 0: não corresponde
  • 00: não corresponde
  • 13: não coincide
  • 21: não coincide

Para testar um padrão como 07/2018, use isto:

 /^(0?[1-9]|1[012])\/([2-9][0-9]{3})$/ 

(Intervalo de datas entre 01/2000 a 12/9999)

Para resolver isso, você pode usar /^[0-1][0-9]$/; E se você quiser apenas 01 a 12 , você precisa verificar duas condições:

Se o valor é 00 usando a instrução if :

 if(thevale=="00") { // message to user...not allowed } 

e:

 if(thevalue >=13) { // message to user...not allowed } 

Exemplo de código em Javascript:

 function CheckMonth(txtBox) { var ex = /^[0-1][0-9]$/; if (txtBox.value.trim() != "") { if (txtBox.value.trim() == "00") { alert('Please enter valid numbers.'); txtBox.value = ""; txtBox.focus(); } else if (ex.test(txtBox.value.trim()) == false) { alert('Please enter valid numbers.'); txtBox.value = ""; txtBox.focus(); } else if (parseInt(txtBox.value.trim()) >= 13) { alert('Please enter valid numbers.'); txtBox.value = ""; txtBox.focus(); } } }