PowerShellのみでJSONの Pretty Print を実現してみました。
モチベーション
- PowerShell標準の
ConvertTo-Json
のフォーマットが横に長いのが気に入らない。 - 外部のライブラリなしにスクリプトだけポンと置いて手軽に使いたい。
- .NETなので Newtonsoft とか読み込んでも良いけどライブラリ握るのもちょっとヤなので。
内容
ソースコードは gist にアップしたので全文はそちらを参照。
2018/01/04 追記
よくよく考えればインデント位置に合わせるよりカッコ数えた方が楽なことに気づいたのでロジック修正。
初版のソースは こちら 。
元のオブジェクト
$person = @{
name = 'kitamin'
age = '3x'
hobbies = @(
'game'
'programming'
)
}
PowerShell標準のJSON変換
# 前のカッコの位置から次のインデントが始まるので、プロパティ名が長いほどインデントが大きくなる _(:3」∠)_
PS> ConvertTo-Json $person
{
"name": "kitamin",
"age": "3x",
"hobbies": [
"game",
"programming"
]
}
実装した関数、デフォルトはスペース4つでインデント
PS> ConvertTo-PrettyJson $person
{
"name": "kitamin",
"age": "3x",
"hobbies": [
"game",
"programming"
]
}
インデント幅も変えられる
PS> ConvertTo-PrettyJson $person -IndentWidth 2
{
"name": "kitamin",
"age": "3x",
"hobbies": [
"game",
"programming"
]
}
既存のJSON文字列も再整形できる
PS> ConvertTo-PrettyJson -Json @'
{
"name": "kitamin",
"age": "3x",
"hobbies": [
"game",
"programming"
]
}
'@
{
"name": "kitamin",
"age": "3x",
"hobbies": [
"game",
"programming"
]
}
仕組み
ConvertTo-Json
で整形されたJSON文字列をベースに インデントの位置を力技で整形してます。
以下のルールでインデントを制御しています (2018/01/04 修正)。
- 開きカッコ(
[
,{
)が見つかったら 次の行 からインデントを一つ下げる - 閉じカッコ(
]
,}
)が見つかったら 今の行 からインデントを一つ上げる
ConvertTo-PrettyJson(該当箇所)
if ($line -match '^\s*[\}\]]') {
# カッコが閉じた
$indentCount--
}
# 出力行の整形
$output = ($indent * $indentCount) + $line.Trim()
Write-Output $output
if ($line -match '[\{\[]\s*$') {
# カッコが開いた
$indentCount++
}
JSON文字列を渡した場合は書式を整えるために内部で ConvertFrom-Json
-> ConvertTo-Json
とやっているのでかなり効率は悪いけど、
今のところ細かいオブジェクトを表示用整形する時に使いたかっただけなのであまり問題にはなってないです。
おまけ
そのうち内部処理をクラス化するかも。
PowerShellのクラスパフォーマンスとか実地取ってみたいのでそのサンプルとして。
2018/01/04
内部処理のクラス化 をしてみた。
パフォーマンスとかは別の記事で書くかもです。