web-dev-qa-db-ja.com

正確に5つの数字と1つのオプションのスペースに一致する正規表現

最近、JavaScriptで入力をチェックするための正規表現を作成する必要がありました。入力は5文字または6文字の長さにすることができ、正確に5つの数字と1つのオプションのスペースを含める必要がありました。私はまったく正規表現に精通していません。より良い方法を探してみましたが、これで終わりました:

(^\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 '

私はこれが正規表現とそのようなマッチングを達成する唯一の方法であるとは思いませんが、よりクリーンな方法でそれを行う方法を見つけていません。だから私の質問は、これをどのように改善することができますか?

ありがとうございました。

編集:
それで、可能です! Tom Lordの答えは正規表現で必要なことを行うので、質問に対する正しい答えとしてマークしました。

しかし、この質問を投稿した直後に、プロジェクトの他のすべての入力が正規表現で簡単に「検証可能」であるため、私は正しく考えていないことに気付きました。

私はちょうどこれを行うことができたことがわかります:

const validate = function(value) {
    const v = value.replace(/\s/g, '')
    const regex = new RegExp('^\\d{5}$');
    return regex.test(v);
}  

クールな回答とアイデアをありがとうございました! :)

Edit2:入力が制限されているため、ユーザーが最大6文字しか入力できないという、非常に重要な詳細について言及するのを忘れました。謝罪いたします。

19
EyfI

注:この問題を解決するために正規表現を使用することは最良の答えではないかもしれません。 以下で回答するように 、単純な関数で数字とスペースを数える方が簡単かもしれません!

ただし、質問は正規表現の答えを求めていたため、一部のシナリオでは、forcedで正規表現でこれを解決することができます(たとえば、特定のライブラリの実装)、次の回答が役立つ場合があります:

この正規表現は、正確に5桁を含む行に一致します。

^(?=(\D*\d){5}\D*$)

この正規表現は、1つのオプションのスペースを含む行に一致します。

^(?=[^ ]* ?[^ ]*$)

それらをまとめてにして、文字列にonly数字とスペース[\d ]*$)、次のようになります:

^(?=(\D*\d){5}\D*$)(?=[^ ]* ?[^ ]*$)[\d ]*$

同じ効果を得るために、そのパターンの最後で[\d ]{5,6}の代わりに[\d ]*を使用することもできます。

Demo

説明:

この正規表現は lookaheads を使用しています。これらは、幅がゼロのパターンマッチャーです。つまり、パターンのboth部分は、文字列の先頭に「固定」されます。

  • \dは「任意の数字」を意味し、\Dは「任意の非数字」を意味します。

  • は「スペース」を意味し、[^ ]は「任意の非スペース」を意味します。

  • \D*\dは5回繰り返され、文字列に正確に5桁が含まれるようにします。

以下は、実行中の正規表現の視覚化です。

regex visualisation

実際に「オプションスペース」にタブなどを含める場合は、代わりに\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})$

上記の各行のデモ: 12

あるいは、assumeストリングがもうないこともできる場合6文字よりも短い場合、これでも十分です:

^(?:\d{5}|\d* \d*)$

それを念頭に置いて、なぜmight同様の問題に対して元のソリューションを使用したいのですか?それは、genericだからです。 free-spacing で書き直された元の答えをもう一度見てください:

^
(?=(\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の特定の問題に対するより良い非正規表現ソリューションである可能性が非常に高いです。しかし、私が提供したのは、この性質のパターンに一致するための一般的で拡張可能なデザインパターンです。

19
Tom Lord

最初に、正確に5つの数字をチェックすることをお勧めします_^\d{5}$_ OR 6文字の_.{6}$_の間で数字^(?=\d* \d*$)の間のスペースを1つ探します。

これらの部分式を組み合わせると、^\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_

または、次のように部分式を個別に照合します:

_/^\d{5}$/.test(input) || input.length == 6 && /^\d* \d*$/.test(input)
_
8
le_m

これは私にとってより直感的で、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;
}
7
user3099140

これを行う簡単な正規表現を次に示します。

^(?=[\d ]{5,6}$)\d*\s?\d*$

説明:

^文字列の先頭の位置をアサートします

正の先読み(?= [\ d] {5,6} $)

以下の正規表現が一致することをアサートする

[\ d] {5,6}の下のリストにある単一の文字に一致します

{5,6}量指定子— 5〜6回、可能な限り多くの回数一致し、必要に応じて返します(貪欲)

\ dは数字と一致し([0-9]と等しい)文字と文字通り一致します(大文字と小文字が区別されます)

$は、文字列の末尾の位置をアサートします\ d *は数字と一致します([0-9]と等しい)

  • 量指定子—ゼロ回から無制限の回数で、可能な限り何度でも一致し、必要に応じて返します(貪欲)

\ sは任意の空白文字に一致します([\ r\n\t\f\vと等しい)

\ d *は数字と一致します([0-9]と等しい)

  • 量指定子—ゼロ回から無制限の回数で、可能な限り何度でも一致し、必要に応じて返します(貪欲)

$は、文字列の最後の位置を表明します

1
John Smith

半分に分割できます:

var input = '0000 ';

if(/^[^ ]* [^ ]*$/.test(input) && /^\d{5,6}$/.test(input.replace(/ /, '')))
  console.log('Match');
1
Thomas Ayoub
string="12345 ";
if(string.length<=6 && string.replace(/\s/g, '').length<=5 && parseInt(string,10)){
  alert("valid");
}

あなたは単純に長さをチェックすることができ、その有効な数字なら...

0
Jonas Wilms

これは正規表現なしでそれを行う方法です:

string => [...string].reduce(
    ([spaces,digits], char) =>
        [spaces += char == ' ', digits += /\d/.test(char)],
    [0,0]
).join(",") == "1,5";
0
corvus_192