Регулярное выражение для полного синтаксиса даты ISO 8601

Обновление. В настоящее время достигнуто рабочее решение с использованием нескольких регулярных выражений одновременно

Я ищу регулярное выражение, которое охватывает диапазон приемлемого синтаксиса для дат ISO 8601. Большинство библиотек и регулярных выражений охватывают только подмножество или «упрощенную» версию 8601, такую ​​как RFC 3339, но полный 8601 включает способы выражения продолжительности времени и интервалов. Запись в Википедии для ISO 8601 дает хороший обзор, но вкратце все они должны быть действительными датами:

var testDates = {
    'year' : "2013",        
    'date' : "2013-01-05",
    'datetime' : "2013-01-05T04:13:00+00:00",
    'Duration only' : "P1Y2M10DT2H30M",
    'Week Duration' : "P1W",
    'Range with start and end' : "2007-03-01T13:00:00Z/2008-05-11T15:30:00Z",
    'Range of Date/Duration' : "2007-03-01T13:00:00Z/P1Y2M10DT2H30M",
    'Range of Date/Duration 1 month' : "2012-10/P1M",
    'Range of Date/Duration 1 week' : "2012-10/P1W",
    'Range of Duration/Date' : "P1Y2M10DT2H30M/2007-03-01T13:00:00Z", 
    'Repeating interval 5 times' : "R5/2007-03-01T13:00:00Z/P1Y2M10DT2H30M", 
    'Repeating interval weekly indefinitely' : "R/2012-10/P1W",
    'Repeating interval monthly 5 times' : "R5/2012-10/P1M"
}

Я пытаюсь создать регулярное выражение, которое будет охватывать все эти возможности. Я собрал несколько компонентов вместе, но недостаточно хорошо разбираюсь в регулярных выражениях, чтобы все они работали как одно выражение и охватывали все возможные случаи. Простое выполнение простого «ИЛИ» между ними, похоже, не работает должным образом, но, возможно, я делаю это не совсем правильно.

Выражения, которые я пробовал, включают следующее:

var regex = {
    'Date' : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
    'Duration' : /^P(?=\w*\d)(?:\d+Y|Y)?(?:\d+M|M)?(?:\d+W|W)?(?:\d+D|D)?(?:T(?:\d+H|H)?(?:\d+M|M)?(?:\d+(?:\­.\d{1,2})?S|S)?)?$/,      
    'Range of Date/Date' : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?(\/)([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,      
    'Range of Date/Duration' : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?(\/)P(?=\w*\d)(?:\d+Y|Y)?(?:\d+M|M)?(?:\d+W|W)?(?:\d+D|D)?(?:T(?:\d+H|H)?(?:\d+M|M)?(?:\d+(?:\­.\d{1,2})?S|S)?)?$/,
    'Range of Duration/Date' : /^P(?=\w*\d)(?:\d+Y|Y)?(?:\d+M|M)?(?:\d+W|W)?(?:\d+D|D)?(?:T(?:\d+H|H)?(?:\d+M|M)?(?:\d+(?:\­.\d{1,2})?S|S)?)?\/([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
    'Repeating interval' : /^R\d*\/([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?\/P(?=\w*\d)(?:\d+Y|Y)?(?:\d+M|M)?(?:\d+W|W)?(?:\d+D|D)?(?:T(?:\d+H|H)?(?:\d+M|M)?(?:\d+(?:\­.\d{1,2})?S|S)?)?$/
}   

Я собрал пример сценария, который пробует эти выражения в каждую из дат, перечисленных выше, но если кто-нибудь может дать рекомендации по объединению всех этих случаев в одно выражение, я был бы очень признателен.

Вариант использования, который приводит к этому, заключается в проверке даты ISO 8601 для документа схемы JSON. Схема JSON обеспечивает некоторую гибкость в том, как что-то проверяется, поскольку вы можете предоставить несколько правил или регулярных выражений для тестирования. В этом случае я мог бы решить свою проблему, используя несколько регулярных выражений, а не одно комбинированное выражение.

Обновление: до сих пор проблема решалась с помощью этого подхода (одновременное использование нескольких отдельных выражений).

If I were to do that, then the one case which I have not solved is a range that starts with a duration and then specifies an end date (Range of Duration/Date) All the expressions noted before are actually just different combinations of two expressions, one for a datetime and another for a duration. The only one I've been unable to validate properly is "Range of Duration/Date"


Вот сценарий:


person Philip Ashlock    schedule 10.02.2014    source источник
comment
Интересный вопрос, и мне будет любопытно увидеть ваш окончательный ответ. Тем не менее, я настоятельно рекомендую писать эти (нетривиальные) регулярные выражения в режиме свободных интервалов с отступами и комментариями, чтобы их могли читать простые смертные (даже несмотря на то, что JavaScript не поддерживает x-модификатор). С ограничением JS no-x-mode-limit мне нравится включать подробное регулярное выражение в многострочный комментарий, непосредственно предшествующий фактическому литералу RegExp.   -  person ridgerunner    schedule 11.02.2014
comment
Я обновил описание, чтобы отметить, что все эти выражения представляют собой просто разные комбинации двух выражений (одно для даты и одно для продолжительности), и только одна комбинация в настоящее время не работает. Я также обновил суть со ссылками на источник этих двух выражений, где есть дополнительное объяснение того, как они были построены.   -  person Philip Ashlock    schedule 15.02.2014


Ответы (3)


Вот полный набор выражений, которые я нашел для достижения разнообразия синтаксиса ISO 8601. В суть добавлены эти и дополнительные тесты для повторяющихся интервалов.

var regex = {
    'Date' : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
    'Duration' : /^P(?=\w*\d)(?:\d+Y|Y)?(?:\d+M|M)?(?:\d+W|W)?(?:\d+D|D)?(?:T(?:\d+H|H)?(?:\d+M|M)?(?:\d+(?:\­.\d{1,2})?S|S)?)?$/,      
    'Range of Date/Date' : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?(\/)([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,      
    'Range of Date/Duration' : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?(\/)P(?=\w*\d)(?:\d+Y|Y)?(?:\d+M|M)?(?:\d+W|W)?(?:\d+D|D)?(?:T(?:\d+H|H)?(?:\d+M|M)?(?:\d+(?:\­.\d{1,2})?S|S)?)?$/,
    'Range of Duration/Date' : /^P(?=\w*\d)(?:\d+Y|Y)?(?:\d+M|M)?(?:\d+W|W)?(?:\d+D|D)?(?:T(?:\d+H|H)?(?:\d+M|M)?(?:\d+(?:\­.\d{1,2})?S|S)?)?\/([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
    'Repeating interval' : /^R\d*\/([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?\/P(?=\w*\d)(?:\d+Y|Y)?(?:\d+M|M)?(?:\d+W|W)?(?:\d+D|D)?(?:T(?:\d+H|H)?(?:\d+M|M)?(?:\d+(?:\­.\d{1,2})?S|S)?)?$/
}
person Philip Ashlock    schedule 26.02.2014
comment
Модификация регулярного выражения даты, которая строго фиксирует то, что вам нужно для синтаксического анализа даты. Обратите внимание, что 24:00 не фиксируется, но фактически это то же самое, что и отсутствие времени, поэтому любой парсер должен обрабатывать его одинаково. /^([\+-]?\d{4}(?!\d{2}\b))(?:(-?)(?:(0[1-9]|1[0-2])(?:\2([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))(?:[T\s](?:(?:([01]\d|2[0-3])(?:(:?)([0-5]\d))?|24\:?00)([\.,]\d+(?!:))?)?(?:\10([0-5]\d)([\.,]\d+)?)?([zZ]|([\+-](?:[01]\d|2[0-3])):?([0-5]\d)?)?)?)?$/ - person Adam Leggett; 11.01.2019

Позвольте мне подвергнуть сомнению весь подход. Даты, моменты времени и диапазоны — это разные концепции, принятие которых взаимозаменяемо (что я понимаю из-за того, что для всех них требуется одно регулярное выражение) приведет к ошибке пользователя, программиста или (что еще хуже) обоих.

Если допустимые форматы слишком сложны, кто-то сделает ошибки. Ваше приложение не может работать с подмножеством?

person vonbrand    schedule 26.02.2014

Является ли регулярное выражение лучшим/наиболее подходящим решением для этого?

Похоже, вы действительно пытаетесь проанализировать строку в соответствии со спецификацией. Просто посмотрите, насколько сложны некоторые из тех регулярных выражений, которые вы пробовали.

Мое предложение состояло бы в том, чтобы либо сделать более простые регулярные выражения, которые соответствуют каждому шаблону, смешанному с некоторым кодом if/then, либо использовать/создать полный синтаксический анализатор.

Помните, что регулярные выражения были разработаны для сопоставления с образцом, а не для синтаксического анализа. Они отлично подходят для быстрого извлечения значения из строки, но не для более сложных вещей.

person Twisted Mentat    schedule 10.02.2014
comment
Я на самом деле не пытаюсь разобрать его, просто проверить его. Это используется в документе схемы JSON (json-schema.org), поэтому он предназначен для языка агностик, используя только регулярное выражение. - person Philip Ashlock; 11.02.2014
comment
В этом случае я бы создал регулярное выражение для каждого шаблона и сказал читателю применить их все вместо одного мегавыражения, которое пытается охватить их все и нечитаемо. Что дает вам одно регулярное выражение, чего не дадут 6 меньших и более простых для понимания регулярных выражений? Кроме того, что вы думаете, что у вас есть одно регулярное выражение uber, которое сделает все. - person Twisted Mentat; 11.02.2014
comment
К счастью, схема JSON позволяет вам определить несколько возможных правил проверки, поэтому я думаю, что мог бы сделать это в контексте схемы JSON. В этом случае я думаю, что единственное регулярное выражение, которое мне не хватает, — это правильное сочетание дат и продолжительности в диапазоне. Я поработаю над этим и предоставлю обновление здесь. - person Philip Ashlock; 15.02.2014
comment
Я обновил описание и суть, чтобы предложить этот подход. Прямо сейчас мне просто не хватает работающего регулярного выражения для одной из перестановок двух комбинированных выражений (диапазон с продолжительностью/датой). - person Philip Ashlock; 15.02.2014
comment
Вы должны понимать, что даже с этими сложными регулярными выражениями вы все равно будете получать ложные срабатывания. 2014-02-31 не является допустимой датой, но будет совпадать, и то же самое касается 2014-04-31. - person Arjan; 15.02.2014
comment
Все в порядке, основное внимание уделяется проверке синтаксиса ISO 8601. - person Philip Ashlock; 20.02.2014