Pourquoi la gamme [01-12] ne fonctionne-t-elle pas comme prévu?


91

J'essaie d'utiliser le modèle de plage [01-12]dans regex pour correspondre à deux chiffres mm, mais cela ne fonctionne pas comme prévu.


8
Vous faites correspondre des caractères , pas des séquences de caractères . Fondamentalement, vous correspondez à 0, 1 à 1 et 2 (c'est-à-dire 0, 1 et 2). Considérez ceci:, cela [a-z0-9]correspond à toutes les lettres minuscules et à tous les chiffres, mais uniquement comme un seul caractère.
Lasse V.Karlsen

fwiw J'ai créé un outil javascript qui crée un regex hautement optimisé à partir de deux entrées (min / max) github.com/jonschlinkert/to-regex-range
jonschlinkert

0 [1-9] | 1 [0-2] -> 0 | 1 | 2 -> [] s dans une expression régulière désignent une classe de caractères. Si aucune plage n'est spécifiée, il ors implicitement chaque caractère.
Badri Gs

Avez-vous besoin de le faire correspondre avec une regex pure? Sinon, vous pouvez: 1.) simplement utiliser le \d+modèle, 2.) convertir les chaînes correspondantes en nombres dans votre code. puis, 3.) vérifiez la plage de numéros comme if(num >= 0 && num <= 12){ /*do something*/ }. C'est tellement plus rapide et flexible.
acegs

Réponses:


192

Vous semblez avoir mal compris comment la définition des classes de caractères fonctionne dans les regex.

Pour correspondre à l' une des chaînes 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, ou 12, quelque chose comme ça fonctionne:

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

Références


Explication

Une classe de caractères, par elle-même, tente de faire correspondre un et exactement un caractère de la chaîne d'entrée. [01-12]définit en fait [012], une classe de caractères qui correspond à un caractère de l'entrée contre l' un des 3 caractères 0, 1ou 2.

La -définition de la plage va de 1à 1, ce qui inclut juste 1. D'autre part, quelque chose comme [1-9]inclut 1, 2, 3, 4, 5, 6, 7, 8, 9.

Les débutants font souvent l'erreur de définir des choses comme [this|that]. Cela ne "fonctionne" pas. Cette définition caractère définit [this|a], à savoir qu'il correspond à un caractère de l'entrée contre l' un des 6 caractères t, h, i, s, |ou a. Ce (this|that)qui est prévu est plus que probable .

Références


Comment les plages sont définies

Il est donc évident maintenant qu'un modèle comme between [24-48] hoursne "fonctionne" pas. La classe de caractères dans ce cas est équivalente à [248].

Autrement dit, -dans une définition de classe de caractères, ne définit pas de plage numérique dans le modèle. Les moteurs Regex ne «comprennent» pas vraiment les nombres dans le modèle, à l'exception de la syntaxe de répétition finie (par exemple, les a{3,5}correspondances entre 3 et 5 a).

La définition de plage utilise à la place le codage ASCII / Unicode des caractères pour définir les plages. Le caractère 0est codé en ASCII en décimal 48; 9est 57. Ainsi, la définition de caractère [0-9]inclut tous les caractères dont les valeurs sont comprises entre la décimale 48 et 57 dans le codage. Plutôt sensiblement, par la conception ce sont les personnages 0, 1..., 9.

Voir également


Un autre exemple: de A à Z

Jetons un coup d'œil à une autre définition de classe de caractères commune [a-zA-Z]

En ASCII:

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

Cela signifie que:

  • [a-zA-Z]et [A-Za-z]sont équivalents
  • Dans la plupart des saveurs, il [a-Z]s'agit probablement d'une plage de caractères illégale
    • parce que a(97) est "supérieur à" que Z(90)
  • [A-z] est légal, mais comprend également ces six caractères:
    • [(91), \(92), ](93), ^(94), _(95), `(96)

Questions connexes


Pour moi, je cherchais des mois sans préfixer avec 0 si un seul chiffre. Et j'ai utilisé ceci ([1-9] | (1 [0-2])) et ça marche.
bunjeeb

2
Important à noter: si vous trouvez que cette page souhaite une solution pour votre plage de numéros qui ne comporte que des chiffres uniques avant d'arriver aux dizaines, 0[1-9]|1[0-2]cela ne fonctionnera pas. Changement à l'étape suivante logique [1-9]|1[0-2]ne fonctionne pas non plus pour des raisons compréhensibles (elle correspond à la 1seule dans 10, 11et 12). J'ai dû utiliser \b(?:[0-9]|1[0-1])\bpour éviter cela. \bs s'assure que l'expression régulière correspond aux limites des mots (ou dans ce cas, des nombres) ( ^& $non); les parenthèses font que ou ( |) considère l'autre côté de celui-ci; et enfin ?:est de ne pas créer de sous-correspondance avec l'utilisation des crochets.
user66001

@polygenelubricants: "1,2,3,4,5,6,7,8,9,10,17,18".match(/^(([1-9]|1[0-7])\,?)+$/g )Pouvez-vous me dire pourquoi cette expression régulière JS correspond à plus de 17?
edam

@edam - polygenelubricants pourraient, et ainsi pourrais - je, mais nous serions répondent un questi ... attente ... est - ce une question que vous posez dans un commentaire ? Il y a des règles sur ce site;) Posez une question si vous avez une nouvelle question. Les commentaires sont uniquement destinés à critiquer et à demander des éclaircissements, et à y répondre.
robinCTS

1
@edam Oh, je vois. Vous avez re-demander comme une question d' une heure plus tard. C'est génial! Cependant, ce serait probablement une bonne idée de supprimer votre commentaire ici.
robinCTS

24

Une classe de caractères dans les expressions régulières, désignée par la [...]syntaxe, spécifie les règles pour faire correspondre un seul caractère dans l'entrée. En tant que tel, tout ce que vous écrivez entre les crochets spécifie comment faire correspondre un seul caractère .

Votre patron, [01-12]se décompose donc comme suit:

  • 0 - correspond au chiffre unique 0
  • ou, 1-1, correspond à un seul chiffre compris entre 1 et 1
  • ou, 2, correspond à un seul chiffre 2

Donc, fondamentalement, tout ce que vous correspondez est 0, 1 ou 2.

Afin de faire la correspondance que vous voulez, en faisant correspondre deux chiffres, allant de 01 à 12 sous forme de nombres, vous devez réfléchir à leur apparence sous forme de texte.

Tu as:

  • 01-09 (c'est-à-dire que le premier chiffre est 0, le deuxième chiffre est 1-9)
  • 10-12 (c'est-à-dire que le premier chiffre est 1, le deuxième chiffre est 0-2)

Vous devrez alors écrire une expression régulière pour cela, qui peut ressembler à ceci:

  +-- 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

Notez qu'essayer de les combiner afin d'obtenir une expression plus courte échouera, en donnant des correspondances fausses positives pour une entrée invalide.

Par exemple, le modèle [0-1][0-9]correspondrait essentiellement aux nombres 00-19, ce qui est un peu plus que ce que vous voulez.

J'ai essayé de trouver une source précise pour plus d'informations sur les classes de caractères, mais pour l'instant, tout ce que je peux vous donner est cette requête Google pour les classes de caractères Regex . J'espère que vous pourrez y trouver plus d'informations pour vous aider.


9

Cela fonctionne également:

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

[1-9] correspond à des chiffres uniques entre 1 et 9

[0-1][0-2] correspond à deux chiffres entre 10 et 12

Il y a quelques bons exemples ici


2
Pour être exact, [0-1][0-2]correspond également 00. Cela dit, +1 pour le lien (que j'ai utilisé dans ma réponse).
polygenelubricants

2
[0-1][0-2]doivent être interprétées avec prudence, car elle permet chaînes comme 00, 01et 02, mais il ne reconnaît pas 03jusqu'à 09, enfin admettre 10, 11et 12. Une bonne expression régulière pour cela est [1-9]|1[0-2], ou même 0*([1-9]|1[0-2])(ce dernier autorisant n'importe quel nombre de zéros non significatifs).
Luis Colorado

1

Le []s dans une expression régulière dénote une classe de caractères . Si aucune plage n'est spécifiée, il est implicitement ou s tous les caractères qu'il contient ensemble. Ainsi, [abcde]est le même que (a|b|c|d|e), sauf qu'il ne capture rien; il correspondra à une des a, b, c, dou e. Tout ce qu'une plage indique est un ensemble de caractères ; [ac-eg]dit "correspond à l'un des caractères suivants a:; tout caractère entre cet e; ou g". Ainsi, votre correspondance dit "correspond à l'un des caractères suivants 0:; tout caractère entre 1et 1( c'est -à- dire juste 1); ou 2.

Votre objectif est évidemment de spécifier une plage de nombres: n'importe quel nombre entre 01et 12écrit avec deux chiffres. Dans ce cas précis, vous pouvez le faire correspondre avec 0[1-9]|1[0-2]: soit a 0suivi de n'importe quel chiffre entre 1et 9, soit a 1suivi de n'importe quel chiffre entre 0et 2. En général, vous pouvez transformer n'importe quelle plage de nombres en une expression régulière valide de la même manière. Il peut y avoir une meilleure option que les expressions régulières, cependant, ou une fonction ou un module existant qui peut construire l'expression régulière pour vous. Cela dépend de votre langue.


0

Comme le dit polygenelubricants, le vôtre recherchera 0 | 1-1 | 2 plutôt que ce que vous souhaitez, car les classes de caractères (les éléments entre []) correspondent à des caractères plutôt qu'à des chaînes.


3
0|1-1|2- cette notation est très trompeuse. Quelque chose comme 0|1|2serait plus précis.
polygenelubricants

0

Utilisez ceci:

0?[1-9]|1[012]
  • 07: valide
  • 7: valide
  • 0: ne correspond pas
  • 00: ne correspond pas
  • 13: ne correspond pas
  • 21: ne correspond pas

Pour tester un modèle comme 07/2018, utilisez ceci:

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

(Plage de dates entre 01/2000 et 12/9999)


J'ai essayé de comprendre comment faire cela, mais pour que la troisième condition de seulement 0 passe.
mkaatman
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.