質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.64%

引数のオプションの入力チェック関数

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 1,393

miu_ras

score 694

引数のオプションの値の入力チェックの関数の実装の話です。

絶対条件
・オプションは文字列で指定される
・オプションはなくてもいい(長さ0バイトの空文字)
・abcABCだけで構成されている
・順は問わない

OK例
・""
・"a"
・"aBc"
・"bac"

NG例
・"abcd"

上記の条件を満たす関数はすぐに出来ました。

function checkOption(o) {
    return /^[abcABC]*$/.test(o);
}

ここで、さらに
「同じ文字の複数回の登場は許可しない」という制約を追加したいのですが、一見簡単そうなことなのに手が止まってしまいました。

NG
・"aba"

正規表現で1行でシンプルに書くことは出来ませんかね。仮に出来なくとも、複数行でも正規表現でなくともいいので、出来るだけシンプルスマートな方法を探しています。これを教えてください。

よろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

0

「引数が String 型でない時」の条件が抜けていますが、「String 型に変換して評価する」でいいのでしょうか。
自己解決されたコードでもいいと思いますが、文字数もチェックすると長大な文字列を判定するときの結果が早く出そうですね。

'use strict';
function checkAbc (string) {
  return /^[abcABC]{0,6}$/.test(string) && !/([abcABC])[abcABC]*\1/.test(string);
}

console.log(checkAbc(''));        // true
console.log(checkAbc('aBc'));     // true
console.log(checkAbc('BaCAbc'));  // true
console.log(checkAbc('aA'));      // true
console.log(checkAbc('aa'));      // false

スマートなコードとなると汎用性が高いコードだと個人的には考えていますが、いろいろと書き方があります。
コードが長くても汎用性の高いコードは美しいと思います。

'use strict';
var checkString1 = (function (String, RegExp){
  return function checkString1 (characterClass, string) {
    var l;

    characterClass = String(characterClass);
    string = String(string);
    l = characterClass.length;

    if (string.length > l) {
      return false;
    }

    characterClass = '[' + characterClass.replace(/(?=\W)/g, '\\') + ']';

    return new RegExp('^' + characterClass + '{0,' + l + '}$').test(string) && !(new RegExp('(' + characterClass + ')' + characterClass + '*\\1').test(string));
  };
}(String, RegExp));

var checkString2 = (function (String, RegExp){
  return function checkString2 (characterClass, string) {
    var cl, l, i, char;

    characterClass = String(characterClass);
    string = String(string);
    cl = characterClass.length;
    l = string.length;

    if (l > cl) {
      return false;
    }

    i = 0;

    while (i < l) {
      char = string[i++];

      if (characterClass.indexOf(char) === -1) {
        return false;
      }

      characterClass = characterClass.replace(new RegExp(char.replace(/(?=\W)/, '\\'), 'g'), '');
    }

    return true;
  };
}(String, RegExp));

console.log(checkString1('abcABC', ''));        // true
console.log(checkString1('abcABC', 'aBc'));     // true
console.log(checkString1('abcABC', 'BaCAbc'));  // true
console.log(checkString1('abcABC', 'aA'));      // true
console.log(checkString1('abcABC', 'aa'));      // false

console.log(checkString2('abcABC', ''));        // true
console.log(checkString2('abcABC', 'aBc'));     // true
console.log(checkString2('abcABC', 'BaCAbc'));  // true
console.log(checkString2('abcABC', 'aA'));      // true
console.log(checkString2('abcABC', 'aa'));      // false

Re: miu_ras さん

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/01/24 18:46 編集

    長さ制限をするのはいいですね。参考にします。
    ありがとうございました

    後半のコードは私は苦手です。
    引数で汎用的にするにしても、私の場合はここまでですね。

    function checkOption(o, v) {
      var reg = new RegExp("^[" + o + "]{0," + o.length + "}$");
      return reg.test(v) && !/(.).*\1/.test(v);
    }

    function checkOption(opts, v) {
      var REG_BODY = "^[【opts】]{0,【len】}$";
      var reg = new RegExp(REG_BODY.replace("【opts】", opts).replace("【len】", o.length));
      return reg.test(v) && !/(.).*\1/.test(v);
    }

    キャンセル

  • 2016/01/25 09:45

    その書き方ですと、「引数の型の想定」と「正規表現判定」が不十分な為に期待通りの結果を返さないケースがあります。
    「引数が String 型でない時」の条件が抜けてるト言ったのはそういう理由です。TypeError を返す設計もありえます。

    function checkOption(o, v) {
      var reg = new RegExp("^[" + o + "]{0," + o.length + "}$");
      return reg.test(v) && !/(.).*\1/.test(v);
    }
    // 引数が String 型ではない場合
    console.log(checkOption([1,2], '1,2')); // false
    console.log(checkOption({}, '[object Object]')); // false
    // 引数が改行コードを含む場合
    console.log(checkOption('abc\n', 'a\na')); // true
    // 引数が正規表現メタキャラクタを含む場合
    console.log(checkOption('[]abc', '[]abc')); // false
    console.log(checkOption('abc\\', 'abc\\')); // SyntaxError: Invalid regular expression: /^[abc\]{0,4}$/: Unterminated character class

    キャンセル

0

あれ?単純にこれでいいのかな…。

function checkOption(o) {
    return /^[abcABC]*$/.test(o) && !/(.).*\1/.test(o);
}


もしもっといい方法があったら、それを教えてくださいよろしくお願いします。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.64%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる