0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Grid.jsの検索をOR検索に対応させる方法

Posted at

はじめに

Javascriptで表を表示するためにGrid.jsを使用していたが,標準仕様の検索ではOR検索に対応していない.
複数のキーワードを半角スペースで区切って入力することで,それらすべての単語を含む検索に対応させることにした.

動作環境

  • Windows10
  • VisualStudioCode v1.74.2
  • Node.js v18.12.1
  • npm v8.19.2
  • Typescript v4.9.4

やったこと

ソースコードの取得

GitHubよりGrid.jsのソースコードを取得

変更するソースファイルの確認

変更するソースは/src/operator/search.ts

/src/operator/search.ts
import Tabular from '../tabular';
import { VNode } from 'preact';
import { HTMLContentProps } from '../view/htmlElement';
import { OneDArray, TCell, TColumn } from '../types';

export default function (
  keyword: string,
  columns: OneDArray<TColumn>,
  ignoreHiddenColumns: boolean,
  tabular: Tabular,
  selector?: (cell: TCell, rowIndex: number, cellIndex: number) => string,
): Tabular {
  // escape special regex chars
  keyword = keyword.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');

  return new Tabular(
        // 中略
        return new RegExp(keyword, 'gi').test(data);
      }),
    ),
  );
}

どうやら,正規表現RegExpに変数keywordで文字列を渡し,dataの中身に一致すればTrueを返すような仕組みで検索結果を判断しているらしい.
このkeywordで書かれた引数をor検索に対応させた文字列にすればうまくできそう...

対応方針

正規表現でのorは各キーワードをパイプ( | )で区切ればよいので,keywordとして渡っている変数をパイプで区切り,RegExpの引数として渡すことにする.

正規表現 意味
AAA|BBB AAAまたはBBB

変更内容

/src/operater/search.ts(変更後)
export default function (
  keyword: string,
  columns: OneDArray<TColumn>,
  ignoreHiddenColumns: boolean,
  tabular: Tabular,
  selector?: (cell: TCell, rowIndex: number, cellIndex: number) => string,
): Tabular {
  // ---変更箇所ここから ---
  keyword = keyword.replace(/[-[\]{}()*+?.,\\^$|#]/g, '\\$&');    
  while (keyword.indexOf('  ') !== -1) {
    keyword = keyword.replace('  ',' ');
  };
  let sp_key = keyword.split(' ');
  // ---変更箇所ここまで ---

  return new Tabular(
        // 省略
          data = String(cell.data);
        }
        
        // ---変更箇所ここから---
        return new RegExp(sp_key.join('|'), 'gi').test(data);
        // ---変更箇所ここまで ---
      }),
    ),
  );
}

変更内容の説明

オリジナル版ではkeywordに特殊文字が含まれていた場合,エスケープ用のバックスラッシュが挿入されるようになっていた.今回の変更では半角スペースの前にエスケープは不要なため,replace処理から半角スペース(\s)を除外する.

-  keyword = keyword.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
+  keyword = keyword.replace(/[-[\]{}()*+?.,\\^$|#]/g, '\\$&');    

while文を用いて,半角スペースが連続した場合に1つに変換する処理を追加した.半角スペース2個を1個に変換し,半角スペースが2連続している場所をindexOf関数で検索,該当箇所がない時にループを抜けるようにした.

  // 半角スペース2個がkeywordの中にあるか判定(なければ-1を返す)
  while (keyword.indexOf('  ') !== -1) { 
    // 半角スペース2個を半角スペース1個に置換
    keyword = keyword.replace('  ',' ');
  };

最後に,splitに半角スペースを指定することで,文字列keywordを文字列配列sp_keyに分割した.

  // 半角スペースで文字列を分割
  let sp_key = keyword.split(' ');

sp_keyのjoinメソッドにパイプを指定することで,文字列配列sp_keyをパイプ(|)で区切った文字列に変換し,RegExpの引数として渡す.

  return new Tabular(
        // 省略
          data = String(cell.data);
        }       
-        return new RegExp(keyword, 'gi').test(data);
+        return new RegExp(sp_key.join('|'), 'gi').test(data);
      }),
    ),
  );
}

動作確認

変更したsearch.tsを含むjsファイルをコンパイルして作成する.
コンパイルにはnpmを利用する.
ターミナルのカレントディレクトリにpackage.jsonのあるフォルダを指定し,以下を実行

ターミナル
npm run build:grid

これにより,/distフォルダ下にjsファイルが作成されるため,自分が使用したいjsファイルを呼び出す.

終わりに

初めてのJavascript,Typescriptでソースコードを読み解くのに手間取ったが,なんとか所望の処理を達成できて満足である.

今見返してみると,splitで配列に分割しなくてもreplaceで半角スペースをパイプに直接置換したほうが早かったかもしれない...

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?