はじめに
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
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 |
変更内容
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で半角スペースをパイプに直接置換したほうが早かったかもしれない...