# 帳票設計書 9-sprintf フォーマット文字列

## 概要

Kernel.#sprintfによる書式指定文字列の生成に関する帳票設計書である。`%d`/`%s`/`%f`等のフォーマット指定子をサポートし、引数を指定形式の文字列に変換する。

### 本帳票の処理概要

本帳票は、mrubyのKernel#sprintf（およびKernel#format、String#%）メソッドによる書式指定文字列の生成機能である。Cのsprintf相当の書式指定子をサポートし、引数リストまたはハッシュから値を取得して指定フォーマットに変換した文字列を返す。

**業務上の目的・背景**：数値、文字列、浮動小数点数等のデータを、ユーザーが指定した書式に従って整形出力するための基盤機能である。ログ出力、レポート生成、データのテキスト変換など、あらゆる文字列生成処理で使用される汎用的なフォーマッティング機能を提供する。

**帳票の利用シーン**：Rubyコード内でsprintf/format/String#%メソッドを呼び出す全ての場面で使用される。例: `sprintf("%d件のデータ", count)` や `"合計: %08.2f" % total`。

**主要な出力内容**：
1. フォーマット指定子に基づく文字列変換結果
2. サポートする指定子: %c(文字), %s/%p(文字列), %d/%i/%u/%o/%x/%X/%b/%B(整数), %f/%e/%E/%g/%G(浮動小数点)
3. フラグ: -(左詰め), +(符号表示), 0(ゼロ埋め), #(プレフィックス), スペース(符号スペース)
4. 幅指定と精度指定（数値リテラルまたは*による引数指定）
5. 名前付き引数（`%<name>d` / `%{name}`形式）

**帳票の出力タイミング**：sprintf/format/String#%メソッドが呼び出された際に、フォーマット済み文字列を戻り値として返す。

**帳票の利用者**：mrubyアプリケーション開発者（全般）。

## 帳票種別

フォーマット出力（メモリ上の文字列として生成）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | Rubyコード | `sprintf(format, ...)` | Kernel#sprintfメソッド呼び出し |
| - | Rubyコード | `format(format, ...)` | Kernel#formatメソッド呼び出し |
| - | Rubyコード | `"format" % args` | String#%メソッド呼び出し |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | mruby String オブジェクト（メモリ上） |
| 用紙サイズ | N/A |
| 向き | N/A |
| ファイル名 | N/A（戻り値として返却） |
| 出力方法 | mrb_value（String型）として返却 |
| 文字コード | UTF-8 |

### PDF固有設定

N/A

### Excel固有設定

N/A

## 帳票レイアウト

### レイアウト概要

フォーマット文字列内の`%`で始まる指定子が、対応する引数の値に置換された結果文字列が生成される。

```
入力: sprintf("名前: %s, 年齢: %d, 身長: %.1fcm", "太郎", 30, 175.5)
出力: "名前: 太郎, 年齢: 30, 身長: 175.5cm"
```

### ヘッダー部

N/A

### 明細部

#### フォーマット指定子一覧

| No | 指定子 | 説明 | データ型 | 表示形式 | 列幅 |
|----|-------|------|---------|---------|-----|
| 1 | %c | 文字（整数を文字に変換） | Integer/String | 単一文字 | 1 |
| 2 | %s | 文字列（to_s変換） | Any | 文字列 | 可変 |
| 3 | %p | inspect形式文字列 | Any | inspect結果 | 可変 |
| 4 | %d / %i | 10進整数（符号付き） | Integer | 10進数 | 可変 |
| 5 | %u | 10進整数（符号なし扱い） | Integer | 10進数 | 可変 |
| 6 | %o | 8進整数 | Integer | 8進数 | 可変 |
| 7 | %x | 16進整数（小文字） | Integer | 16進数(a-f) | 可変 |
| 8 | %X | 16進整数（大文字） | Integer | 16進数(A-F) | 可変 |
| 9 | %b | 2進整数（小文字） | Integer | 2進数 | 可変 |
| 10 | %B | 2進整数（大文字） | Integer | 2進数 | 可変 |
| 11 | %f | 浮動小数点数（固定小数点表記） | Float | 小数点表記 | 可変 |
| 12 | %e | 浮動小数点数（指数表記・小文字） | Float | 指数表記(e) | 可変 |
| 13 | %E | 浮動小数点数（指数表記・大文字） | Float | 指数表記(E) | 可変 |
| 14 | %g | 浮動小数点数（汎用・小文字） | Float | 自動選択 | 可変 |
| 15 | %G | 浮動小数点数（汎用・大文字） | Float | 自動選択 | 可変 |
| 16 | %% | リテラル% | - | % | 1 |

#### フラグ一覧

| No | フラグ | 説明 | 定数 |
|----|-------|------|------|
| 1 | `-` | 左詰め | FMINUS (2) |
| 2 | `+` | 正数に+符号表示 | FPLUS (4) |
| 3 | `0` | ゼロ埋め | FZERO (8) |
| 4 | `#` | プレフィックス表示（0x, 0b等） | FSHARP (1) |
| 5 | ` ` (スペース) | 正数にスペース表示 | FSPACE (16) |

### フッター部

N/A

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| フォーマット文字列 | %指定子を含むString | Yes |
| 引数リスト | フォーマット指定子に対応する値群 | 指定子がある場合Yes |

### ソート順

N/A

### 改ページ条件

N/A

## データベース参照仕様

### 参照テーブル一覧

本帳票はデータベースを参照しない。引数として渡されたmrubyオブジェクトを参照する。

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| mrb_value argv[] | フォーマット引数配列 | 位置指定または名前指定 |

### テーブル別参照項目詳細

N/A（引数配列から直接取得）

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| 初期バッファサイズ | `(end - p) + 120 + 24 * (指定子数)` (上限4096) | なし | 動的拡張あり |
| 整数の基数変換 | mrb_uint_to_cstr / mrb_int_to_cstr | なし | 2/8/10/16進数 |
| 浮動小数点フォーマット | mrb_format_float | 精度指定に従う | f/e/E/g/G形式 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[sprintf呼び出し] --> B[引数検証]
    B --> C[フォーマット文字列をスキャン]
    C --> D{次の文字?}
    D -->|リテラル文字| E[バッファに直接コピー]
    D -->|%指定子| F[get_fmt_specで指定子解析]
    F --> G[フラグ・幅・精度の解析]
    G --> H{指定子の型?}
    H -->|FMT_CHAR| I[文字変換・出力]
    H -->|FMT_STRING| J[to_s/inspect変換・出力]
    H -->|FMT_INTEGER| K[整数変換・基数変換・出力]
    H -->|FMT_FLOAT| L[浮動小数点変換・出力]
    H -->|FMT_LITERAL| M[%%やリテラル出力]
    I --> N[次の文字へ]
    J --> N
    K --> N
    L --> N
    M --> N
    N --> D
    D -->|文字列終端| O[結果文字列を返却]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| 引数不足 | argc <= 0 | `too few arguments` | フォーマット文字列を指定 |
| 幅の二重指定 | FWIDTH設定後に再度幅指定 | `width given twice` | フォーマット文字列を修正 |
| 精度後の幅指定 | FPREC0後に幅指定 | `width after precision` | フォーマット文字列を修正 |
| 幅後のフラグ | FWIDTH後にフラグ指定 | `flag after width` | フォーマット文字列を修正 |
| 精度後のフラグ | FPREC0後にフラグ指定 | `flag after precision` | フォーマット文字列を修正 |
| ハッシュ必須 | 名前付き引数で非Hash | `one hash required` | Hash引数を渡す |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 1回の呼び出しで1文字列を生成 |
| 目標出力時間 | マイクロ秒〜ミリ秒単位 |
| 同時出力数上限 | N/A（スレッドセーフ） |

## セキュリティ考慮事項

- フォーマット文字列インジェクションに注意（ユーザー入力をフォーマット文字列に使用しない）
- 幅指定で大きな値を指定するとメモリ消費が増大する可能性がある（bsiz上限4096で初期制限）

## 備考

- Kernel#sprintfとKernel#formatは同一関数（mrb_f_sprintf）のエイリアス
- 名前付き引数は`%<name>d`形式（フォーマット指定子付き）と`%{name}`形式（そのまま文字列化）の2種類をサポート
- バッファサイズは動的に拡張される（初期見積もり後、必要に応じてmrb_str_resizeで拡張）
- BIT_DIGITS(N)マクロは整数を文字列に変換する際の桁数見積もりに使用される

---

## コードリーディングガイド

本帳票を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | sprintf.c | `mrbgems/mruby-sprintf/src/sprintf.c` | `fmt_spec_t`構造体（102-106行目）: type, base, subtypeフィールド |
| 1-2 | sprintf.c | `mrbgems/mruby-sprintf/src/sprintf.c` | FMT_*定数（89-99行目）: フォーマット指定子の型分類 |
| 1-3 | sprintf.c | `mrbgems/mruby-sprintf/src/sprintf.c` | F*フラグ定数（78-86行目）: FNONE, FSHARP, FMINUS, FPLUS, FZERO, FSPACE, FWIDTH, FPREC |

**読解のコツ**: get_fmt_spec関数（110-174行目）がフォーマット指定子の文字をfmt_spec_t構造体に変換するルックアップテーブルとして機能する。この関数を先に理解すると全体の構造が把握しやすい。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | sprintf.c | `mrbgems/mruby-sprintf/src/sprintf.c` | `mrb_f_sprintf`（1168-1182行目）: Rubyレベルのsprintf/format関数 |
| 2-2 | sprintf.c | `mrbgems/mruby-sprintf/src/sprintf.c` | `mrb_mruby_sprintf_gem_init`（1185-1190行目）: gem初期化。sprintf/formatメソッド登録 |

**主要処理フロー**:
1. **1173行目**: mrb_get_argsで可変長引数を取得
2. **1175-1177行目**: 引数なしエラー
3. **1180行目**: mrb_str_formatに委譲（argv[0]=フォーマット文字列、残り=引数）

#### Step 3: フォーマット処理のコアを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | sprintf.c | `mrbgems/mruby-sprintf/src/sprintf.c` | `mrb_str_format`（350-行末）: フォーマット処理のメイン関数 |
| 3-2 | sprintf.c | `mrbgems/mruby-sprintf/src/sprintf.c` | `get_fmt_spec`（110-174行目）: 指定子文字→fmt_spec_t変換 |
| 3-3 | sprintf.c | `mrbgems/mruby-sprintf/src/sprintf.c` | `fmt_float`（178行目〜）: 浮動小数点フォーマット |
| 3-4 | sprintf.c | `mrbgems/mruby-sprintf/src/sprintf.c` | `mrb_uint_to_cstr`（49-76行目）: 整数の基数変換 |

**主要処理フロー**:
- **383行目**: フォーマット文字列をString型に確定
- **393-398行目**: バッファサイズ見積もりと初期確保
- **メインループ**: フォーマット文字列を1文字ずつ走査し、%指定子を検出して変換処理

### プログラム呼び出し階層図

```
mrb_f_sprintf() [sprintf.c:1168]
    │
    └─ mrb_str_format() [sprintf.c:350]
           │
           ├─ get_fmt_spec() [sprintf.c:110]  ← 指定子解析
           │
           ├─ (FMT_CHAR処理) ← 文字変換
           ├─ (FMT_STRING処理) ← 文字列/inspect変換
           │      └─ mrb_obj_as_string() / mrb_inspect()
           │
           ├─ (FMT_INTEGER処理) ← 整数変換
           │      ├─ mrb_as_int() ← Integer取得
           │      ├─ mrb_int_to_cstr() ← 10進変換
           │      └─ mrb_uint_to_cstr() [sprintf.c:49] ← 2/8/16進変換
           │
           ├─ (FMT_FLOAT処理) ← 浮動小数点変換
           │      └─ fmt_float() [sprintf.c:178]
           │             └─ mrb_format_float() ← 外部関数
           │
           └─ (FMT_NAMED処理) ← 名前付き引数
                  └─ mrb_hash_get() ← Hash参照
```

### データフロー図

```
[入力]                       [処理]                         [出力]

フォーマット文字列 ──▶ mrb_str_format() ─────────▶ mrb_value (String)
+ 引数リスト            │
                       ├─ リテラル文字 → バッファコピー
                       ├─ %c → 文字変換
                       ├─ %s/%p → 文字列変換
                       ├─ %d/%o/%x/%b → 整数基数変換
                       ├─ %f/%e/%g → 浮動小数点変換
                       └─ %<name>/%{name} → Hash参照
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| sprintf.c | `mrbgems/mruby-sprintf/src/sprintf.c` | ソース | sprintfのコア実装。mrb_str_format, mrb_f_sprintf等 |
| string.h | `include/mruby/string.h` | ヘッダー | mruby String操作関数 |
| hash.h | `include/mruby/hash.h` | ヘッダー | Hash操作（名前付き引数用） |
| numeric.h | `include/mruby/numeric.h` | ヘッダー | 数値変換関数 |
