2017/09/04

テキストボックスの入力除外リスト機能を作ってみた。

その言葉は使わせない!

今回はテキストボックスに入力した文字列の中身を照合して、
使用していいのか判定して、表示みたいと思います。

それでは本編です。

目次

目標

テキストボックスの中身を照合して使用していいか判定してみよう!
そして高速化してみよう!!

サンプルコード1

test015.html

<!DOCTYPE html>
<html>
  <head>
    <meta content="IE=edge"
          http-equiv="X-UA-Compatible" />
    <link href="./test015css.css"
          rel="stylesheet"
          type="text/css" />
    <title>Selecters</title>
    <script type="text/javascript">
        var list =
        "__6kh4zd",
        "_0hmo8qv",
        "_0l20t5a",
        "_0tusswy",
        "_0y1v855",
        ~~省略~~
        "zu522mgt",
        "zvq7thq5",
        "zydbox68"
        ];
   
      var flag = true;
     
      function matchchack(targettextid,statusid,resultid){
        if(flag){

          flag=false;         
         
          var target = document.getElementById(targettextid);
          var status = document.getElementById(statusid);
          var result = document.getElementById(resultid);
         
          var counter = 0;

          status.innerHTML="検索中";         
         
          //コールバック関数定義
          var collback = function(){ 
            document.getElementById("vi").innerHTML
              = list[counter]+":"+counter+"<br>";         
            if(document.getElementById(targettextid).value
              == list[counter]){
              result.innerHTML="この入力は使えません";
            }
            else
              //コールバックでのループ処理
              if(counter<list.length){
                counter+=1;
                setTimeout(collback,0);
                return 0;
              }
              else{
                result.innerHTML="使用可能です。";
              }
            }
            flag=true;
            //フォーカスが当たっているときには再度処理実施
            if(document.activeElement.id
               == targettextid){
              matchchack(targettextid,statusid,resultid);
              return 0
            }
            status.innerHTML="";                       
          }

          setTimeout(collback,1);
        }
      }
    </script>
  </head>
  <body>
    <div class="container">
      <main>
        <input type="text" id="searchtext"
        onfocus="matchchack('searchtext','status','result');">
        <div id="status"></div>
        <div id="result"></div>
        <div id="vi"></div>  
      </main>
    </div>
  </body>
</html>

実行例-表示例

テクストボックスにフォーカスが当たると検索を開始します。 リストに一致した文字列があると「この入力は使えません」と表示し、 一致するものが無いと「使用可能です」と表示します。

ポイント!

  • ループ処理はforやwhileで書かない!
    入力に関する処理の中でforやwhileを検索などに使うとその処理中は入力ができなくなる。
    なので、ループ処理をコールバック関数で実現する。[matchchack関数の中のcollback関数]
  • 関数入口でフラグ処理
    多重に実行されては困るので、関数処理の1行目でフラグ処理を行い、多重実行されないようにする。 [matchchack関数冒頭]

一休み

これで検索処理ができました。

しかし結果が出るまでが若干時間がかかりすぎている気がします・・・。
今1000件の検索をしているけどタイミング次第で5秒以上かかってしまう。
というのも、検索処理は文字列を昇順で並べて、0番目から末尾まで線形探索しているからです。
aから始まるものは検索が早く終わるし、zで始まるものは時間がかかってしまします。

次では少しく工夫して検索処理を高速化してみます。

サンプルコード2

test015-index-metadata.html

<!DOCTYPE html>
<html>
  <head>
    <meta content="IE=edge"
          http-equiv="X-UA-Compatible" />
    <link href="./test015css.css"
          rel="stylesheet"
          type="text/css" />
    <title>Selecters</title>
    <script type="text/javascript">
        var list = [
        "__6kh4zd",
        "_0hmo8qv",
        "_0l20t5a",
        ~~省略~~
        "zsx7_7o5",
        "zu522mgt",
        "zvq7thq5",
        "zydbox68"
        ];

        var listindex1=["_",
        "0",
        "1",
        ~~省略~~
        "w",
        "x",
        "y",
        "z"
        ];

        var listindex2=[
        [0,33],
        [34,64],
        [65,86],
        ~~省略~~
        [927,950],
        [951,970],
        [971,999]
        ];
   
      var flag = true;
      var counter = 0;
     
      function matchchack(targettextid,statusid,resultid){
        if(flag){

          flag=false;     
         
          var target = document.getElementById(targettextid);
          var status = document.getElementById(statusid);
          var result = document.getElementById(resultid);
         
          counter = 0;
          var indexkeyword = target.value.substr(0,1);
          var indexresult= listindex1.indexOf(indexkeyword);
          if(indexresult==-1){
            flag=true;
            if(document.activeElement.id == targettextid){             
              result.innerHTML="使用可能です";
              setTimeout(matchchack,1,targettextid,statusid,resultid);
              return 0
            }
          }
          else{
            var start = listindex2[indexresult][0]
            var end   = listindex2[indexresult][1]

            counter = start;

            status.innerHTML="検索中";         
         
            //コールバック関数定義
            var collback = function(){ 
              document.getElementById("vi").innerHTML
                = list[counter]+":"+counter+"<br>";         
              if(document.getElementById(targettextid).value
                == list[counter]){
                  result.innerHTML="この入力は使えません";
              }
              else
                //コールバックでのループ処理
                if(counter<list.length && counter<end){
                  counter+=1;
                  setTimeout(collback,0);
                  return 0;
                }
                else{
                  result.innerHTML="使用可能です";
                }
              }
              flag=true;
              //フォーカスが当たっているときには再度処理実施
              if(document.activeElement.id == targettextid){

                setTimeout(matchchack,0,targettextid,statusid,resultid);
                return 0
              }
              status.innerHTML="";
            }
            //コールバック定義終わり

            setTimeout(collback,0);
          }
        }
      }
    </script>
  </head>
  <body>
    <div class="container">
      <main>
        <input type="text" id="searchtext"
        onfocus="matchchack('searchtext','status','result');">
        <div id="status"></div>
        <div id="result"></div>
        <div id="vi"></div>  
      </main>
    </div>
  </body>
</html>

実行例-表示例2

実行例-表示例1と同じ文字列を検索してみます。
明らかに実行例-表示例1よりも検索結果が素早く表示される。

ポイント2

  • 入力が空欄の場合は待機処理
  • 検索対象の配列のメタデータを使う
    検索対象を効率良く探索するために、
    1. 検索対象の文字列の1文字目リスト
    2. 検索対象のX個目からY個目までがどの1文字目で始まるかというリスト
    の二つのデータを使う。
    このデータで検索対象を1000個の内で、aで始まるものや、
    zで始まるものだけに検索対象を絞ることができる。
    一様に文字列の1文字目がアルファベット26文字に分散するならば,
    検索時間は1/26以下にできるはず。

終わりに

今回は文字列の検索処理を作ってみました。
検索処理を2分探索にするとか、aが1文字目に多い場合はaだけ2文字目までメタデータを作ってみるとか
工夫次第でもっと遊べそうです。

参考になれば幸いです。
ご使用は自己責任で。

以上。

0 件のコメント:

コメントを投稿

AWSに手を出してフレームワークも使ってみたが・・・。

サイトを作り直しました。 AWS上に構築した Content created by AXY を作り直しました。 具体的にはbottle.pyを使ったpythonで構築したサイトからPHP7を使用したサイトに再構築しています。 特別何か問題点があったというわけで...