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

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

  • 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 ]

10 голосов
/ 09 сентября 2009

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

(?:(?:(?<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 или якоря строк (^ и $).

РЕДАКТИРОВАТЬ: Думая об этом, вы можете ограничить это, чтобы захватить время, которое имеет смысл только. Используйте

[0-5]?\d

вместо

\d{1,2}

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

5 голосов
/ 09 сентября 2009

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

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

Edit:
Теперь я проверил это и убедился, что это работает. :)

2 голосов
/ 09 сентября 2009

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

^(((?<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})$

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

1 голос
/ 09 сентября 2009

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...