このページの内容

正規表現

jqは、PHP、TextMate、Sublime Textなどと同様に、Oniguruma正規表現ライブラリを使っています。そのため、ここではjq固有の点を中心に説明します。

Onigurumaは複数の正規表現の構文に対応しています。jqが使うのは"Perl NG"(名前付きグループを持つPerl)の構文であることを知っておく必要があります。

jqの正規表現フィルターは、次のいずれかの形式で使えるように定義されています。

STRING | FILTER(REGEX)
STRING | FILTER(REGEX; FLAGS)
STRING | FILTER([REGEX])
STRING | FILTER([REGEX, FLAGS])

ここで、各要素は次のようになります。

  • STRING、REGEX、FLAGSはjqの文字列で、jqの文字列への式の埋込みが適用されます。
  • REGEXは、式の埋込み後に、有効な正規表現である必要があります。
  • FILTERは、後述する test、match、capture のいずれかです。

REGEXはJSON文字列に評価される必要があるため、正規表現を構成するための一部の文字をエスケープしなければなりません。たとえば、空白文字を表す正規表現 \s は、"\\s" と書きます。

FLAGSは、対応するフラグを1つ以上含む文字列です。

  • g - 全体検索(最初だけでなく、すべての一致を見つける)
  • i - 大文字と小文字を区別しない検索
  • m - 複数行モード(. が改行にも一致する)
  • n - 空の一致を無視する
  • p - sとmの両方のモードを有効にする
  • s - 単一行モード(^ -> \A、$ -> \Z)
  • l - 可能な限り長い一致を見つける
  • x - 拡張正規表現形式(空白とコメントを無視する)

x フラグで空白に一致させるには、\s を使います。例:

jq -n '"a b" | test("a\\sb"; "x")'

一部のフラグは、REGEX内でも指定できることに注意してください。例:

jq -n '("test", "TEst", "teST", "TEST") | test("(?i)te(?-i)st")'

これは、true、true、false、false に評価されます。

test(val), test(regex; flags)

match と同様ですが、一致オブジェクトは返しません。正規表現が入力に一致するかどうかに応じて、true または false だけを返します。

実行例 1

コマンド

jq 'test("foo")'

入力

"foo"

出力 1

true

実行例 2

コマンド

jq '.[] | test("a b c # spaces are ignored"; "ix")'

入力

["xabcd", "ABC"]

出力 1

true

出力 2

true

match(val), match(regex; flags)

matchは、見つかった一致ごとにオブジェクトを出力します。一致には、次のフィールドがあります。

  • offset - 入力の先頭からのオフセット。UTF-8コードポイント単位
  • length - 一致の長さ。UTF-8コードポイント単位
  • string - 一致した文字列
  • captures - キャプチャグループを表すオブジェクトの配列

キャプチャグループのオブジェクトには、次のフィールドがあります。

  • offset - 入力の先頭からのオフセット。UTF-8コードポイント単位
  • length - このキャプチャグループの長さ。UTF-8コードポイント単位
  • string - キャプチャされた文字列
  • name - キャプチャグループの名前(名前なしの場合は null)

何にも一致しなかったキャプチャグループは、オフセット-1を返します。

実行例 1

コマンド

jq 'match("(abc)+"; "g")'

入力

"abc abc"

出力 1

{"offset": 0, "length": 3, "string": "abc", "captures": [{"offset": 0, "length": 3, "string": "abc", "name": null}]}

出力 2

{"offset": 4, "length": 3, "string": "abc", "captures": [{"offset": 4, "length": 3, "string": "abc", "name": null}]}

実行例 2

コマンド

jq 'match("foo")'

入力

"foo bar foo"

出力 1

{"offset": 0, "length": 3, "string": "foo", "captures": []}

実行例 3

コマンド

jq 'match(["foo", "ig"])'

入力

"foo bar FOO"

出力 1

{"offset": 0, "length": 3, "string": "foo", "captures": []}

出力 2

{"offset": 8, "length": 3, "string": "FOO", "captures": []}

実行例 4

コマンド

jq 'match("foo (?<bar123>bar)? foo"; "ig")'

入力

"foo bar foo foo  foo"

出力 1

{"offset": 0, "length": 11, "string": "foo bar foo", "captures": [{"offset": 4, "length": 3, "string": "bar", "name": "bar123"}]}

出力 2

{"offset": 12, "length": 8, "string": "foo  foo", "captures": [{"offset": -1, "length": 0, "string": null, "name": "bar123"}]}

実行例 5

コマンド

jq '[ match("."; "g")] | length'

入力

"abc"

出力 1

3

capture(val), capture(regex; flags)

名前付きキャプチャをJSONオブジェクトにまとめます。各キャプチャの名前をキーとし、一致した文字列を対応する値とします。

実行例 1

コマンド

jq 'capture("(?<a>[a-z]+)-(?<n>[0-9]+)")'

入力

"xyzzy-14"

出力 1

{ "a": "xyzzy", "n": "14" }

scan(regex), scan(regex; flags)

入力のうち、正規表現に一致する重なりのない部分文字列を、ストリームとして出力します。フラグが指定されていれば、それに従います。一致がなければ、ストリームは空です。各入力文字列のすべての一致をまとめて取得するには、[ expr ] という書き方を使います。たとえば、[ scan(regex) ] です。正規表現にキャプチャグループが含まれている場合、フィルターは配列のストリームを出力し、各配列にはキャプチャされた文字列が入ります。

実行例 1

コマンド

jq 'scan("c")'

入力

"abcdefabc"

出力 1

"c"

出力 2

"c"

実行例 2

コマンド

jq 'scan("(a+)(b+)")'

入力

"abaabbaaabbb"

出力 1

["a","b"]

出力 2

["aa","bb"]

出力 3

["aaa","bbb"]

split(regex; flags)

入力文字列を、正規表現の各一致箇所で分割します。

後方互換性のため、引数を1つ指定して呼び出した split は、正規表現ではなく文字列で分割します。

実行例 1

コマンド

jq 'split(", *"; null)'

入力

"ab,cd, ef"

出力 1

["ab","cd","ef"]

splits(regex), splits(regex; flags)

対応する split と同じ結果を、配列ではなくストリームとして提供します。

実行例 1

コマンド

jq 'splits(", *")'

入力

"ab,cd,   ef, gh"

出力 1

"ab"

出力 2

"cd"

出力 3

"ef"

出力 4

"gh"

実行例 2

コマンド

jq 'splits(",? *"; "n")'

入力

"ab,cd ef,  gh"

出力 1

"ab"

出力 2

"cd"

出力 3

"ef"

出力 4

"gh"

sub(regex; tostring), sub(regex; tostring; flags)

入力文字列内の正規表現の最初の一致を、式の埋込み後の tostring で置き換えて得られる文字列を出力します。tostring はjqの文字列、またはそのような文字列のストリームである必要があります。各文字列は、名前付きキャプチャへの参照を含められます。名前付きキャプチャは、実質的に、capture が構築するようなJSONオブジェクトとして tostring に渡されます。そのため、"x"という名前でキャプチャされた変数への参照は、"\(.x)" という形式になります。

実行例 1

コマンド

jq 'sub("[^a-z]*(?<x>[a-z]+)"; "Z\(.x)"; "g")'

入力

"123abc456def"

出力 1

"ZabcZdef"

実行例 2

コマンド

jq '[sub("(?<a>.)"; "\(.a|ascii_upcase)", "\(.a|ascii_downcase)")]'

入力

"aB"

出力 1

["AB","aB"]

gsub(regex; tostring), gsub(regex; tostring; flags)

gsub は sub と同様ですが、正規表現の重なりのないすべての一致を、式の埋込み後の tostring で置き換えます。2番目の引数がjq文字列のストリームであれば、gsub は対応するJSON文字列のストリームを生成します。

実行例 1

コマンド

jq 'gsub("(?<x>.)[^a]*"; "+\(.x)-")'

入力

"Abcabc"

出力 1

"+A-+a-"

実行例 2

コマンド

jq '[gsub("p"; "a", "b")]'

入力

"p"

出力 1

["a","b"]