2011-05-20 3 views
7

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

Вот что я пришел до сих пор.

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

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

+5

Регулярное выражение кажется странным инструментом для этой задачи. Не можете ли вы преобразовать текст в дату и проверить его значения? –

+1

Хотя это теоретически можно было бы сделать, регулярное выражение, которое обрабатывало правильное количество дней для каждого месяца (включая високосные годы), было бы безумно сложным. Почему бы просто не разделить дату и проверить каждый компонент? (Или еще лучше использовать один из многих парсеров даты на CPAN.) – cjm

+0

@ Zerobu, почему вы задаете тот же вопрос снова, чем год назад ??? [Вопросы/2573466/согласования-а-дата-в-Perl] (http://stackoverflow.com/questions/2573466/matching-a-date-in-perl). Хорошо, год назад у вас не было ответа регулярного выражения, но я надеюсь, что вы видите из @Seth answer regex не полезно проверять дату. – stema

ответ

25

Regex для 0-31:

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

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

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

Спасибо, по-видимому, другим плакатам было трудно выяснить, что я искал, хотя я уже сказал, что мне нужно – Zerobu

+3

Это потому, что дата не обязательно будет действительна. Он не будет, например, отклоняться 31 февраля 2011 года. Regex это неправильный инструмент для этого. – MRAB

+1

был в 1974 году високосным годом? как насчет 2000? –

1

Try это:
/(0?[1-9]|1[012])\/(0?[1-9]|[12][0-9]|3[01])\/((19|20)\d\d)/

5
^(((((((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])))))$ 

От Expressions in category: Dates and Times

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

Вы можете, конечно, изменить [\.\-/] на /, чтобы разрешить косые черты.

+11

+1 для смешного количества сложности. @Zerobu, надеюсь, это показывает вам, почему regex - плохая идея для этой проблемы! Даже этот зверь не совсем корректен: как отмечает автор оригинала, он неверно совпадает с 02/29/1900. – OpenSauce

12
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 расскажет вам, почему.

+0

Я никогда не понимаю, почему люди хотят переопределять что-то, не говоря уже о чем-то сложном, как синтаксический анализ даты! –

1

Является ли регулярное выражение обязательным? Если нет, то лучше использовать другой подход, например 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"; 
} 
2

Это не все, что трудно ...

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 
8
  • Как многие уже отмечали выше, если мы хотите проверить дату в целом, тогда 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 за указание на это.

Так что в результате регулярных выражений является: ^(([0]?[1-9])|([1-2][0-9])|(3[01]))$

Испытано здесь: http://regexr.com/?383k1[UPDATE]

+1

Лучшие оценки для объяснения. Оригинальный вопрос не сформулирован особенно хорошо (не ошибка OPs), но если вы ищете REGEXP для проверки дня месяца, это так. –

+2

Улучшение принятого ответа. Тем не менее, это будет принимать 001, 00000001 и т. Д. Я предлагаю^(([0]? [1-9]) | ([1-2] [0-9]) | (3 [01])) $ http: //regexr.com?383k1 –

+1

@MattFrear - Да, хорошо поймать! Я допустил ошибку, комбинируя '([0] [1-9])' и '([1-9])' вместе как '([0] * [1-9])' ... пока он должен четко be '([0]? [1-9])'. Спасибо, что поделились тестовым случаем. –

Смежные вопросы