Регулярное выражение для соответствия действительному дню в дате

Мне нужна помощь при появлении регулярного выражения, чтобы убедиться, что пользователь вводит действительную дату Строка будет в формате mm/dd/yyyy

Вот что я придумал до сих пор.

/\[1-9]|0[1-9]|1[0-2]\/\d{1,2}\/19|20\d\d/

Я проверил регулярное выражение, в котором пользователь не может ввести день, превышающий 12, и годы должны начинаться с "19" или "20". У меня возникают проблемы с выяснением некоторой логики для проверки дня. День не должен превышать 31.

Ответ 1

Regex для 0-31:

(0[1-9]|[12]\d|3[01])

Или, если вам не нужны дни с предшествующим нулем (например, 05):

([1-9]|[12]\d|3[01])

Ответ 2

use DateTime;

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

DateTime и formatters - это ваше решение, Используй их! Иногда они немного перегружены, но часто это работает для вас по дороге.

my $dayFormat = new DateTime::Format::Strptime(pattern => '%d/%m/%Y');
my $foo = $dayFormat->parse_datetime($myDateString);

$foo теперь является объектом DateTime. Наслаждаться.

Если ваша строка даты не была правильно отформатирована, $foo будет "undef" и $dayFormat->errstr расскажет вам, почему.

Ответ 3

  • Как многие отмечали выше, если мы хотим проверить дату в целом, то RegEx - очень плохой выбор.
  • Но если мы хотим сопоставить шаблон чисел, в данном случае из 01-31, то с RegEx все в порядке, если есть некоторая внутренняя логика, которая проверяет дату в целом, если это необходимо.
  • Я вижу ожидаемый ответ в настоящее время не для 10, 20.

    • Тест: gawk 'BEGIN{ for(i=0;i<=32;i++){ if (i ~ /^([0-2]?[1-9]|3[01])$/){print i " yes"}else {print i " no"} } }
    • Это можно исправить следующим образом: ^([0-2]?[1-9]|3[01]|10|20)$

Поэтому, пожалуйста, рассмотрите следующее решение...

1. Определите наборы, которые должны быть сопоставлены:

  • Дни с префиксом "0": {01,...,09},{10,...,31}
    • Подмножество {10,...,31} можно разбить на => {10,...,29},{30,31}
  • Без префикса: {1,...,31} => {1,...,9},{10,...,31}

2. Соответствующие регулярные выражения для каждого подмножества:

---------------------------------
Sub-Set     |  Regular-Expression
---------------------------------
{01,...,09} | [0][1-9]
{10,...,29} | [1-2][0-9]
{30,31}     | 3[01]
{1,...,9}   | [1-9]
---------------------------------

Теперь мы можем сгруппировать ([0][1-9]) и ([1-9]) вместе как ([0]?[1-9]). Где ? означает 0 или 1 вхождение шаблона/символа. [ОБНОВЛЕНИЕ] - Спасибо, @MattFrear, за то, что указали на это.

В результате RegEx выглядит так: ^(([0]?[1-9])|([1-2][0-9])|(3[01]))$

Проверено здесь: http://regexr.com/?383k1 [ОБНОВЛЕНИЕ]

Ответ 4

^(((((((0?[13578])|(1[02]))[\.\-/]?((0?[1-9])|([12]\d)|(3[01])))|(((0?[469])|(11))[\.\-/]?((0?[1-9])|([12]\d)|(30)))|((0?2)[\.\-/]?((0?[1-9])|(1\d)|(2[0-8]))))[\.\-/]?(((19)|(20))?([\d][\d]))))|((0?2)[\.\-/]?(29)[\.\-/]?(((19)|(20))?(([02468][048])|([13579][26])))))$

Из Выражения в категории: Даты и время

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

Вы можете, конечно, изменить [\.\-/] на / только для разрешений.

Ответ 5

Это не так сложно...

qr#^
    (?: 0[1-9] | 1[012] )
    /
    (?:
        0[1-9] | 1[0-9] | 2[0-8]
        | (?<! 0[2469]/ | 11/ ) 31
        | (?<! 02/ ) 30
        | (?<! 02/
             (?= ... 
                 (?: 
                     .. (?: [02468][1235679] | [13579][01345789] )
                     | (?: [02468][1235679] | [13579][01345789] ) 00
                 )
             )
        ) 29
    )
    /
    [0-9]{4}
    \z
#x

Ответ 6

Попробуйте:
/(0?[1-9]|1[012])\/(0?[1-9]|[12][0-9]|3[01])\/((19|20)\d\d)/

Ответ 7

Является ли регулярное выражение обязательным? Если нет, вам лучше использовать другой подход, например DateTime::Format::DateManip

my @dates = (
    '04/23/2009',
    '01/22/2010 6pm',
    'adasdas',
    '1010101/12312312/1232132'
);

for my $date ( @dates ) 
{
    my $date = DateTime::Format::DateManip->parse_datetime( $date );
    die "Bad Date $date"  unless (defined $date);
    print "$dt\n";
}

Ответ 8

Регулярное выражение на 0-31 день:

0 [1-9] | [12]\d | 3 [01]) без префикса 0 - когда "1", "23"...

([1-9] | [12]\d | 3 [01]) с префиксом 0 - когда "01", "04"

(0? [1-9] | [12]\d | 3 [01]) - с или без "0" - когда ""

Ответ 9

Упрощенное регулярное выражение:

([12]\d|3[01]|0?[1-9])

Рассмотрите принятый ответ и это выражение:

(0[1-9]|[12]\d|3[01])

Это соответствует 01, но не 1

Другое выражение в принятом ответе:

([1-9]|[12]\d|3[01])

Это соответствует 1, но не 01

Невозможно добавить предложение OR, чтобы заставить их обоих работать.

Тот, который я предложил, соответствует обоим. Надеюсь это поможет.

Ответ 10

Я работал с этим некоторое время, и лучшим из предложенных мной регулярных выражений является следующее:

\b(0)?(?(1)[1-9]|(3)?(?(2)[01]|[12][0-9]))\b|\b[1-9]\b

Он будет соответствовать следующим номерам:

1 01 10 15 20 25 30 31

Это не соответствует следующему:

32 40 50 90