Regex соответствует точно 5 номерам и одному дополнительному пространству
Недавно мне нужно было создать регулярное выражение для проверки ввода в JavaScript. Вход может содержать 5 или 6 символов и должен содержать ровно 5 номеров и одно дополнительное пространство, которое может быть в любом месте строки. Я вообще не привык к регулярному выражению, и хотя я пытался найти лучший способ, я закончил с этим:
(^\d{5}$)|(^ \d{5}$)|(^\d{5} $)|(^\d{1} \d{4}$)|(^\d{2} \d{3}$)|(^\d{3} \d{2}$)|(^\d{4} \d{1}$)
Это делает то, что мне нужно, поэтому допустимые входы (если 0 - любое число)
'00000'
' 00000'
'0 0000'
'00 000'
'000 00'
'0000 0'
'00000 '
Я сомневаюсь, что это единственный способ добиться такого соответствия с регулярным выражением, но я не нашел способ сделать это более чистым способом. Итак, мой вопрос: как это лучше писать?
Спасибо.
Edit:
Так что можно! Ответ Tom Lord делает то, что мне нужно, с регулярными выражениями, поэтому я отметил его как правильный ответ на мой вопрос.
Однако вскоре после того, как я опубликовал этот вопрос, я понял, что я не думаю правильно, поскольку каждый другой ввод в проекте был легко "валидируемым" с регулярным выражением, я сразу же предполагал, что смогу проверить его и с ним,
Оказывается, я мог бы просто сделать это:
const validate = function(value) {
const v = value.replace(/\s/g, '')
const regex = new RegExp('^\\d{5}$');
return regex.test(v);
}
Спасибо всем за крутые ответы и идеи!:)
Edit2: Я забыл упомянуть, возможно, очень важную деталь, которая заключается в том, что вход ограничен, поэтому пользователь может ввести только до 6 символов. Мои извинения.
Ответы
Ответ 1
Примечание. Использование регулярного выражения для решения этой проблемы может не быть лучший ответ. Как ответил ниже, это может быть проще просто пересчитать цифры и пробелы с помощью простой функции!
Однако, поскольку вопрос задавал регулярный запрос, а в некоторых сценарии, вы можете быть вынуждены решить это с помощью регулярного выражения (например, если вы привязаны к определенной реализации библиотеки), следующее ответ может быть полезным:
Это регулярное выражение соответствует строкам, содержащим ровно 5 цифр:
^(?=(\D*\d){5}\D*$)
Это регулярное выражение соответствует строкам, содержащим одно дополнительное пространство:
^(?=[^ ]* ?[^ ]*$)
Если мы поместим их вместе, а также убедитесь, что строка содержит только цифры и пробелы ([\d ]*$
), мы получаем:
^(?=(\D*\d){5}\D*$)(?=[^ ]* ?[^ ]*$)[\d ]*$
Вы также можете использовать [\d ]{5,6}
вместо [\d ]*
в конце этого шаблона с тем же эффектом.
Демо
Объяснение:
Это регулярное выражение использует lookaheads. Это шаблоны шаблонов с нулевой шириной, что означает, что обе части шаблона привязаны к началу строки.
-
\d
означает "любая цифра", а \d
означает "любая цифра".
-
означает "пробел", а [^ ]
означает "любое не-пространство".
-
\D*\d
повторяется 5 раз, чтобы в строке было ровно 5 цифр.
Вот визуализация регулярного выражения в действии:
![визуализация regex]()
Обратите внимание: если вы действительно хотели, чтобы "дополнительное пространство" включало такие вещи, как вкладки, вы могли вместо этого использовать \s
и \s
.
Обновление:. Поскольку этот вопрос, похоже, приобрел немалую тягу, я хотел прояснить что-то об этом ответе.
Есть несколько "более простых" вариантов решения моего ответа выше, например:
// Only look for digits and spaces, not "non-digits" and "non-spaces":
^(?=( ?\d){5} *$)(?=\d* ?\d*$)
// Like above, but also simplifying the second lookahead:
^(?=( ?\d){5} *$)\d* ?\d*
// Or even splitting it into two, simpler, problems with an "or" operator:
^(?:\d{5}|(?=\d* \d*$).{6})$
Демонстрации каждой строки выше: 1 2 3
Или даже если мы можем предположить, что строка не более 6 символов, тогда даже этого достаточно:
^(?:\d{5}|\d* \d*)$
Итак, имея в виду, почему вы хотите использовать оригинальное решение для подобных проблем? Потому что он общий. Посмотрите еще раз на мой первоначальный ответ, переписанный с помощью свободного пробега:
^
(?=(\D*\d){5}\D*$) # Must contain exactly 5 digits
(?=[^ ]* ?[^ ]*$) # Must contain 0 or 1 spaces
[\d ]*$ # Must contain ONLY digits and spaces
Эта схема использования последовательных перспектив может использоваться в различных сценариях, чтобы писать шаблоны, которые являются высокоструктурированными и (возможно, удивительно) легко расширяемыми.
Например, предположим, что правила изменились, и теперь вы хотите совместить 2-3 пробела, 1 .
и любое количество дефис. На самом деле очень просто обновить регулярное выражение:
^
(?=(\D*\d){5}\D*$) # Must contain exactly 5 digits
(?=([^ ]* ){2,3}[^ ]*$) # Must contain 2 or 3 spaces
(?=[^.]*\.[^.]*$) # Must contain 1 period
[\d .-]*$ # Must contain ONLY digits, spaces, periods and hyphens
... Итак, в общем, существуют "более простые" решения регулярных выражений и, возможно, лучшее решение без регулярных выражений для конкретной задачи OP. Но то, что я предоставил, является универсальным, расширяемым шаблоном проектирования для сопоставления шаблонов такого характера.
Ответ 2
Я предлагаю сначала проверить ровно пять чисел ^\d{5}$
ИЛИ смотреть вперед для одного пробела между цифрами ^(?=\d* \d*$)
среди шести символов .{6}$
.
Объединяя эти частичные выражения, получаем ^\d{5}$|^(?=\d* \d*$).{6}$
:
let regex = /^\d{5}$|^(?=\d* \d*$).{6}$/;
console.log(regex.test('00000')); // true
console.log(regex.test(' 00000')); // true
console.log(regex.test('00000 ')); // true
console.log(regex.test('00 000')); // true
console.log(regex.test(' 00000')); // false
console.log(regex.test('00000 ')); // false
console.log(regex.test('00 000')); // false
console.log(regex.test('00 0 00')); // false
console.log(regex.test('000 000')); // false
console.log(regex.test('0000')); // false
console.log(regex.test('000000')); // false
console.log(regex.test('000 0')); // false
console.log(regex.test('000 0x')); // false
console.log(regex.test('0000x0')); // false
console.log(regex.test('x00000')); // false
Ответ 3
Это кажется мне более интуитивным и является O (n)
function isInputValid(input) {
const length = input.length;
if (length != 5 && length != 6) {
return false;
}
let spaceSeen = false;
let digitsSeen = 0;
for (let character of input) {
if (character === ' ') {
if (spaceSeen) {
return false;
}
spaceSeen = true;
}
else if (/^\d$/.test(character)) {
digitsSeen++;
}
else {
return false;
}
}
return digitsSeen == 5;
}
Ответ 4
Вы можете разбить его пополам:
var input = '0000 ';
if(/^[^ ]* [^ ]*$/.test(input) && /^\d{5,6}$/.test(input.replace(/ /, '')))
console.log('Match');
Ответ 5
Здесь простое регулярное выражение для выполнения задания:
^(?=[\d ]{5,6}$)\d*\s?\d*$
Пояснение:
^ утверждает положение в начале строки
Положительный Lookahead (? = [\ d] {5,6} $)
Утвердите, что Regex ниже соответствует
Сопоставьте один символ, присутствующий в списке ниже [\ d] {5,6}
{5,6} Квантификатор - Соответствует между 5 и 6 раз, как можно больше раз, возвращая по мере необходимости (жадный)
\ d соответствует цифре (равной [0-9]) соответствует букве буквально (с учетом регистра)
$утверждает позицию в конце строки
\ d * соответствует цифре (равной [0-9])
- Квантификатор - совпадение между нулем и неограниченным временем, как можно больше раз, при необходимости, при необходимости (жадный)
\ s соответствует любому символу пробела (равному [\ r\n\t\f\v])
\ d * соответствует цифре (равной [0-9])
- Квантификатор - совпадение между нулем и неограниченным временем, как можно больше раз, при необходимости, при необходимости (жадный)
$утверждает позицию в конце строки
Ответ 6
string="12345 ";
if(string.length<=6 && string.replace(/\s/g, '').length<=5 && parseInt(string,10)){
alert("valid");
}
Вы можете просто проверить длину и, если ее действительный номер...
Ответ 7
Так я бы сделал это без регулярного выражения:
string => [...string].reduce(
([spaces,digits], char) =>
[spaces += char == ' ', digits += /\d/.test(char)],
[0,0]
).join(",") == "1,5";