2009-09-09 9 views
7

donc j'ai besoin pour obtenir les heures, les minutes et les secondes sur les entrées comme celles-ci:Correspondant heures/minutes/secondes dans les expressions régulières - une meilleure façon?

  • 04:43:12
  • 9.43.12
  • 1:00
  • 01,04

Les deux premiers sont les heures, les minutes et les secondes. À côté de est minutes et secondes. Les deux dernières secondes ne sont que quelques secondes.

Et je suis venu avec cette expression rationnelle, qui fonctionne ..:

\A(?<hours>\d{1,2})(?::|\.)(?<minutes>\d{1,2})(?::|\.)(?<seconds>\d{1,2})\z|\A(?<minutes>\d{1,2})(?::|\.)(?<seconds>\d{1,2})\z|\A(?<seconds>\d{1,2})\z 

Mais il est laid, et je veux refactoriser vers le bas pour ne pas être 3 expressions différentes (la plupart du temps juste pour apprendre). J'ai essayé ceci:

\A(?:(?<hours>\d{1,2})(?::|\.){0,1})(?:(?<minutes>\d{1,2})(?::|\.){0,1})(?:(?<seconds>\d{1,2}){0,1})\z 

Mais cela ne fonctionne pas - minutes et secondes parfois se foirent. Mon cerveau me fait mal et je n'arrive pas à comprendre ce que je fais de mal.

+1

Ceci n'est PAS indépendant de la langue. La syntaxe des expressions régulières est différente pour différentes langues. –

Répondre

10

Ma suggestion:

(?:(?:(?<hh>\d{1,2})[:.])?(?<mm>\d{1,2})[:.])?(?<ss>\d{1,2}) 

structuré:

(?:      # group 1 (non-capturing) 
    (?:     # group 2 (non-capturing) 
    (?<hh>\d{1,2})  #  hours 
    [:.]    #  delimiter 
)?     # end group 2, make optional 
    (?<mm>\d{1,2})  # minutes 
    [:.]     # delimiter 
)?      # end group 1, make optional 
(?<ss>\d{1,2})   # seconds (required) 

Si vous le souhaitez, vous pouvez envelopper le regex dans délimiteurs - limites de mots comme \b ou points d'ancrage à cordes (^ et $).

EDIT: En y réfléchissant, vous pouvez restreindre cela davantage pour capturer des temps qui n'ont de sens que. Utilisation

[0-5]?\d 

à la place de

\d{1,2} 

pour capturer des valeurs comprises entre 0 et 59 uniquement, le cas échéant (secondes et minutes).

+0

Aimez les exemples structurés dans regexp ... – gnarf

+0

Awesome! Fonctionne bien - et aime le formatage aussi. Si seulement mon éditeur supportait cela, il serait plus facile de travailler avec. – Kjensen

+0

Le caractère de commentaire pour les expressions régulières n'est-il pas dans le mode "Ignorer les espaces et autoriser les commentaires" au lieu de "//"? – Joey

2

Je suggère l'expression suivante.

^(((?<Hour>[0-9]{1,2})[.:])?(?<Minute>[0-9]{1,2})[.:])?(?<Second>[0-9]{2})$

Cela permettra heures à un seul chiffre combiné à un seul chiffre minutes comme 3:7:21. Si cela n'est pas souhaité, une légère modification est nécessaire.

^(((?<Hour>[0-9]{1,2})[.:](?=[0-9]{2}))?(?<Minute>[0-9]{1,2})[.:])?(?<Second>[0-9]{2})$

L'affirmation de positif (?=[0-9]{2}) dans préanalyse la deuxième expression permet de résoudre ce problème.

1

Il n'y a pas vraiment de bon moyen pour cela, car cela dépend vraiment de votre situation particulière que faire lorsque les trois parties ne sont pas spécifiées. Par exemple, dans de nombreux cas, je préférerais peut-être interpréter 3:30 comme 3 heures et 30 minutes au lieu de 3 minutes et 30 secondes. Cela ne peut pas nuire à être explicite à ce sujet, et à rendre facile, à partir de l'expression régulière, ce que signifient ces types d'intrants.

Par conséquent, je crois personnellement que la première regex n'est pas si moche - elle pourrait être moins "magique", mais elle est beaucoup plus lisible et maintenable. Assurez-vous que vous et les autres pouvez toujours lire et modifier le code plus tard! Si votre langue le supporte, j'utiliserais des regexes étendues (avec un support pour les espaces et les commentaires) et je le diviserais sur trois lignes (ou 6 ou 9 si vous mettez un commentaire sur une ligne séparée). Cela ne changera pas la regex, mais cela la rendra moins laide à coup sûr.

+0

Valeurs valides. La raison pour laquelle je veux l'améliorer est avant tout d'apprendre. – Kjensen

5

Je ne l'ai pas encore testé, mais il devrait fonctionner:

^(?:(?:(?<hours>\d\d?)[:\.])?(?<minutes>\d\d?)[:\.])?(?<seconds>\d\d?)$ 

Edit:
Maintenant, je l'ai testé et vérifié que cela fonctionne.:)

+0

Cela fonctionne, mais capturera 3: 7: 21 ce qui pourrait être ou non être 3:07:21. Et en passant, il n'est pas nécessaire d'échapper au point dans les groupes de caractères. (Ou est-ce que je me trompe? Existe-t-il une implémentation de regex exigeant cela?) –

+0

La barre oblique inverse sur le point dans une classe de caractères est inutile. Autoriser 3: 7: 21 pour 3:07:21 est probablement un exemple de «soyez généreux dans ce que vous acceptez». –

+0

J'ai tendance à échapper à certains caractères qui n'ont pas strictement besoin de s'échapper. Même si la classe Regex n'en a pas besoin pour le comprendre, je le ferais peut-être. :) – Guffa

Questions connexes