Общий вопрос
Как вы предотвращаете соответствие регулярного выражения, если этот шаблон был сопоставлен N раз ранее?
Конкретный пример
У меня есть 13-значный идентификатор записи, который пользователь вводит в текстовое поле, например "123-456-7891011".
Поведение, которое я пытаюсь инкапсулировать, - добавить тире до 4-й и 7-й цифр по мере их ввода. У меня есть все javascript вокруг обработки события без проблем.
Он всегда будет числовым - я обрабатываю это до этого конкретного шага.
Я могу получить регулярное выражение достаточно хорошо, чтобы вставить тире, когда я набираю n + 4-й разряд каждый раз. Мне нужно, чтобы он не делал этого в любое время после второго "-",
Самое близкое, что у меня есть в обработчике событий (oninput
):
var addDash = /([^\-\d{3}]*\d{3})(\d+)/;
this.value = this.value.replace(addDash, "$1-$2");
Например, ввод "1234567891011" приводит к "123-456-789-101-1", где я хочу "123-456-7891011".
Есть, вероятно, другие способы справиться с этой ситуацией (например, split
и join
), но для целей этого вопроса пусть придерживается ответа с правильным шаблоном регулярного выражения, если такой шаблон возможен. Происходят и другие вещи, которые сделали бы эту модель очень полезной - мне просто не повезло.
Для ясности этот шаблон будет запущен oninput
в текстовом поле - совпадение должно работать для любой длины символов от 1 до 13:
"123456" -> "123-456"
"123456789" -> "123-456-789"
"1234567891011" -> 123-456-7891011"
Использование регулярного выражения без дополнительного JS:
var addDash = /^((\d{3}\-?)(\d{3}\-?)?)(\d)$|^(\d{3})(\d)$/;
this.value = this.value.replace(addDash, "$1$5-$4$6");
Начиная с начала строки, сопоставьте 3 цифры с необязательным "-" и, возможно, еще 3 цифры, а за ними следует последняя цифра в конце строки. Если это не соответствует, посмотрите, начинается ли строка с 3-х цифр, за которыми следует сразу конечная цифра в конце строки.
Получите немного фанки с группами захвата в строке замены, чтобы выполнить нужный формат.
Использовать обратные вызовы.
Вы можете указать функцию как второй параметр. В этом случае функция будет вызываться после выполнения совпадения. Результат функции (возвращаемое значение) будет использоваться в качестве замены строки.
Решение, соответствующее вашим текущим потребностям, - это изменить шаблон и всегда идти полным путем:
this.value = this.value.replace(/^(\d{3})-?(\d{3})?-?(\d*)$/, function (m, a, b, c) {
return b ? a + "-" + b + "-" + c : a + "-" + c;
});
Работа выполнена.
Если вы хотите использовать более общее решение, вы можете использовать переменную счетчика:
var count = 0;
this.value = this.value.replace(/(\d{3})-?/g, function (m, a) {
return ++count <= 2 ? a + "-" : m;
});
Этот использует шаблон, который менее точен для того, что вам нужно, но он должен продемонстрировать, как вы могли бы обобщить различные ситуации, когда вам действительно нужно ограничить количество замен.
Кстати, у вас есть недоразумение синтаксиса: [^\-\d{3}]
не означает, что вы думаете. Он будет соответствовать одному символу, который не является цифрой или ни одним из них: -
, {
или }
. Все внутри [
... ]
скобок определяет класс символов, поэтому такие кванторы, как {n}
имеют смысла.
Вы можете использовать обратный вызов в рамках замены с некоторой логикой о том, как обрабатывать разделители. Это облегчит вам поведение, которое вы ожидаете.
var values = ['12', '123', '123-4', '123-45', '123-456', '123-456-7', '123-456-7891011'];
var addDash = /^(\d{3})-?(\d?\d?\d?)-?(\d*)/;
values.forEach(function(value) {
value = value.replace(addDash, function(match, capture1, capture2, capture3) {
var secondDelimiter = capture2.length == 3 ? '-' : '';
return capture1 + '-' + capture2 + secondDelimiter + capture3;
});
})
console.log(values)
$(function() {
var txt='1232';
var addDash = /^(\d{3})-?(\d?\d?\d?)-?(\d*)/;
$("#test").html(txt.replace(addDash, function(match, capture1, capture2, capture3) {
var firstDelimiter = (capture1.length == 3 && capture2.length > 0) ? '-' : '';
var secondDelimiter = (capture2.length == 3 && capture3.length > 0) ? '-' : '';
return capture1 + firstDelimiter + capture2 + secondDelimiter + capture3;
}));
})