Javascriptファジーな解答の
正否を判定
Fuzy(ファジィ、あいまい)な解答も
正しく判定するプログラム

image: Javascriptファジーな解答の正否を判定
Toplabo
Levenshtein Distance

「お母さん」も「ママ」もOKにする文字列判定法

 | 2025/06/30

はじ めに

javascriptで高度なあいまい判定を開発する
  • プログラムにゆるさを導入

    たとえば、クイズなどで、ユーザーの解答は、必ずしも「模範解答」とは限りません。
    そのクイズの答えが「母親」だったとして、ユーザーが「おかあさん」と答えた場合、「おかあさん」、「母親」は意味は同じでも文字列としては違います。もしも判定プログラムが単純な等価演算式だった場合、意味としては正解なのに答えと文字列が違うため不正解と判定してしまうでしょう。
    これでは正しい判定プログラムとは言えません。
    ではどうやってプログラム(今回はJavaScript)で正しい判定をするか?
    次のブロックからは算数のような「厳密一致」に頼らず、ゆるくても賢い判定をする考え方を紹介します。

方法

あいまいな入力を許容する文字列マッチ術
  • 厳密一致と簡易的なファジー判定

    例えばクイズの答えが「母」の場合、「母親、おかあさん、ママ」など予想できるいくつかの解答文字列を用意して、
    ユーザーの解答と順番に比較していけば、ある程度のゆるさを許容する正解判定が可能です。
    しかし用意した答えと一文字でも違えば、例えば「おかーさん」などは間違いと判定されます。
    つまり、単純な文字列同士の等値演算ではユーザーの解答の真意をくみ取った判定が難しいことになります。

    /* 解答マップにユーザーの答えがある場合 */
    const synonyms = ["母親", "お母さん", "ママ", "母", "おかあさん"];
    const userInput = "ママ";
    if (synonyms.includes(userInput)) {
      console.log("正解!");
    } else {
      console.log("不正解!");
    }
    
    /* 解答マップにユーザーの答えがない場合 */
    const synonyms = ["母親", "お母さん", "ママ", "母", "おかあさん"];
    const userInput = "おかーさん";
    if (synonyms.includes(userInput)) {
      console.log("正解!");
    } else {
      console.log("不正解!");
    もう少し柔軟に!類似度で判定してみる

    たとえば「おかあさん」「お母さん」「おかーさん」…これらはすべて意味は同じですが、文字列としては一致しません。
    そこで使えるのが「Levenshtein距離(レーベンシュタイン距離、編集距離)」です。
    これは、2つの文字列の違いを「何回の編集で一致させられるか?」という視点で測るアルゴリズムです。

    ・「ママ」と「まま」 → 距離 1(1文字の置換)
    ・「お母さん」と「おかあさん」 → 距離 1(1文字の変換)
    ・「おかあさん」と「おかーさん」 → 距離 1(1文字の置換)

    距離が0に近いほど、よく似た文字列ということになります。
    これを使って、「●文字までの違いなら正解とみなす」といった処理ができます。

    /*Levenshtein距離(編集距離)を使う例*/
    
    function levenshtein(a, b) {
      const dp = Array.from({ length: a.length + 1 }, (_, i) =>
        Array(b.length + 1).fill(0)
      );
    
      for (let i = 0; i <= a.length; i++) dp[i][0] = i;
      for (let j = 0; j <= b.length; j++) dp[0][j] = j;
    
      for (let i = 1; i <= a.length; i++) {
        for (let j = 1; j <= b.length; j++) {
          dp[i][j] = a[i - 1] === b[j - 1]
            ? dp[i - 1][j - 1]
            : Math.min(
                dp[i - 1][j] + 1,
                dp[i][j - 1] + 1,
                dp[i - 1][j - 1] + 1
              );
        }
      }
    
      return dp[a.length][b.length];
    }
    
    // 類似度を元に許容判定
    function isFuzzyMatch(input, list, maxDistance = 2) {
      return list.some(word => levenshtein(input, word) <= maxDistance);
    }
    
    const synonyms = ["母親", "お母さん", "ママ", "母", "おかあさん"];
    const userInput = "おかーさん";
    
    if (isFuzzyMatch(userInput, synonyms)) {
      console.log("正解!");
    } else {
      console.log("不正解!");
    }
    
    簡単な解説

    maxDistance = 1 のように設定することで、「少しの違い(1回の編集)」までを許容できます。
    編集距離の閾値を 2 にするとさらにゆるく、「タイプミス」程度もカバーできます。
    完全一致と違い、柔軟に“だいたい合ってる”入力を拾うことができます。

    Levenshtein距離の面白いポイント

    ”正解っぽいけど違う”を、数字でスコア化できる。
    これはAIや自然言語処理の基礎にも使われるアルゴリズム。
    検索機能・予測変換・スペルチェック・クイズ判定など応用先が広い。
    また、ユーザー入力を感じを全部ひらがなに変換してから判定を行う方法などもあります。
    その他、判定だけでなく類義語辞書と組み合わせて文章の生成などにも応用ができます。
    さらにJaro-Winkler距離(ジャロウ・ウィンクラー)というアルゴリズムもあります。
    これはライブラリーを使うのでまたの機会にご紹介。

    予算があるならChatGPTを使うのが効率がいい

    予算が許せるならもちろんChatGPTを使うのが最も正確で効率がいいのは言うまでもありません。

『Javascript.ファジーな解答の正否を判定』関連のお薦め

このページで紹介しているプログラムやビジュアルなどご依頼いただければ実装を賜ります。
お問い合わせはこちら