テキスト・正規表現
正規表現で欲しい部分だけ取れているか試したい
使うツール
正規表現は、欲しい文字列が一つ見つかった瞬間に完成した気分になりがちです。しかし、本当に困るのは、似た別の値まで拾ったり、例外的な一行を黙って落としたりすることです。最初から長い式を作るより、短い対象と明確な期待結果を用意し、一つずつ条件を加える方が、後から直しやすくなります。
ここでは架空の注文IDを使います。正規表現テストはJavaScript方式で動き、式とフラグを別に指定します。実際の個人情報やログを貼る前に、この小さな例で『抽出する範囲』『グループに残す値』『置換後の文字列』を分けて見てみましょう。
拾いたい二件と、拾いたくない二件を置く
order-104
order-205
preorder-306
order-407xorder-([0-9]+)フラグをgmとして実行すると、この式は四か所に一致します。preorder-306の途中にもorder-306があり、order-407xの先頭にもorder-407があるからです。『欲しい二件が含まれている』だけでは抽出条件は十分ではありません。この例では、一行全体が注文IDである行だけを残す、という条件がまだ式に入っていません。
行全体を対象にするなら、始まりと終わりを決める
^order-([0-9]+)$先頭の^と末尾の$を加えると、gmの条件ではorder-104とorder-205の二件になります。mは、^と$を複数行の各行の境界として扱うためのフラグです。mを外したgだけでは、この四行全体が一つの注文IDではないので一致しません。gとmは別の役割であり、『複数行だからg』と覚えると混乱します。
SheepDevの現在のテスト画面は一致箇所を列挙するため、処理内部でgを補います。gを外して最初の一件だけを調べる使い方にはなりません。移植先のコードで最初の一件だけを扱う場合は、その実行方法も別に検証します。同じ式でも、呼び出すAPIやフラグの違いで得られる結果は変わります。
一致した文字列と、取り出した数字を分ける
括弧で囲んだ([0-9]+)は、IDの数字部分をグループとして残します。order-104全体に一致していても、グループ1には104だけが入ります。式を104のような特定の値にしてしまうより、同じ形式の別IDにも対応できることが分かります。一方、+は一文字以上なので、order-だけの行は一致しません。空の数字列を許す必要があるかは、仕様として別に考えます。
全角数字や符号付き数、桁区切りをこの式は扱いません。order-012を許すなら、その条件を明示して別の試験例を加えます。また、IDの001を数値の1へ変換してよいとは限りません。正規表現が取り出した文字列の型や意味を、後の処理で勝手に変えないようにします。
置換では、拾わなかった行が残る
ID:$1ID:104
ID:205
preorder-306
order-407x$1は最初の捕獲グループを置換文字列へ入れる指定です。置換結果では、正しく一致した二行だけがID:104、ID:205へ変わり、それ以外の行は残ります。抽出したグループの一覧だけが欲しいのか、原文の一部を書き換えたいのかを区別してください。置換結果を抽出リストだと思うと、除外したはずの行が混ざって見えます。
式の中の括弧を追加すると、番号付きグループの対応が変わることがあります。式だけを直して置換文字列をそのままにせず、実際の出力を読み直します。$そのものなど、置換文字列にも特別な意味を持つ記法があります。大きな入力へ適用する前に、一致する一行、一致しない一行、空に近い一行で確認すると、意図しない書き換えを見つけやすくなります。
入力欄と、プログラムの文字列では書き方が違う
この画面の式欄には、正規表現本体を入力します。JavaScriptのリテラル表記のように/で囲んだり、末尾へgmを続けたりせず、フラグは別の設定へ入れます。プログラム内で文字列として書く際には、バックスラッシュをさらにエスケープする必要がある場合があります。画面で動く式をコードへ貼って動かないときは、正規表現そのものと、それを包む文字列の二段階を分けて確認します。
また、別の言語やデータベースが持つ正規表現と、JavaScript方式は同一とは限りません。ここで成功したことは、すべての実行環境で使える保証ではありません。移植先のフラグ、Unicodeの扱い、対応構文、置換のグループ指定を確認し、同じ成功例・失敗例を移植先でも実行します。
時間切れは『一致なし』ではない
式によっては、少し長い入力に変えただけで処理量が急増することがあります。このツールはWorkerで実行し、約1秒の制限で停止できる設計です。時間切れは処理を完了できなかった状態であり、対象が条件に一致しなかったという結果ではありません。短い成功例だけで速さを判断せず、失敗する長めの入力でも検証します。
対象テキストや式の大きさにも上限があり、一致一覧の表示は最大5,000件です。上限まで並んだ一覧を、すべての一致件数だと思わないでください。ログ全体の集計や本番の入力検証へ使う場合は、必要な制限と失敗時の扱いを移植先でも設計します。ここでの停止機能が、コピーした式へ自動的に付いていくわけではありません。
成功例だけでなく、似ている失敗例を増やす
注文番号を取り出す式が一件で成功すると、そのまま完成にしたくなります。そこで、番号の前に余分な文字がある行、数字が一桁少ない行、番号の後ろに別の文字が続く行を加えてみます。途中の部分一致を許す目的なら正しい結果でも、行全体の形式を確かめる目的なら誤りかもしれません。マッチした数だけでなく、ハイライトされた範囲を見て、何を一致とみなしたかを確認します。抽出したい範囲と、入力全体を検証する範囲は同じとは限りません。
数字を表す書き方にも前提があります。JavaScriptの通常の\dは、全角の123などを自動的に半角数字と同じものとして扱うための指定ではありません。入力を正規化してから比べるか、別の文字集合を許すかは、対象データのルールとして決めます。大文字小文字の無視も同様で、フラグを付ければ都合よく同一視できるからといって、そのIDが本来大小文字を区別しないとは限りません。テストの成功に合わせてルールを緩めるのではなく、許可する入力の定義に式を合わせます。
式をアプリへ戻すときは、正常例と反例も一緒にテストへ移します。JavaScriptで試した式を別言語の正規表現エンジンへ貼る場合は、フラグ、グループ、改行、置換記法の対応を再確認します。この画面で一秒以内に終わったことは、あらゆる長さの入力や別の実行環境で速いことの保証ではありません。入力の長さを増やした場合や一致しない長い入力も検証し、時間切れになった結果を空の抽出結果として採用しないようにします。