【JavaScript(HTML)】対応するカッコが正しく入力されているか検証(チェック)する方法【テストツール】

JavaScript

はじめに

このカッコに対応するカッコは正しく入力されているのか。。

対応するカッコがない場合に強調表示することで誤入力を防げるため、対応するカッコが正しく入力されているか検証(チェック)するJavaScript(HTML)を作りました。

対応するカッコがない場合は赤で表示

対応するカッコを強調表示するデモ

対応するカッコを強調表示するデモです。

以下テキストエリアのカッコ消したり追加したりすると対応するカッコがないカッコへ色を付けて表示します。

【テキストエリア】
{“id”: 111, “products”: [ { “name”: “Coffee”, “quantity”: 1 } ] }

実装方法

テキストエリア内で対応するカッコが正しく入力されているか検証(チェック)するJavaScript(HTML)を実装します。

以下のソースをコピーしテキストエディタへ貼付け、保存してください。(ファイル名は任意、拡張子は.html)

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>【JavaScript(HTML)】テキストエリア内の対応するカッコを確認(検証)する方法【テストツール】</title>
    <!-- こちらのjqueryはバージョンアップ等、適宜変更してください -->
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script> 
  </head>
  <body>
    【テキストエリア】<BR>
    <textarea id="req_text" cols=120 rows=10>
{"id": 111,
  "products": [
                {
                  "name": "Coffee",
                  "quantity": 1
                }
              ]
}
</textarea>
    <div id="req_overlay" cols=120 rows=10>
{"id": 111,
  "products": [
                {
                  "name": "Coffee",
                  "quantity": 1
                }
              ]
}
    </div>
  </body>
</html>
<script type="text/javascript">
const textElem    = document.querySelector('#req_text');
const overlayArea = document.querySelector('#req_overlay');

//keyup時処理
textElem.addEventListener('keyup', (event) => {
  var txt = '\n' + event.target.value + '\n';
  txt= bracketCheck(txt);
  overlayArea.innerHTML = txt;
});

//click時処理
textElem.addEventListener('click', (event) => {
  var txt = '\n' + event.target.value + '\n';
  txt= bracketCheck(txt);
  overlayArea.innerHTML = txt;
});

//対応カッコ検証
function bracketCheck(text) {
    let txtArr = text.split('');
    let bct = bracketPut(text);
    for (let i = 0; i < bct.length; ++i) {
        if(bct[i][1] === ""){
            txtArr[bct[i][0]] = `<span class='bracketNg'>` + txtArr[bct[i][0]] + `</span>`;
        }
    }
    return txtArr.join("");
}

//カッコ格納
function bracketPut(text) {
    let putArr = [];
    let txtArr = text.split('');
    let bCnt = 0;
    for (let i = 0; i < txtArr.length; ++i) {
        switch (txtArr[i]) {
            case "{" :
                putArr.push([i,""]);
                break;
            case "}" :
                putArr.push([i,""]);
                var inx = bracketFind(putArr,putArr.length - 1);
                if (txtArr[inx[0]] == "{") {
                    putArr[inx[1]][1] = bCnt;
                    putArr[putArr.length - 1][1] = bCnt;
                    bCnt = bCnt + 1;
                }
                break;
            case "[" :
                putArr.push([i,""]);
                break;
            case "]" :
                putArr.push([i,""]);
                var inx = bracketFind(putArr,putArr.length - 1);
                if (txtArr[inx[0]] == "[") {
                    putArr[inx[1]][1] = bCnt;
                    putArr[putArr.length - 1][1] = bCnt;
                    bCnt = bCnt + 1;
                }
                break;
        }
    }
    return putArr;
}

//カッコindex検索
function bracketFind(arr,num) {
    for (let i = num; i--;) {
        if (arr[i][1] === ""){
            return [arr[i][0],i]
        }
    }
    return [-1,-1];
}

//テキストエリアサイズ変更対応
document.addEventListener('DOMContentLoaded', () => {
  const observer = new MutationObserver(() => {
    const width  = textElem.getBoundingClientRect().width
    const height = textElem.getBoundingClientRect().height
    overlayArea.style.width  = width + "px";
    overlayArea.style.height = height + "px";
  })
  observer.observe(textElem, {
    attriblutes: true,
    attributeFilter: ["style"]
  })
}, false)

//テキストエリア改行対応
$('#req_text').scroll(function() {
  var t = $(this).scrollTop();
  var l = $(this).scrollLeft();
  $('#req_overlay').scrollTop(t);
  $('#req_overlay').scrollLeft(l);
});
</script>
<style>
#req_text {
    background-color: transparent;
    padding: 13px 12px;
    position: absolute;
    overflow-wrap: break-word;
    margin: 2px;
    white-space: pre-wrap;
    font-family: monospace;
    font-size: 14px;
    width: 800px;
    height: 150px;
}
#req_overlay {
    color: #e2e2e2;
    padding: 1px 12px;
    overflow: hidden;
    overflow-wrap: break-word;
    margin: 2px;
    white-space: pre-wrap;
    font-family: monospace;
    font-size: 14px;
    width: 800px;
    height: 150px;
}
#req_overlay span.bracketNg {
  background: linear-gradient(transparent 0, #FF0000 0);
}
</style>

テキストエリアのサイズや位置は必要に応じて微調整してください。

※70-84行目:case “{” : ~中略~ break; の「{}」の部分を追加変更することで、「()」など別の文字括りにも対応できます。

便利な入力補助機能

テキストエリアへJSONデータを入力する際の入力補助機能を以下の記事で紹介しています。

解説

テキストエリアの下へdivタグを重ねています。

keyup・click時に、JavaScriptで対応するカッコが存在しないカッコをspanタグへ入れ、他の文字も含めてdivタグへ入れてます。

対応するカッコが存在しないカッコのspanタグへは、背景色付きのclassが設定されています。

対応するカッコの見分け方は、テキスト中のカッコを全て配列へ入れ、以下のようにカッコそれぞれの位置、グループを付けて検証しています。

index:147の「]」を削除した場合、配列は以下のように変わります。

青いカッコは対応するカッコがあるのでグループとして認識していますが、それ以外のカッコは対応するカッコがないためグループとならず、エラーとして強調表示します。

まとめ

対応するカッコ(括弧)が不足または誤って配置されている場合、さまざまな問題が起こり得ます。

  1. 構文エラー: カッコが正しく配置されていない場合、プログラムは構文エラーを発生させます。これはコンパイラまたはインタプリタによって検出され、プログラムの実行が中断されます。
  2. 予期しない動作: カッコが正しく配置されていない場合、プログラムの制御フローが意図しない方法で変更される可能性があります。これにより、予期しない動作が発生し、バグやエラーが発生します。
  3. メモリリーク: カッコが正しく閉じられない場合、メモリリークの原因となる可能性があります。特に、動的メモリ割り当てが関与する場合、メモリが解放されずにプログラムのメモリ使用量が増加することがあります。
  4. スタックオーバーフロー: 再帰関数を使用する場合、適切な再帰の終了条件がないと、プログラムが無限に再帰呼び出しを行うことがあり、スタックオーバーフローが発生する可能性があります。
  5. データの破損: カッコが不足または誤って配置された場合、データの整合性が損なわれる可能性があります。これは、ファイルの書き込みや読み取り時に特に問題となります。
  6. エラーメッセージの難読化: エラーメッセージは通常、カッコの不一致を指摘するものですが、正確な位置を特定することが難しい場合があります。これにより、デバッグが困難になります。
  7. コードの可読性の低下: カッコが正しく配置されていないコードは、他のプログラマーにとって理解が難しく、可読性が低下します。コードが読みにくいと、保守性が低下し、バグの発見と修正が難しくなります。
  8. セキュリティリスク: カッコの不適切な使用は、セキュリティの問題を引き起こす可能性があります。例えば、インジェクション攻撃(SQLインジェクション、クロスサイトスクリプティングなど)は、カッコの不適切な使用が原因となることがあります。

要するに、カッコの不足や誤った配置は、プログラムの正確性、安全性、可読性、保守性に影響を与える可能性があります。コードの品質を高めるために、適切なカッコの使用とエラーチェックが重要です。対応するカッコ検証ツールは、構文エラーを検出しやすくするために役立つツールです。

コメント

タイトルとURLをコピーしました