nikkie-ftnextの日記

イベントレポートや読書メモを発信

jqのsplitで文字列分割。では、末尾のデリミタによる空文字列はどう除く? 対処法をGPT-4に教わりました

はじめに

ねぇ、あな〜たは〜 し〜あわせに〜 なれ〜るのよ〜♪1 nikkieです。

jqコマンド2の小ネタです。

目次

デリミタで区切られた文字列を分割したい

JSONのフィールドにデリミタで区切られた文字列(例:"kokoro,aki,fuka")が入っているとします。
デリミタ(ここではカンマ)で分割して、配列に格納したいです。

これはsplitでできます!3
https://www.tohoho-web.com/ex/jq.html#split

% jq --version
jq-1.6
% echo '"kokoro,aki,fuka"' | jq 'split(",")'
[
  "kokoro",
  "aki",
  "fuka"
]

末尾にもデリミタがついているときは...

splitすると、配列に空文字列が入ってきます。

% echo '"kokoro,aki,fuka,"' | jq 'split(",")'
[
  "kokoro",
  "aki",
  "fuka",
  ""
]

今回の利用シーンではこれがきれいではないので、除く方法を調べました。

「文字列の最後にデリミタがあったら除いてデリミタで分割する」という方法が浮かぶもjqでの方法が分からず(そもそもsuffixのremoveってできるんでしょうか?)
そうするとsplitしてできた配列から空文字列を除きたかったのですが、これも検索した範囲ではぱっと分からず、GPT-4にすがることに

助けて〜、GPT-4えも〜ん!

GPT-4「まかせて!」

% echo '"kokoro,aki,fuka,"' | jq 'split(",") | map(select(length > 0))'
[
  "kokoro",
  "aki",
  "fuka"
]

map(select(length > 0))で空文字列が除ける!

私が知らなかったのが、配列に対するmap
https://www.tohoho-web.com/ex/jq.html#map

配列やオブジェクトを受け取り、それぞれの値に対してマップ処理を行った結果の配列を返却します。

length > 0では各文字列の長さが0(=空文字列)でないかどうかが返ります(空文字列のときfalse)。
https://www.tohoho-web.com/ex/jq.html#length

% echo '"kokoro,aki,fuka,"' | jq 'split(",") | .[] | length > 0'
true
true
true
false

selectは条件を満たす要素を取り出すので
https://www.tohoho-web.com/ex/jq.html#select
以上でlength > 0の要素、すなわち、空文字列でない要素を取り出せるというわけですね!

% echo '"kokoro,aki,fuka,"' | jq 'split(",") | map(select(length > 0))'
[
  "kokoro",
  "aki",
  "fuka"
]

終わりに

jqコマンドで文字列をデリミタで分割する方法をアウトプットしました。

  • split("delimiter")で分割できる
  • もじ文字列の最後にデリミタがあって空文字列が混ざるようなら、map(select(length > 0))で空文字列でない要素だけを取り出せる

配列の要素に処理を適用できるmapを知って、jqでますますいろいろなことができそうです!
さすがGPT-4さん、ありがとうございます。

P.S. 最近のjq

超便利ツールを開発していただき、ありがとうございます!
バージョン上がるかな、ワクワク。


  1. 今日はシオンさんの初登校日!(『アイの歌声を聴かせて』)
  2. JSON Linesを扱うことが多いのですが、ちょっとした操作ならjqでできちゃうので、私には非常に重宝しています
  3. 今回「とほほのjq入門」を知ったのですが、これは情報量がやばいです!