C# Tips | 文字列処理:JSON整形

C# C#
スポンサーリンク

はじめに 「JSON整形」は“ぐちゃぐちゃなJSONを、人間が読める形にする”作業

APIレスポンス、ログ、設定ファイル——
JSONは業務システムのあちこちに出てきますが、そのままだと

{"id":1,"name":"Taro","tags":["dev","backend"],"active":true}

のように「1行ベタ書き」で、目で追うのがつらいことが多いです。

JSON整形(Pretty Print)は、これを

{
  "id": 1,
  "name": "Taro",
  "tags": [
    "dev",
    "backend"
  ],
  "active": true
}

のように、インデントと改行を付けて「人間が読みやすい形」にする処理です。

C#では、これを“ユーティリティメソッド化”しておくと、
デバッグ、ログ出力、ツール作成などでかなり重宝します。


基本方針:一度「パース」してから「整形して書き出す」

なぜ「文字列置換」ではダメなのか

初心者がやりがちなのは、

  • カンマの後に改行を入れる
  • { の後に改行を入れる

といった「文字列置換ベース」の整形です。

これはすぐに破綻します。

文字列の中に "," が出てきた場合
エスケープされた {} が出てきた場合

など、「JSONの構造」と「ただの文字」とを区別できないからです。

正しいやり方は、

  1. JSON文字列を一度「オブジェクト」としてパースする
  2. そのオブジェクトを「整形オプション付き」で文字列に書き出す

という二段構えです。

C#では、System.Text.Json(.NET標準)を使うのが今の主流です。


実務で使える基本実装(System.Text.Json版)

まずは完成形のユーティリティ

using System;
using System.Text.Json;

public static class JsonFormatUtil
{
    public static string FormatJson(string? json)
    {
        if (string.IsNullOrWhiteSpace(json))
        {
            return string.Empty;
        }

        try
        {
            using var doc = JsonDocument.Parse(json);

            var options = new JsonSerializerOptions
            {
                WriteIndented = true
            };

            string formatted = JsonSerializer.Serialize(doc.RootElement, options);

            return formatted;
        }
        catch (JsonException)
        {
            return json;
        }
    }
}
C#

この1メソッドで、「JSON整形ユーティリティ」としてほぼ実務投入できます。
何をしているか、順番にかみ砕いていきます。


重要ポイント1:JsonDocument.Parse で“正しいJSONかどうか”をチェックする

using var doc = JsonDocument.Parse(json);
C#

ここでやっているのは、

  • JSON文字列をパースして
  • メモリ上の「JSONドキュメント」として扱えるようにする

という処理です。

ここで JsonException が投げられたら、その文字列は「JSONとして不正」です。

業務ユーティリティとしては、

  • 不正なら例外をそのまま投げる
  • 不正なら元の文字列をそのまま返す
  • 不正なら空文字を返す

など、方針を決める必要があります。

ここでは「整形だけしたい」「壊れていてもとりあえず見たい」という用途を想定して、
不正な場合は「元の文字列をそのまま返す」ようにしています。


重要ポイント2:WriteIndented = true で“整形モード”にする

var options = new JsonSerializerOptions
{
    WriteIndented = true
};

string formatted = JsonSerializer.Serialize(doc.RootElement, options);
C#

JsonSerializer.Serialize は、
オブジェクトをJSON文字列に変換するメソッドです。

ここで WriteIndented = true を指定すると、

  • 改行を入れる
  • インデント(スペース)を入れる

という「人間が読みやすい形」で出力してくれます。

逆に、WriteIndented = false(デフォルト)の場合は、
1行に詰めた“コンパクトなJSON”になります。

つまり、

  • パース → JsonDocument
  • 整形オプション付きでシリアライズ → 整形済みJSON文字列

という流れになっています。


動作例でイメージを固める

1行JSONを整形する

string raw = "{\"id\":1,\"name\":\"Taro\",\"tags\":[\"dev\",\"backend\"],\"active\":true}";

string formatted = JsonFormatUtil.FormatJson(raw);

Console.WriteLine(formatted);
C#

出力イメージは次のようになります。

{
  "id": 1,
  "name": "Taro",
  "tags": [
    "dev",
    "backend"
  ],
  "active": true
}

すでに整形済みのJSONを渡した場合

string pretty = "{\n  \"id\": 1,\n  \"name\": \"Taro\"\n}";

string formatted = JsonFormatUtil.FormatJson(pretty);

Console.WriteLine(formatted);
C#

この場合も、一度パースしてから再シリアライズされるので、
インデントスタイルが「ユーティリティ側のルール」に揃います。


ここが実務ポイント:不正JSONへの向き合い方

「壊れているけど、とりあえず見たい」ケースは多い

ログや外部システムとの連携では、

  • 途中で切れたJSON
  • 余計な文字が混ざったJSON
  • JSONっぽいけど完全ではない文字列

が飛んでくることがあります。

JsonDocument.Parse は厳密なので、
こういったものに対しては JsonException を投げます。

今回の実装では、

catch (JsonException)
{
    return json;
}
C#

として、「整形はあきらめて、元の文字列をそのまま返す」方針にしています。

これにより、

  • 正しいJSON → きれいに整形される
  • 不正なJSON → 少なくとも“見える”

という挙動になります。

「不正なら絶対に例外で止めたい」という要件なら、
ここで例外をそのまま投げる実装に変えればOKです。


Newtonsoft.Json(Json.NET)版も知っておくと便利

既存プロジェクトでよく使われているライブラリ

古めのプロジェクトや、
今でも柔軟な機能が必要な場面では、
Newtonsoft.Json(Json.NET)が使われていることも多いです。

同じような「JSON整形ユーティリティ」は、こう書けます。

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

public static class JsonFormatUtilNewtonsoft
{
    public static string FormatJson(string? json)
    {
        if (string.IsNullOrWhiteSpace(json))
        {
            return string.Empty;
        }

        try
        {
            var parsed = JToken.Parse(json);

            return parsed.ToString(Formatting.Indented);
        }
        catch (JsonReaderException)
        {
            return json;
        }
    }
}
C#

JToken.Parse でパースし、
ToString(Formatting.Indented) で整形済みJSONを出力する、という流れです。

新規開発なら System.Text.Json を優先でよく、
既存コードがJson.NETベースならこちらを使う、という使い分けになります。


業務ユーティリティとしてどうまとめるか

「とりあえず整形してログに出したい」を一行で書けるようにする

例えば、こんなラッパーを用意しておくと便利です。

public static class JsonPretty
{
    public static string Format(string? json)
        => JsonFormatUtil.FormatJson(json);
}
C#

呼び出し側は、

logger.LogInformation(JsonPretty.Format(responseBody));
C#

のように、「とりあえず整形してからログに出す」という処理を一行で書けます。

nullや空文字の扱いをユーティリティ側で決めておく

今回の実装では、

  • null / 空 / 空白だけ → 空文字を返す
  • 不正JSON → 元の文字列を返す

というルールにしています。

これにより、呼び出し側は

  • 例外処理を書かなくてよい
  • nullチェックを書かなくてよい

というメリットがあります。

プロジェクトの方針に合わせて、

  • 不正JSONは例外
  • nullはそのままnull

などに変えるのもアリですが、
「ユーティリティ側でルールを固定する」のが大事です。


まとめ 「JSON整形ユーティリティ」は“JSONの中身を理解するためのルーペ”

JSON整形は、
「アプリの動きを理解する」「外部サービスのレスポンスを読む」ための、
とても実務的なユーティリティです。

押さえておきたいポイントは、

JSON整形は“文字列置換”ではなく、“パースしてから整形して書き出す”のが正しいこと。
System.Text.JsonJsonDocument.ParseJsonSerializer.Serialize(WriteIndented = true) で、簡潔に実装できること。
不正JSONへの扱い(例外にするか、元の文字列を返すか)をユーティリティ側で決めておくと、呼び出し側が楽になること。
既存プロジェクトでは Newtonsoft.Json 版も書けると、どちらの世界でも戦えること。

ここまで理解できれば、「なんとなくJSONを眺めている」段階から一歩進んで、
“読みやすさとデバッグ効率を上げるためのJSON整形ユーティリティ”を、
自分のC#コードの中に自然に組み込めるようになっていきます。

タイトルとURLをコピーしました