2015-05-29 2 views
1

Я пытаюсь использовать регулярное выражение для совпадения даты (с 2000-2099). следующее регулярное выражение отлично.не соответствует пустой строке для regex

((((^20[02468][048])|(^20[13579][26]))-(((0[13578]|1[02])-(0[1-9]|[12]\d|3[0-1]$))|((0[469]|11)-(0[1-9]|[12]\d|30$))|(02-(0[1-9]|1\d|2[0-9]$)))|((^20\d{2})-(((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]$))|((0[469]|11)-(0[1-9]|[12]\d|30$))|(02-(0[1-9]|1\d|2[0-8]$)))))|0000-00-00){1} 

примечание: матч високосный год (#days в месяц: 31, 30, 29) или нормальный год (#days в месяц: 31, 30, 28) или по умолчанию (0000-00-00)

однако он соответствует пустой строке тоже. Я попытался найти решение, например, this one, но мой путь более сложный, и я попытался добавить {1,}, как предложение, указанное в ссылке.

Но это не работает.

и на самом деле я не понимаю, почему он соответствует пустой строке, может ли кто-нибудь, пожалуйста, рассказать мне тоже?

+2

Вы реализуете это на определенном языке? Очень вероятно, что вы можете обойти это с помощью функции длины строки, которая предоставляется большинством языков. – npinti

+0

Я пишу для атрибута 'pattern'' input' HTML, это регулярное выражение хранится в переменной PHP, а затем эхо-код HTML –

+0

Внешний '(...) {1}' бессмыслен; это означает то же, что и «...». Я надеюсь, что это часть попытки разобраться в проблеме «она соответствует пустой строке». –

ответ

1

Добавьте необходимый атрибут для ввода:

<input pattern="(((^20[02468][048])|(^20[13579][26]))-(((0[13578]|1[02])-(0[1-9]|[12]\d|3[0-1]$))|((0[469]|11)-(0[1-9]|[12]\d|30$))|(02-(0[1-9]|1\d|2[0-9]$)))|((^20\d{2})-(((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]$))|((0[469]|11)-(0[1-9]|[12]\d|30$))|(02-(0[1-9]|1\d|2[0-8]$)))))|0000-00-00" 
type="text" 
required/> 

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

http://jsfiddle.net/kyaLhqpu/ против http://jsfiddle.net/kyaLhqpu/1/

+0

большое спасибо. он работает сейчас. Я могу избежать javascript какое-то время: P –

0

Возможно, имеет смысл извлечь это регулярное выражение из тега input и просто создать функцию Javascript, целью которой является проверка ввода.

Проверка будет два раза:

  1. Во-первых, убедитесь, что строка при условии непусто.
  2. Вы проверяете строку против выражения, которое вы используете в настоящее время.

Примечания, хотя, использование Javascript может иметь дополнительное преимущество, когда вы используете реальные математические операторы, такие как <, > и = выполнить проверку числового диапазона, в отличие от того, что вы делаете сейчас. Конечный результат должен быть легче понять и изменить, если возникнет необходимость в будущем.

+0

на самом деле то, что я делаю: сделать динамическую таблицу, данные которой получены из db Каждая запись имеет 2 ввода даты (validate!). есть кнопка отправки для каждой строки данных. Я начал с javascript, но, возможно, потому, что я новичок в js, я могу получить только первую строку (форму) таблицы. Я тоже не могу найти решение. и затем я думаю о регулярном выражении в html вместо этого. –

+0

@HonLunChan: Возможно, вам придется перебирать строки данных. При этом * dtanders *, похоже, дает правильное решение. – npinti

+0

ах, но почему вы говорите, что это недействительное решение? я не понимаю. я думаю, что оба пути будут делать? –

0

У меня нет прямого ответа на вопрос, с пустой строкой принимаются. Я не думаю, что проблема в регулярном выражении - ни в оригинале, ни в пересмотренной версии. Я думаю, что suggestion на dtanders, вероятно, находится на пути; ваши комментарии поддерживают это.

Однако, я думаю, что есть место для упрощения и улучшения вашего регулярного выражения.

В регулярном выражении много ненужных круглых скобок, и логика кажется немного запутанной. Вы проверяете 0000-00-00 (на самом деле последний вариант, но самый короткий для описания), или за «любую действительную дату в любой високосный год» или за «любую действительную дату в течение не-високосного года». Это приводит к большому повторному куску регулярного выражения для проверки всех инвариантных месяцев.

Было бы меньше повторений, если вы изменили свой код для проверки на 0000-00-00 или любого действительного дня в любом месяце или в любой действительный високосный день.

В Perl вы можете писать расширенные регулярные выражения, где пробелы не значимы, и регулярное выражение может быть распространено по многим строкам, чтобы было легче понять. Это приводит к тестовому сценарию, как:

#!/usr/bin/env perl 
use strict; 
use warnings; 

my $rx = qr/ 
    ^(
     20\d{2} - 
      ( (0[13578] | 1[02]) - (0[1-9] | [12]\d | 3[01]) 
      | ((0[469] | 11) - (0[1-9] | [12]\d | 30)) 
      | (02 - (0[1-9] | 1\d | 2[0-8])) 
      ) 
    | (^20[02468][048] | ^20[13579][26]) - 02 - 29 # Leap day 
    | 0000-00-00 
    )$ 
    /x; 

while (<>) 
{ 
    chomp; 
    printf "%s: %s\n", (m/$rx/ ? "PASS" : "FAIL"), $_; 
} 

Если регулярное выражение уплощена на одной линии (и комментарий удален), то вы получите:

^(20\d{2}-((0[13578]|1[02])-(0[1-9]|[12]\d|3[01])|((0[469]|11)-(0[1-9]|[12]\d|30))|(02-(0[1-9]|1\d|2[0-8])))|(20[02468][048]|20[13579][26])-02-29|0000-00-00)$ 

Оригинальное регулярное выражение занимает 276 символов. Пересмотр занимает 158 при сплющивании.

Я вызывал скрипт regex-hell и создал файл various-dates с различными образцами дат в нем. Выход был:

PASS: 0000-00-00 
FAIL: 0001-00-00 
FAIL: 0000-01-00 
FAIL: 0000-00-01 
FAIL: 2000-00-00 
FAIL: 2000-01-00 
FAIL: 2000-00-01 
PASS: 2000-01-01 
PASS: 2000-02-28 
PASS: 2000-02-29 
PASS: 2001-02-28 
FAIL: 2001-02-29 
PASS: 2003-03-31 
FAIL: 2003-03-32 
PASS: 2004-04-30 
FAIL: 2004-04-31 
PASS: 2005-05-31 
FAIL: 2005-05-32 
FAIL: 2005-05-00 
PASS: 2005-05-01 
PASS: 2006-06-30 
FAIL: 2006-06-31 
PASS: 2007-07-31 
FAIL: 2007-07-32 
PASS: 2008-08-31 
FAIL: 2008-08-32 
PASS: 2009-09-30 
FAIL: 2009-09-31 
FAIL: 2009-09-32 
PASS: 2010-10-30 
PASS: 2010-10-31 
FAIL: 2010-10-32 
PASS: 2011-11-30 
FAIL: 2011-11-31 
PASS: 2012-12-31 
FAIL: 2012-12-32 
PASS: 2099-01-01 
PASS: 2099-12-31 
FAIL: 
+0

Вы имеете в виду, что если я должен проверить его в последовательности '0000-00-00', тогда нормальный, то високосный год? от самого маленького до самого большого, и удалить некоторые резервные скобки? Я думаю, что добавление '()' будет легче увидеть, но я знаю, что внутри '()' будет память регулярного выражения, так что это будет медленнее? –

+0

Вначале нет достоинства положить 0000-00-00; на самом деле мой пересмотренный RE оставил его в конце. Было проще объяснить, что в начале есть простая запись, вот и все. Я обнаружил, что дополнительные круглые скобки путают, а не помогают (они были не все, где я ожидал их), но ваш RE работал правильно при использовании (и ваша проблема заключалась в том, что он просто не применялся, когда в поле не было данных), и моя более короткая версия также работает - и потому, что она проще, она может быть незначительно, но, вероятно, неизмеримо быстрее. В основном, однако, это легче понять. –

+0

Я полностью читал ваше регулярное выражение. Я очень ценю ваше регулярное выражение !! Большое спасибо за лучшую идею! И я думаю, что понимаю, почему ты сейчас это понимаешь! :) –

0

Я не думаю, что это соответствует пустой строке, и neither does Rubular, но в любом случае, добавить привязанную отрицательные смотреть вперед для завершения ввода ^(?!$) в свое регулярное выражение, чтобы предотвратить пустой от соответствие:

^(?!$)((((^20[02468][048])|(^20[13579][26]))-(((0[13578]|1[02])-(0[1-9]|[12]\d|3[0-1]$))|((0[469]|11)-(0[1-9]|[12]\d|30$))|(02-(0[1-9]|1\d|2[0-9]$)))|((^20\d{2})-(((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]$))|((0[469]|11)-(0[1-9]|[12]\d|30$))|(02-(0[1-9]|1\d|2[0-8]$)))))|0000-00-00){1} 
Смежные вопросы