Соответствие часов / минут / секунд в регулярных выражениях-лучший способ?

поэтому мне нужно получить часы, минуты и секунды записи, как это:

  • 04:43:12
  • 9.43.12
  • 1:00
  • 01.04
  • 59
  • 09

первые два часа, минуты и секунды. Рядом-минуты и секунды. Последние две секунды.

и я придумал это выражение, которое работает..:

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

но это некрасиво, и я хочу, чтобы рефакторинг его не будьте 3 разных выражения (в основном, чтобы узнать). Я попробовал:

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

но это не работает - минуты и секунды иногда запутаются. Мой мозг болит, и я не могу понять, что я делаю неправильно.

4 ответов


мое предложение:

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

структуру:

(?:                     # 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)

если вы хотите, вы можете обернуть выражение в разделители - как границы слов \b или String якоря (^ и $).

EDIT: думая об этом, вы можете ограничить это дальше, чтобы захватить время, которое имеет смысл только. Использовать

[0-5]?\d

на месте

\d{1,2}

для захвата значений только от 0 до 59, где это необходимо (секунды и минуты).


Я еще не тестировал это, но он должен работать:

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

изменить:
Теперь я проверил его и убедился, что он работает. :)


Я предлагаю следующее выражение.

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

Это позволит одноразрядные часы в сочетании с одной цифрой минут, как 3:7:21. Если это нежелательно, требуется небольшое изменение.

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

положительное утверждение lookahead (?=[0-9]{2}) во втором выражении решает эту проблему.


нет реальной хороший способ для этого, так как это действительно зависит от вашей конкретной ситуации, что делать, когда указаны не все три части. Например, во многих случаях я бы предпочел интерпретировать 3: 30 как 3 часа 30 минут вместо 3 минут 30 секунд. Это не помешает быть явным об этом и сделать его легким для получения из регулярного выражения, что означают эти виды входов.

поэтому я лично считаю, что первое регулярное выражение не так уж уродливо-это может быть меньше "волшебства", но гораздо более читабельно и ремонтопригодно. Убедитесь, что вы и другие могут прочитать и изменить код позже!

Если ваш язык поддерживает его, я бы использовал расширенные регулярные выражения (с поддержкой пробелов и комментариев) и разделил его на три строки (или 6 или 9, Если вы поместите комментарий в отдельную строку). Это не изменит регулярное выражение, но это сделает его менее уродливым.