やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

SQLite3構文 expression(glob 句)

 文字列パターン比較式。like句と違い大文字・小文字を区別するが、エスケープ文字を指定できない。

成果物

一覧

文法

'文字列' glob 'パターン'
glob('パターン', '文字列')
  • 大文字・小文字を区別する
  • NOTで反転できる

メタ文字

メタ文字 意味
? 任意の1文字
* 任意の0文字以上
[abc] a,b,cのいずれか
[a-z] azまでの文字のいずれか(ASCII文字コード範囲指定)
[^0-9] 09以外の文字のいずれか

エスケープ

 []で囲む。

  • エスケープパターン
    • [?]
    • [*]

 だが[,]文字のエスケープは不可能。よってglob[,]の字を含むテキストのマッチ判定には使えない。

パターンの冗長化

 正規表現のように字数指定はできない。たとえばよくある日付の書式を正規表現にすると以下。

\d{4}-\d{2}-\d{2}

 これをglobでやると以下のように冗長になってしまう。字数だけパターン用メタ文字を繰り返さねばならない。字数が多ければ現実的でなくなることは察しがつくだろう。

glob '[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]'

?

 ?は任意の1字を表す。

select '1A' glob '?A';
1

 大文字と小文字の区別はつける。

select '1A' glob '?A';
0

 字数が違えば偽。

select '11A' glob '?A';
0

*

 *は任意の0字以上を表す。

select 'A' glob '*A';
1
select '1A' glob '*A';
1
select '11A' glob '*A';
1
select '11A1' glob '*A';
0

前方一致

select 'abc123' glob 'abc*';
1

後方一致

select '123abc' glob '*abc';
1

部分一致

select '123abc456' glob '*abc*';
1

 ,区切りの配列内から1つの要素を検索するときは以下。

select (',' || 'abc' || ',') glob '*,abc,*';
1

 CSVの先頭や末尾ならabc,*, *,abcのパターンもある。だが上記SQL文では、両端に,を付与することで*,abc,*パターンに統一している。

メタ文字のエスケープ

[?]

 ?を文字としてマッチさせるには[?]とする。

select 'A?B' glob 'A[?]B';
select 'A!B' glob 'A[?]B';
1
0

 []で囲わなければメタ文字として解釈される。

select 'A?B' glob 'A?B';
select 'A!B' glob 'A?B';
select 'A123B' glob 'A?B';
1
1
0

[*]

 *を文字としてマッチさせるには[*]とする。

select 'A*B' glob 'A[*]B';
select 'A-B' glob 'A[*]B';
1
0

 []で囲わなければメタ文字として解釈される。

select 'A*B' glob 'A*B';
select 'A-B' glob 'A*B';
select 'A123B' glob 'A*B';
1
1
1

[?],[*]のエスケープは不可能

 [?][*]文字列にマッチさせたいときは? 不可能と思われる。globにはエスケープ文字を設定する方法がないから。

select 'A[?]B' glob 'A[?]B';
select 'A[?]B' glob 'A[[?]]B';
select 'A[?]B' glob 'A\[?]\B';
0
0
0

 つまり、glob[, ]文字を含む文字列にマッチさせることはできない。

大文字・小文字の区別

 必ずする。しないように変更することはできない。

select '1a' glob '?A';
0
select '1A' glob '?A';
1

 collate nocaseを使ってもダメ。

select '1a' collate nocase glob '?A';
select '1a' glob '?A' collate nocase;
select '1a' collate nocase glob '?A' collate nocase;
0
0
0

 以下プラグマを使ってもダメ。

PRAGMA case_sensitive_like = false;
select '1a' glob '?A';
0

 以下のようなプラグマは存在しない。

PRAGMA case_sensitive_glob = false;
select '1a' glob '?A';
0

 [a-zA-Z]を使えば1文字分だけは可能。

select '1a' glob '?[a-zA-Z]';
1

 だが、これは字数まで一致させねばならない。大文字小文字の無視とは要件が違う。

最適化

 次回。

対象環境

$ uname -a
Linux raspberrypi 4.19.42-v7+ #1218 SMP Tue May 14 00:48:17 BST 2019 armv7l GNU/Linux

前回まで