JavaScript RegExp для автоматического форматирования шаблона
Я видел много функций, которые форматируют телефон или номер (запятая и десятичная) в сообществе стека, как этот вопрос здесь и другие. Вот что я хочу:
Шаг 1: Поддерживайте библиотеку для таких шаблонов:
var library = {
fullDate : {
pattern : /^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}$/,
error : "Invalid Date format. Use YYYY-MM-DD format."
},
fullDateTime : {
pattern : /^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2} [0-9]{1,2}:[0-9]{1,2}$/,
error : "Invalid DateTime format. Use YYYY-MM-DD HH:MM (24-hour) format."
},
tel : {
pattern : /^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/,
error : "Invalid Telephone format."
}
};
Шаг 2: автоматически добавьте символ по мере его ввода. Для примера добавьте -
после 4 чисел в Date.
У меня есть текстовое поле:
<input type="text" data-validate="fullDate" placeholder="YYYY-MM-DD"/>
И возможное место для запуска script как:
$('body').on('keyup','input',function(){
var validate = $(this).data('validate');
var pattern = library[validate].pattern;
//Some more steps here....
});
Но я не могу сделать дальше, потому что я новичок в RegExp. Здесь сценарий запуска. Кто-нибудь?
Дальнейшие заметки: я смог проверить, используя следующие функции, но то, что я хочу, автоматически создает шаблон:
function validate(libraryItem, subject){
var item = library[libraryItem];
if(item !== undefined){
var pattern = item.pattern;
if(validatePattern(pattern, subject)){
return true;
} else {
return item.error;
}
}
return false;
}
function validatePattern(pattern, subject){
return pattern.test(subject);
}
Ответы
Ответ 1
Это не так сложно, как вы думаете. Вы ищете JQuery Masked ввода и другие альтернативные библиотеки. Вот документация . Все что вам нужно:
<input id="date" type="text" placeholder="YYYY-MM-DD"/>
и script:
$("#date").mask("9999-99-99",{placeholder:"YYYY-MM-DD"});
Вот ссылка на демонстрационную ручку:
http://codepen.io/anon/pen/gpRyBp
Для реализации проверки используйте эту библиотеку:
https://github.com/RobinHerbots/jquery.inputmask
Ответ 2
Здесь необходимо разбить регулярное выражение в подвыражении, которое соответствует части строки, и предложить завершить на основе следующего символа в регулярном выражении.
Я написал наивный парсер, который анализирует выражение и делит на атомное подвыражение.
var parser = function(input) {
var tokenStack = [];
var suggestions = [];
var suggestion;
var lookAhead;
if (input[0] === '/')
input = input.slice(1, input.length - 1);
var i;
for (i = 0; i < input.length - 1; i++) {
lookAhead = input[i + 1];
switch (input[i]) {
case '(':
tokenStack.push('(');
break;
case '[':
tokenStack.push('[');
break;
case ')':
if (tokenStack[tokenStack.length - 1] === '(') {
tokenStack.pop();
if (tokenStack.length === 0) {
suggestion = generateSuggestion(input, i);
if (suggestion !== null)
suggestions.push(suggestion);
}
}
else
throw 'bracket mismatch';
break;
case ']':
if (lookAhead === '{') {
while (input[i] !== '}')
i++;
}
if (tokenStack[tokenStack.length - 1] === '[') {
tokenStack.pop();
if (tokenStack.length === 0) {
suggestion = generateSuggestion(input, i);
if (suggestion !== null)
suggestions.push(suggestion);
}
}
else
throw 'bracket mismatch';
break;
default:
if (tokenStack.length === 0) {
suggestion = generateSuggestion(input, i);
if (suggestion !== null)
suggestions.push(suggestion);
}
break;
}
}
return suggestions;
}
var generateSuggestion = function(input, index) {
if (input[index].match(/[a-zA-Z\-\ \.:]/) !== null)
return {
'regex': input.slice(0, index) + '$',
'suggestion': input[index]
};
else
return null;
}
Вот пример ввода и вывода parser()
parser('/^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}$/');
// output:
[ { regex: '^[0-9]{4}$', suggestion: '-' },
{ regex: '^[0-9]{4}-[0-9]{1,2}$', suggestion: '-' } ]
Таким образом, на каждом keyup
вам нужно проверить список RegExp, сгенерированный parser
, и если какой-либо из них соответствует вводу, используйте предложение.
EDIT:
Отредактировано generateSuggestion
, чтобы соответствовать только полному выражению.
Вот пример скрипта: http://jsfiddle.net/a7kkL6xu/6/
Если backspace игнорируется: http://jsfiddle.net/a7kkL6xu/7/
Ответ 3
Это можно сделать с помощью одного регулярного выражения.
Для этого требуется MM: DD и HH: MM - 2 цифры, а YYYY - 4 цифры.
полностью действительный вход, но соответствует всем частичным.
Это может быть сделано для того, чтобы разрешить однозначную действительность для упомянутой 2-значной цифры.
Но сделайте это, сделайте преждевременные предложения по форме - - [ ] :
.
Если вы не хотите вводить предложение, то 1 или 2 цифры в порядке.
JavaScript не допускает утверждений lookbehind, поэтому частичные выражения полей
ниже допустимых выражений поля в их соответствующих группах.
В основном, что происходит, вход записывается в каждое событие нажатия клавиши.
Все, что вы делаете, соответствует текущему входу в обработчике событий.
Без предложений вы просто пишете ввод со всем совпадением (группа 0).
Совпадение (группа 0) будет содержать только действительное частичное или полное совпадение.
Действительные заполненные группы захвата поля от 1 до 5
[Год, Месяц, День, Часы, Минуты]
Неполные поля захватываются группами с 6 по 10
[Минуты, Часы, День, Месяц, Год]
Это логика:
// Note 1 - can handle control chars by just returning.
// Note 2 - can avoid rewrite by keeping a global of last good,
// then return if current == last.
if ( last char of group 0 is a dash '-' or space ' ' or colon ':'
or any of groups 6 - 10 matched
or group 5 matched )
set input equal to the group 0 string;
else if ( group 4 matched ) // Hours
set input equal to group 0 string + ':';
else if ( group 3 matched ) // Day
set input equal to group 0 string + ' ';
else if ( group 1 or 2 matched ) // Year or Month
set input equal to group 0 string + '-';
else // Here, effectively strips bad chars from input box
// before they are displayed.
set input equal to group 0 string;
Обратите внимание, что если группа не соответствует ей, значение будет NULL
и для проверки всей действительности, не должно быть никаких партиций и
группы 1 - 3 должны быть полными только для YYYY-MM-DD или 1 - 5 с дополнительным
время HH: MM
Заключительное примечание: это синтаксический анализатор и, фактически, тестовый пример внешнего вида, т.е. мерцание, перезаписи ввода в реальном времени.
Если все будет хорошо, логика в обработчике может включать проверку дня (и переписать) в зависимости от месяца.
Кроме того, помещение можно расширить до любого типа ввода, любого типа формы и
комбинации разделителей форм и т.д.
Если он работает, вы можете создать библиотеку.
# /^(?:(19\d{2}|20[0-1]\d|202[0-5])(?:-(?:(0[1-9]|1[0-2])(?:-(?:(0[1-9]|[1-2]\d|3[0-1])(?:[ ](?:(0\d|1\d|2[0-3])(?::(?:(0\d|[1-5][0-9])|([0-5]))?)?|([0-2]))?)?|([0-3]))?)?|([01]))?)?|(19\d?|20[0-2]?|[12]))/
^ # BOL
(?:
( # (1 start), Year 1900 - 2025
19 \d{2}
| 20 [0-1] \d
| 202 [0-5]
) # (1 end)
(?:
- # -
(?:
( # (2 start), Month 00 - 12
0 [1-9]
| 1 [0-2]
) # (2 end)
(?:
- # -
(?:
( # (3 start), Day 00 - 31
0 [1-9]
| [1-2] \d
| 3 [0-1]
) # (3 end)
(?:
[ ] # space
(?:
( # (4 start), Hour 00 - 23
0 \d
| 1 \d
| 2 [0-3]
) # (4 end)
(?:
: # :
(?:
( # (5 start), Minutes 00 - 59
0 \d
| [1-5] [0-9]
) # (5 end)
|
( [0-5] ) # (6)
)?
)?
|
( [0-2] ) # (7)
)?
)?
|
( [0-3] ) # (8)
)?
)?
|
( [01] ) # (9)
)?
)?
|
( # (10 start)
19 \d?
|
20 [0-2]?
|
[12]
) # (10 end)
)
Ответ 4
Можно добавить символ, только если это единственный возможный выбор в этой точке. Примером может быть регулярное выражение для формата YYYY-MM-DD HH24:mm
: -
, :
и
(пробел). Вот соответствующее регулярное выражение (/
, чтобы сделать его более читаемым, оно более строже, чем таковое в вопросе, некоторые незаконные даты все еще возможны, например, 31 февраля):
^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01]) (?:[01][0-9]|2[0-3]):[0-5][0-9]$
Входы с фиксированной длиной вы можете использовать решение @DineshDevkotastrong > , чтобы добавить литералы и проверить весь текст с помощью регулярного выражения. Я считаю это самым простым и простым решением. Вы также можете записать год, месяц и день, чтобы проверить день математически. Также правила, такие как "дата не в будущем" или "максимум 100 лет назад", могут быть разрешены только в JS, а не только с регулярным выражением.
Единственные дополнительные шаблоны, которые приходят на ум, когда персонаж может быть добавлен автоматически:
- A
+
после литерала, например. на A+
добавить A
- Минимальные события в целом, например. на
(?:foo){2,5}
добавить foofoo
не путать с [fo]{2,5}
, где никакие символы не могут быть добавлены
- Литералы после максимальной длины переменной части, например. на
(?:foo){1,3}bar
добавить bar
после текста foofoofoo
, прежде чем это невозможно.
- Добавить остатки, например.
foo|bar
добавить ar
при вводе b
и oo
при вводе f
(также возможно в шаблоне, показанном в 3.), но это не будет работать для ^[a-z]+?(?:foo|bar)$
, потому что мы не знаем когда пользователь планирует закончить текст, и он может стать действительно сложным (foo|flo|flu|food|fish
только sh
может быть добавлен после fi
).
Как видно из 3. и 4., те дополнительные случаи, когда символы могут быть добавлены, очень ограничены, как только появляются части с переменной длиной. Вам придется анализировать регулярное выражение, разделять его в буквальном и регулярном выражении. Затем вам нужно проанализировать/проанализировать детали регулярных выражений, чтобы включить дополнительные случаи, упомянутые выше, в которые можно добавить символы. На самом деле не стоит того, чтобы спросить меня. (В вашем шаблоне tel нельзя добавить ни одного символа.)