Подтвердить что ты не робот

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 символов. Мои извинения.

4b9b3361

Ответ 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";