※小説ではない※専門書 要約資料集 為替(換算)3.9万円でもらう 紐解集生成 専門 初入門 資料 作:{作者名}
> 現代学問宇宙図鑑シリーズ・PC創造大全(BOOK-0358・水準一〜十二を貫く22部構成の統合大型巻)・ノウハウ目録帯(関数ノウハウ500)第3巻(m部)。設計書の正: gakumon/CATALOG_PC創造大全.md。ガイド役: Fable 5 監修 / Sonnet 5 執筆(脚本班)。
> **帯**: 関数ノウハウ500(KNOW-F-0001〜0500)のうち、本冊は**KNOW-F-0251〜0375の125項目(データ変換の型)**を正式登録する。目録帯の系列: k部(KNOW-F-0001〜0125・関数設計の基本形)→l部(KNOW-F-0126〜0250・制御と分岐の型)→**m部(本冊・KNOW-F-0251〜0375・データ変換の型)**→n部(KNOW-F-0376〜0500・合成と堅牢化の型)。→前巻BOOK-0358l(制御と分岐の型)/→次巻BOOK-0358n(合成と堅牢化の型)。
> **§16.22完全性優先・上限例外則を適用**。目安は空白除き80,000〜120,000字程度(実測は本文末尾「参考: 本冊の構成情報」に記載)。KNOW-F-0251〜0375の全125項目に五点セット(①名称 ②構造の型〈骨子・図または式〉 ③使いどころ ④組合せ例 ⑤確認事項〈罠と検算・安全注意〉)を漏れなく揃える完全性を数値上限より優先し、白カード(未執筆項目)は0件とする。
> 接続先: →BOOK-0184(関数パターン目録I・構造二百種、理-KAN-001〜200と本冊KNOW-F-0251〜375は「関数の形」と「データの変換技」という姉妹目録の関係にある)、→BOOK-0343(作る力生きる力・情報構造の設計、木構造・グラフ構造の理論的背景)、→脊椎対BOOK-0358f(関数を正式に組む・水準五〜八、「段落を崩しても通る」の解釈表=順序独立・冪等・参照透過)。
> 安全: 本冊が扱う配列・文字列・数値・構造変換・検証はソフトウェア設計上の技法であり、電気工事や高電圧部品の分解のような物理的危険は伴わない。ただし第3章(数値精度)の扱いを誤ると金額計算・計量・医療計算などで実害を生みうるため、実務転用時は各項目の「確認事項」に記す検算を必ず自分の手でも再現すること。
> 水準: 五〜八(脊椎BOOK-0358fの「関数を正式に組む」に対応するノウハウ実務篇)。
---
# BOOK-0358m PC創造大全 目録III データ変換の型125種
> 現代学問宇宙図鑑シリーズ・PC創造大全(BOOK-0358・水準一〜十二を貫く22部構成の統合大型巻)・ノウハウ目録帯(関数ノウハウ500)第3巻(m部)。設計書の正: gakumon/CATALOG_PC創造大全.md。ガイド役: Fable 5 監修 / Sonnet 5 執筆(脚本班)。
> **帯**: 関数ノウハウ500(KNOW-F-0001〜0500)のうち、本冊は**KNOW-F-0251〜0375の125項目(データ変換の型)**を正式登録する。目録帯の系列: k部(KNOW-F-0001〜0125・関数設計の基本形)→l部(KNOW-F-0126〜0250・制御と分岐の型)→**m部(本冊・KNOW-F-0251〜0375・データ変換の型)**→n部(KNOW-F-0376〜0500・合成と堅牢化の型)。→前巻BOOK-0358l(制御と分岐の型)/→次巻BOOK-0358n(合成と堅牢化の型)。
> **§16.22完全性優先・上限例外則を適用**。目安は空白除き80,000〜120,000字程度(実測は本文末尾「参考: 本冊の構成情報」に記載)。KNOW-F-0251〜0375の全125項目に五点セット(①名称 ②構造の型〈骨子・図または式〉 ③使いどころ ④組合せ例 ⑤確認事項〈罠と検算・安全注意〉)を漏れなく揃える完全性を数値上限より優先し、白カード(未執筆項目)は0件とする。
> 接続先: →BOOK-0184(関数パターン目録I・構造二百種、理-KAN-001〜200と本冊KNOW-F-0251〜375は「関数の形」と「データの変換技」という姉妹目録の関係にある)、→BOOK-0343(作る力生きる力・情報構造の設計、木構造・グラフ構造の理論的背景)、→脊椎対BOOK-0358f(関数を正式に組む・水準五〜八、「段落を崩しても通る」の解釈表=順序独立・冪等・参照透過)。
> 安全: 本冊が扱う配列・文字列・数値・構造変換・検証はソフトウェア設計上の技法であり、電気工事や高電圧部品の分解のような物理的危険は伴わない。ただし第3章(数値精度)の扱いを誤ると金額計算・計量・医療計算などで実害を生みうるため、実務転用時は各項目の「確認事項」に記す検算を必ず自分の手でも再現すること。
> 水準: 五〜八(脊椎BOOK-0358fの「関数を正式に組む」に対応するノウハウ実務篇)。
---
## 序章 データを「型」として引き出しに並べる
### 入口の物語 — 変換の型番号で会話するチーム
あるデータ基盤チームでは、レビューの会話が「そこはKNOW-F-0328で」「いや0328だと参照が重複するから0331のマージで」というふうに、型番号だけで進むという話がある。新しく入った人が驚いて理由を尋ねると、古参のエンジニアはこう答えたという。「配列を回してオブジェクトに詰め替える処理も、文字列をエスケープする処理も、金額を丸める処理も、突き詰めれば入力の形を別の形へ移す『変換』でしかない。毎回コードを一から読むより、あらかじめ型に名前をつけておいて、その型が持つ罠と検算方法までセットで覚えておくほうが、圧倒的にレビューが速い」。
この発想はBOOK-0184『関数パターン目録I』が関数の「形」を理-KAN-001〜200としてそろえた発想と地続きである。理-KAN帯が「f(x)=2x+1のような式の形」を目録化したのに対し、本冊が扱うのは「配列Aを受け取って別の配列Bを返す」「文字列Sを受け取って正規化済みの文字列を返す」というような、**具体的なデータを入力してデータを出力する変換の型**である。BOOK-0358の脊椎(物語篇)f部では「関数を正式に組む」道筋を一本道でたどるが、本冊(目録篇m部)はその実務側として、変換のパターンを125種、KNOW-F-0251〜KNOW-F-0375というIDのもとに网羅する。
### 五点セットの構成(KNOW-F-0251〜0375共通)
本冊のKNOW-F項目は、CATALOG_PC創造大全.mdが定める五点セットを次のように具体化して用いる。
1. **①名称**(見出しに記す型の名前。英語の一般名を併記する)
2. **②構造の型**(骨子・図または式。疑似コードまたはASCII図で処理の骨格を示す)
3. **③使いどころ**(どんな場面で選ぶか、逆にどんな場面では避けるべきかの判断基準)
4. **④組合せ例**(他のKNOW-F項目と組み合わせた具体的な使用例、可能な限り数値・文字列の実例つき)
5. **⑤確認事項**(罠と検算・安全注意。誤りやすい点と、実際に手を動かして確かめられる検算行)
### 本冊で使う共通サンプル(KNOW-F-0251〜0375共通)
個別の項目で断りがない限り、本冊の疑似コード・検算は以下の共通サンプルを土台にする(BOOK-0318a方式で基準寸法をそろえたのと同じ発想で、基準データをそろえておく)。
| 記号 | 内容 | 値 |
|---|---|---|
| A | 数値配列サンプル | `[5, 3, 8, 1, 9, 2]` |
| B | 第二の数値配列サンプル(結合・zip用) | `[10, 20, 30]` |
| S | 文字列サンプル | `" Hello, World! "`(前後に半角空白2つずつ) |
| U | ユーザー配列サンプル(オブジェクトの配列) | `[{id:1,name:"佐藤",dept:"営業"}, {id:2,name:"鈴木",dept:"開発"}, {id:3,name:"高橋",dept:"営業"}]` |
| T | ネスト木構造サンプル | `{id:1, children:[{id:2, children:[]}, {id:3, children:[{id:4, children:[]}]}]}` |
| P | 金額サンプル(円) | 1980円(税込10%で計算する場合の税抜相当を各項目で個別に検算する) |
| V | 検証対象サンプル(フォームオブジェクト) | `{name:"", age:17, email:"a@b"}` |
**表記の約束**: 疑似コードは特定の言語に依存しない擬似構文を用いる。`for x of A` は配列Aの各要素xを先頭から順に取り出す走査、`[]` は空配列、`->` は「入力から出力への変換」を表す矢印として使う。0で始まる添字(0-indexed)を既定とし、1-indexedを使う場合はその都度明記する。
### 本冊の構成(五章・KNOW-F-0251〜0375)
- 第1章 配列操作の型(KNOW-F-0251〜0275・走査/フィルタ/写像/畳み込み/分割結合/整列の使い分け)
- 第2章 文字列処理の型(KNOW-F-0276〜0300・分解/正規化/エスケープ/テンプレート)
- 第3章 数値精度の型(KNOW-F-0301〜0325・浮動小数点の罠/丸め/整数演算への還元/桁あふれ)
- 第4章 構造変換の型(KNOW-F-0326〜0350・ネスト⇄フラット/グループ化/索引作り)
- 第5章 検証の型(KNOW-F-0351〜0375・入力検証/スキーマ的検査)
各章の末尾(KNOW-F-0275・0300・0325・0350・0375)には、章内の全項目を分類表にまとめた「まとめ」項目を置く。まとめ項目も他の項目と同じく五点セットを備えるが、②構造の型は「章内の分類表」、③使いどころは「章全体の使い分け方針」、④組合せ例は「代表的な組合せの並記」、⑤確認事項は「章全体で共有される検証原則」として与える(BOOK-0318a方式を踏襲)。
---
---
## 第1章 配列操作の型(KNOW-F-0251〜0275)
配列は「同じ形の値が並んだ入れ物」であり、PC創造大全が扱うメモリ番地の連なり(脊椎a部「配列の数理」)を、プログラムの中で直接操作するための最も基本的な構造でもある。第1章では、共通サンプルA=[5,3,8,1,9,2]を軸に、走査・フィルタ・写像・畳み込み・分割/結合・整列という6系統の使い分けを24種の型として並べる。
### KNOW-F-0251 走査の型(for/forEachによる線形走査)
**構造の型**:
```
for x of A:
処理(x)
```
配列の先頭から末尾まで、各要素に同じ処理を1回ずつ適用する最も基本的な反復構造。
**使いどころ**: 表示・書き込み・カウントのような副作用を各要素に及ぼしたいときに使う。戻り値を作らない「見て回るだけ」の処理に向き、値を変換したいならmap(KNOW-F-0254)、条件で絞りたいならfilter(KNOW-F-0253)を選ぶほうが意図が伝わる。
**組合せ例**: 共通サンプルAに対しforEachで合計を数える処理は、reduce(KNOW-F-0255)で `A.reduce((acc,x)=>acc+x, 0)` と書き直せる。走査自体は同じでも、蓄積の責任を呼び出し側の変数に持たせるか関数の戻り値に持たせるかが設計上の分岐点になる。
**確認事項**: forEach系のAPIはbreakやreturnで途中終了できない実装が多く、条件成立時に打ち切りたい場合はforやfor-ofへ書き換える必要がある。Aの合計は5+3+8+1+9+2=28であり、初期値を誤って0でなく1にすると29という誤った値が出る(検算: 0スタートで28、1スタートで29、差分1が初期値のずれと一致)。
---
### KNOW-F-0252 while走査の型(条件終了走査)
**構造の型**:
```
i = 0
while 条件(A[i]):
処理(A[i]); i = i + 1
```
添字を明示的に管理し、要素の値やインデックスに基づく条件が崩れた時点で止まる反復構造。
**使いどころ**: 「配列の要素数」ではなく「値の条件」で止めたいときに使う。たとえばAを先頭から見て、値が5未満である間だけ処理するような場合、for-ofでは素直に書けないためwhileが向く。
**組合せ例**: Aに対し「値が8未満の間だけ加算する」whileループはA[0]=5(加算,計5)→A[1]=3(加算,計8)→A[2]=8(条件false、8未満ではないため停止)となり、結果は5+3=8で停止する。同じ処理をfindIndex(KNOW-F-0256)で「8以上になる最初の添字」を先に求めてからslice(KNOW-F-0261)する二段構成に書き換えることもできる。
**確認事項**: 添字の更新(i=i+1)を書き忘れると無限ループになる典型的な罠がある。停止条件が「値が8未満」なのか「値が8以下」なのかで結果が変わる点も要注意で、上の例をA[2]=8を含めて加算する条件(8以下)にすると合計は5+3+8=16になる(検算: 未満条件で8、以下条件で16、差分8がA[2]の値と一致)。
---
### KNOW-F-0253 filter(条件抽出)の型
**構造の型**:
```
B = []
for x of A:
if 条件(x): B.push(x)
```
条件を満たす要素だけを残した新しい配列を作る、非破壊の抽出構造。
**使いどころ**: 元の配列を変更せずに「条件に合うものだけ」を取り出したいときに使う。件数を知りたいだけならfilter結果の長さを数えるより、条件を満たす個数を直接reduceで数えるほうが中間配列を作らず効率的な場合がある。
**組合せ例**: Aに対し「4より大きい」条件でfilterすると[5,8,9]が得られる(5>4,3>4は偽,8>4,1>4は偽,9>4)。続けてmap(KNOW-F-0254)でそれぞれを2倍すると[10,16,18]になり、filter→mapの二段構成は「絞ってから変換する」という順序を明示する典型例になる。
**確認事項**: filterは元の配列を変更しない非破壊操作である点をsplice(KNOW-F-0262)と混同しないこと。条件式に副作用(カウンタの加算など)を書き込むと、実行順序やスキップされた要素の扱いによって結果が変わりうるため、条件式は原則として純粋な判定だけにとどめる。
---
### KNOW-F-0254 map(写像)の型
**構造の型**:
```
B = []
for x of A:
B.push(変換(x))
```
各要素を1対1で別の値に変換し、同じ長さの新しい配列を作る構造。
**使いどころ**: 要素数を変えずに「形だけ変える」ときに使う。要素数を減らしたいならfilter(KNOW-F-0253)、要素数を増減させたり合体させたいならflatMap(KNOW-F-0264)やreduce(KNOW-F-0255)を選ぶ。
**組合せ例**: Aの各要素を2倍する変換で[10,6,16,2,18,4]が得られる。続けてfilter(KNOW-F-0253)で「10より大きい」条件をかけると[16,18]になり、map→filterの順序は「まず全部変換してから絞る」という、filter→mapとは意味の異なる処理になる。
**確認事項**: mapのコールバックの中でAの他の要素を参照したり配列全体を書き換えたりすると、意図しない副作用でバグを生みやすい。変換(x)=x*2をA=[5,3,8,1,9,2]に適用した結果[10,6,16,2,18,4]の合計は10+6+16+2+18+4=56であり、元の合計28のちょうど2倍になっている(検算: 56÷28=2、変換の係数2と一致)。
---
### KNOW-F-0255 reduce(畳み込み)の型
**構造の型**:
```
acc = 初期値
for x of A:
acc = 結合(acc, x)
return acc
```
配列全体を1つの値(合計・最大値・別の配列・オブジェクトなど何でもよい)に畳み込む、最も汎用性の高い集約構造。
**使いどころ**: 合計・積・最大最小・件数のような「配列を1つの値にまとめる」処理全般に使える。ただし可読性が下がりやすいため、単純な合計や件数にはより専用的な処理(組み込みのsum相当)がある場合はそちらを優先する判断も実務では行われる。
**組合せ例**: Aに対し初期値0・結合を加算とするreduceは合計28を返す。初期値1・結合を乗算とすると積2160(5×3×8×1×9×2)になる。畳み込みの結合関数を変えるだけで同じ走査構造から異なる集約結果を得られる点が、他のどの配列操作よりも汎用的である理由になっている。
**確認事項**: 初期値を省略できるreduce実装では、空配列に対して呼び出すとエラーになる場合があるため、初期値は原則として明示する。結合関数が非可換(例: 引き算)の場合、走査順序によって結果が変わる点にも注意する(検算: 加算28と乗算2160はいずれも共通サンプルAの値と手計算で一致することを確認済み)。
---
### KNOW-F-0256 find/findIndex(条件探索)の型
**構造の型**:
```
for i, x of A (添字つき走査):
if 条件(x): return x (findの場合) / return i (findIndexの場合)
return 見つからなければ undefined / -1
```
条件を満たす**最初の**要素またはその添字を返し、見つかった時点で走査を打ち切る構造。
**使いどころ**: 「条件を満たす全部」ではなく「最初の1件」だけが欲しいときに使う。全件が欲しいならfilter(KNOW-F-0253)を、存在の有無だけでよいならsome(KNOW-F-0257)を選ぶほうが意図が明確になる。
**組合せ例**: Aに対し「5より大きい」条件でfindすると最初に条件を満たす8が返り、findIndexなら添字2が返る(A[0]=5は5より大きくないため対象外、A[1]=3も対象外、A[2]=8で条件成立)。見つかった添字をslice(KNOW-F-0261)の起点に使うと「条件成立以降の部分配列」を切り出せる。
**確認事項**: findは全走査より先に打ち切るため、条件判定に副作用がある場合、残りの要素に対してその副作用が発生しない点を見落としやすい。見つからない場合の戻り値(undefinedや-1)を後続処理でそのまま使うと「見つからなかった」を「0番目が見つかった」と誤読するバグになりやすいため、明示的な存在チェックを挟む。
---
### KNOW-F-0257 some/every(存在・全称判定)の型
**構造の型**:
```
some: 1つでも条件(x)が真ならtrueを返し打ち切る
every: 1つでも条件(x)が偽ならfalseを返し打ち切る
```
配列全体を「存在(∃)」または「全称(∀)」の観点で真偽1つに要約する構造。
**使いどころ**: 「1件でも該当すればよい」判定にはsome、「全件が条件を満たす必要がある」判定にはeveryを使う。件数や該当要素そのものが必要ならfind/filterに切り替える。
**組合せ例**: Aに対し「8より大きい」条件でsomeを適用すると9が該当するためtrue、「0より大きい」条件でeveryを適用すると全要素が正であるためtrueになる。「5より大きい」条件でeveryを適用すると3が該当しないためfalseになる(A[1]=3は5より大きくない)。
**確認事項**: 空配列に対してsomeは常にfalse、everyは常にtrueを返すという数学的な取り決め(空虚な真、vacuous truth)があり、直感に反するため誤解しやすい。これはeveryが「反例が1つもない」ことをtrueの根拠にしており、要素が0個なら反例も0個で必ずtrueになる、という論理構造に由来する。
---
### KNOW-F-0258 sort(整列)と比較関数の型
**構造の型**:
```
A.sort((a, b) => a - b) // 昇順(数値)
A.sort((a, b) => b - a) // 降順(数値)
```
比較関数が返す符号(負・零・正)に従って要素の並び順を決める構造。数値のまま比較する場合とは異なり、既定の文字列比較に頼ると数値の大小が崩れる点が最大の罠になる。
**使いどころ**: 表示順・優先順位づけ・後続の二分探索(KNOW-F-0260)の前処理として使う。頻繁に挿入が発生する用途では毎回全体をソートし直すより、挿入位置を探して差し込む設計のほうが効率的な場合がある。
**組合せ例**: Aに比較関数`(a,b)=>a-b`でsortを適用すると[1,2,3,5,8,9]になる。比較関数を渡さず既定の文字列比較でsortすると、"10"<"2"のような桁比較の崩れが起こりうる(1桁の"9"より2桁の"10"が辞書順で先に来る)ため、数値配列には必ず比較関数を明示する。
**確認事項**: `A.sort()`を比較関数なしで数値配列に使うと、要素は文字列化されて比較されるため、たとえば[10,2,1]は[1,10,2]という直感に反する順序になる(検算: 文字列"1"<"10"<"2"の辞書順であり、数値の大小1<2<10とは一致しない)。
---
### KNOW-F-0259 安定ソートの型(同値要素の順序保持)
**構造の型**:
```
R = [{key:2,tag:'X'}, {key:1,tag:'Y'}, {key:2,tag:'Z'}]
R.sort((a,b) => a.key - b.key)
```
比較キーが同じ要素同士については、元の配列での相対順序を変えずに並べ替える性質(安定性)を持つ整列構造。
**使いどころ**: 「部署で並べ替えるが、同じ部署内では入力順(たとえば入社日順)を保ちたい」というような、複数キーの優先順位づけを多段ソートで実現したいときに前提となる性質である。不安定なソートを使うと同キー内の順序が実装依存で崩れる。
**組合せ例**: サンプルR(key=2,1,2の順)をkeyで安定ソートすると、まずkey=1のYが最初に来て、続いてkey=2のXとZが**元の出現順(X→Z)のまま**並ぶため[Y,X,Z]になる。これを「部署でソートしたあと名前でソートし直す」という二段安定ソートに応用すると、部署内が名前順に整った状態を保てる。
**確認事項**: 現代の主要な言語処理系の標準sort実装は安定ソートを既定とすることが多いが、明示的に「不安定」と仕様に書かれた実装や独自実装のクイックソートでは順序が保証されない場合がある。安定性に依存する設計をするなら、使用する処理系の仕様書で明記されているかを確認する。
---
### KNOW-F-0260 二分探索(binary search)の型
**構造の型**:
```
low=0; high=len(A_sorted)-1
while low <= high:
mid = (low+high)/2 (切り捨て)
if A_sorted[mid] == target: return mid
elif A_sorted[mid] < target: low = mid+1
else: high = mid-1
return 見つからず
```
**整列済み**配列に対し、探索範囲を毎回半分に絞り込むことでO(log n)の速さを実現する探索構造。
**使いどころ**: 事前にsort(KNOW-F-0258)済みで、かつ何度も探索を行う場合に威力を発揮する。1回しか探索しないならソートのコストのほうが高くつくため、find(KNOW-F-0256)による線形探索のほうが適切な場合が多い。
**組合せ例**: A_sorted=[1,2,3,5,8,9](Aをsortした結果)からtarget=8を探すと、low=0,high=5でmid=2(値3)は8より小さいためlow=3、次にmid=4(値8)で一致し添字4を返す。線形探索なら5回の比較が必要な位置に、2回の比較で到達している。
**確認事項**: 配列が整列されていない状態で二分探索を使うと、存在する値でも見つからない・存在しない値を誤って見つけるという静かな誤動作を起こす。mid計算で(low+high)を先に足すと、非常に大きな配列では桁あふれ(KNOW-F-0305参照)の理論上の懸念があるため、`low + (high-low)/2`という書き方を使う実装もある。
---
### KNOW-F-0261 slice(非破壊部分抽出)の型
**構造の型**:
```
B = A[start:end] // endは含まない(半開区間)
```
元の配列を変更せず、指定範囲の要素だけをコピーした新しい配列を作る構造。
**使いどころ**: 元の配列を保持したまま部分だけを扱いたいときに使う。元の配列自体を変形してよいならsplice(KNOW-F-0262)のほうが余分なコピーを作らず済む場合がある。
**組合せ例**: Aに対しslice(1,3)を適用すると、添字1と2(3は含まない)を取り出した[3,8]が得られる。slice(0,3)とslice(3,6)を組み合わせるとAを前半[5,3,8]と後半[1,9,2]に分割でき、これはchunk(KNOW-F-0265)の考え方の基礎になっている。
**確認事項**: 終端インデックスは「含まない」半開区間であるため、slice(1,3)の結果の長さは3-1=2であり、「3番目まで含む」と誤解して長さ3を期待するとずれる。負の添字(末尾からの位置)をサポートする実装もあるが、対応の有無は使用する処理系の仕様で確認する。
---
### KNOW-F-0262 splice(破壊的挿入削除)の型
**構造の型**:
```
A.splice(start, deleteCount, ...items)
```
元の配列そのものを変更し、指定位置から指定個数を削除しつつ、任意個の要素を挿入する構造。
**使いどころ**: 配列の途中への挿入・削除をその場で行いたいときに使う。元の配列を保持したい、あるいは複数箇所から同時に参照される配列を不用意に変更したくない場合はスプレッド構文による非破壊コピー(KNOW-F-0263)を使う。
**組合せ例**: Aに対しsplice(2,1,99)を適用すると、添字2の要素(8)を1個削除し、その位置に99を挿入するため、Aは[5,3,99,1,9,2]に変化する。削除だけしたい場合はdeleteCountのみ指定し挿入項目を省略、挿入だけしたい場合はdeleteCountを0にする。
**確認事項**: spliceは元の配列を直接書き換える破壊的操作であるため、他の変数が同じ配列を参照している場合、意図しない箇所にも変更が波及する。戻り値は「削除された要素の配列」であり、変更後の配列そのものではない点も誤解しやすい(splice(2,1,99)の戻り値は[8]であり、[5,3,99,1,9,2]ではない)。
---
### KNOW-F-0263 結合(concat/スプレッド)の型
**構造の型**:
```
C = A.concat(B) // 非破壊結合
C = [...A, ...B] // スプレッド構文による非破壊結合(同じ結果)
```
2つ以上の配列を、元の配列を変更せずに1つの新しい配列へつなぎ合わせる構造。
**使いどころ**: 複数の配列を1本にまとめて後続処理(sort・reduceなど)にかけたいときに使う。要素数が非常に多い配列を頻繁に結合する場合は、都度新しい配列を作るコストが積み重なるため、あらかじめ容量を見積もる設計が有効な場合がある。
**組合せ例**: A=[5,3,8,1,9,2]とB=[10,20,30]をconcatすると[5,3,8,1,9,2,10,20,30](長さ9)になる。続けてsort(KNOW-F-0258)を適用すると[1,2,3,5,8,9,10,20,30]という一本の整列済み配列が得られ、複数のソース由来のデータを1つの整列済みリストにまとめる典型的な流れになる。
**確認事項**: concatやスプレッド構文は浅いコピー(shallow copy)であり、要素がオブジェクトの場合は参照そのものがコピーされるため、結合後の配列の要素を書き換えると元の配列の要素にも影響する。要素ごと独立させたい場合はディープコピー(KNOW-F-0331)を別途行う。
---
### KNOW-F-0264 flat/flatMap(平坦化)の型
**構造の型**:
```
N = [[1,2],[3,[4,5]]]
N.flat(1) // 1段だけ平坦化 -> [1,2,3,[4,5]]
N.flat(2) // 2段まで平坦化 -> [1,2,3,4,5]
```
入れ子になった配列を、指定した深さだけ1段の配列に展開する構造。flatMapはmapとflat(1)を1回の走査で行う合成型である。
**使いどころ**: グループ化(KNOW-F-0328)などで一時的に配列の配列になったデータを、最終的に1本の配列へ戻したいときに使う。深さが不明な木構造を完全に平坦化したい場合は、再帰的なDFS走査(KNOW-F-0333)を使うほうが安全な場合が多い。
**組合せ例**: サンプルN=[[1,2],[3,[4,5]]]にflat(1)を適用すると[1,2,3,[4,5]](内側の[4,5]は1段しか展開されないため残る)、flat(2)を適用すると[1,2,3,4,5]まで展開される。flatMapは例えばmapで各要素xを[x,x*10]という配列に変換してから1段flatする処理を1回でまとめて行える。
**確認事項**: flat()の深さ引数を省略すると1段しか展開されない実装が一般的であり、「全部展開されるはず」という思い込みで多段ネストのデータに深さ指定なしのflatを使うと、内側の配列が残ったまま次の処理に渡ってしまう静かなバグになる。深さが可変・未知のデータにはInfinityに相当する深さ指定か再帰処理を使う。
---
### KNOW-F-0265 chunk(等分割)の型
**構造の型**:
```
B = []
for i = 0; i < len(A); i += size:
B.push(A[i:i+size])
```
配列を指定サイズごとの小さな配列(チャンク)に分割する構造。
**使いどころ**: ページネーション(1ページあたりの表示件数で区切る)や、並列処理のためにデータをバッチへ分けたいときに使う。最後のチャンクはsizeに満たない端数になりうる点を前提に後続処理を設計する。
**組合せ例**: A=[5,3,8,1,9,2](長さ6)をsize=2でchunkすると[[5,3],[8,1],[9,2]]になる。size=4でchunkすると[[5,3,8,1],[9,2]]となり、最後のチャンクは2要素しかない端数チャンクになる(6÷4=1あまり2、あまりの2要素が最後のチャンクに入ることを検算で確認)。
**確認事項**: size=0を指定すると無限ループになる実装があるため、size>=1を事前に検証しておく必要がある。chunkしたあとflat(KNOW-F-0264)を1段適用すると元の配列に戻ることを確認しておくと、往復の整合性を検算できる。
---
### KNOW-F-0266 zip(対応付け結合)の型
**構造の型**:
```
C = []
for i = 0; i < min(len(A), len(B)); i += 1:
C.push([A[i], B[i]])
```
複数の配列の同じ添字同士を1組にまとめ、タプル(組)の配列を作る構造。
**使いどころ**: 「名前の配列」と「点数の配列」のように、別々に持っていた対応関係のあるデータを1本の配列にまとめたいときに使う。長さが異なる配列をzipする場合、短いほうに合わせて余りを切り捨てるか、足りない側をnullで埋めるかを事前に決めておく。
**組合せ例**: A=[5,3,8,1,9,2](長さ6)とB=[10,20,30](長さ3)をzipすると、短いBの長さに合わせて[[5,10],[3,20],[8,30]]の3組が得られる。続けてmap(KNOW-F-0254)で各組の合計を取ると[15,23,38]になり、対応する2系列のデータをまとめて集計する典型的な流れになる。
**確認事項**: zipは長さの短い側で打ち切られる実装と、長い側に合わせてnullで埋める実装があり、どちらの仕様かを確認せずに使うとデータの欠落や意図しないnullの混入に気づかないまま後続処理が進むことがある。上の例では長さ6のAのうち後半3要素(1,9,2)が結果に含まれない点を必ず確認する。
---
### KNOW-F-0267 unique(重複除去)の型
**構造の型**:
```
seen = {} (集合)
B = []
for x of A:
if x not in seen: seen.add(x); B.push(x)
```
配列から重複する値を取り除き、初出順を保ったまま一意な値だけの配列を作る構造。
**使いどころ**: IDの一覧から重複を除いて件数を数えたい、選択肢の候補から同じ値を1つにまとめたいときに使う。順序を保つ必要がないなら集合(Set)型へ変換するだけで済む場合もある。
**組合せ例**: サンプル配列D=[1,2,2,3,3,3]にuniqueを適用すると[1,2,3]になる。続けてlength(要素数)を取ると3であり、「元の配列の長さ6から重複除去後の長さ3を引いた3が、重複によって除去された要素の個数」という関係が成り立つ(検算: 6-3=3)。
**確認事項**: オブジェクトの配列に単純なuniqueを適用すると、内容が同じでも参照が異なるため「別物」と判定され重複除去できない場合がある。この場合はキー(id等)を基準にした索引作り(KNOW-F-0329)と組み合わせて、キーの一意性で判定する設計に切り替える。
---
### KNOW-F-0268 集合演算(union/intersection/difference)の型
**構造の型**:
```
union(X,Y) = XとYのどちらかに含まれる要素の集合
intersection(X,Y) = XとYの両方に含まれる要素の集合
difference(X,Y) = Xに含まれ、Yに含まれない要素の集合
```
2つの配列を集合とみなし、和・積・差という3つの基本演算で新しい集合を作る構造。
**使いどころ**: 「両方のリストに載っている人」「片方にしかいない人」のような比較処理に使う。件数が多い場合は、両方を配列のまま二重ループで比較すると要素数の積に比例して遅くなるため、片方を索引作り(KNOW-F-0329)してから照合すると速い。
**組合せ例**: X=[1,2,3,4]、Y=[3,4,5,6]とすると、union(X,Y)=[1,2,3,4,5,6]、intersection(X,Y)=[3,4]、difference(X,Y)=[1,2](Xのうち3,4はYにも含まれるため除外)になる。これらは|union|=|X|+|Y|-|intersection|という関係で検算でき、4+4-2=6となりunionの要素数6と一致する。
**確認事項**: difference(X,Y)とdifference(Y,X)は対称ではない(前者は[1,2]、後者は[5,6])ため、引数の順序を取り違えると逆の結果になる。集合演算である以上、元の配列内に重複があった場合の扱い(結果からも重複を除くかどうか)を事前に決めておく。
---
### KNOW-F-0269 reverse(逆順)の型
**構造の型**:
```
B = []
for i = len(A)-1; i >= 0; i -= 1:
B.push(A[i])
```
配列の要素順を先頭と末尾から入れ替えるようにして、完全に逆向きにする構造。
**使いどころ**: 新しい順に並んだログを古い順に表示し直したい、あるいはその逆をしたいときに使う。末尾からの走査だけで済むならreverseで新しい配列を作らず、末尾から直接forループで走査するほうが余分なコピーを避けられる。
**組合せ例**: A=[5,3,8,1,9,2]をreverseすると[2,9,1,8,3,5]になる。reverseを2回適用すると元の配列に戻ることが恒等性の検算になる([2,9,1,8,3,5]を再度reverseすると[5,3,8,1,9,2]で元と一致)。
**確認事項**: 実装によってはreverseが元の配列を直接書き換える破壊的操作である場合があり、spliceと同様に他の参照箇所への影響を確認する必要がある。非破壊にしたい場合はスプレッド構文で複製してからreverseする([...A].reverse())。
---
### KNOW-F-0270 shuffle(Fisher-Yatesの型)
**構造の型**:
```
for i = len(A)-1; i > 0; i -= 1:
j = 乱数(0からiの範囲)
A[i], A[j] = A[j], A[i] // 交換
```
末尾から先頭に向かって、まだ確定していない範囲からランダムに選んだ要素と交換していくことで、すべての並び順が等確率で出現するように並べ替える構造。
**使いどころ**: カードや出題順のシャッフルのように、真にランダムな並び替えが必要なときに使う。単純に「ランダムな数で比較してsort」する実装は各並びの出現確率が均等にならない場合があり、公平性が必要な場面では避ける。
**組合せ例**: A=[5,3,8,1,9,2]に対し、乱数列としてi=5でj=1、i=4でj=4、i=3でj=0、i=2でj=2、i=1でj=0を引いたと仮定して逐次交換を追うと、[5,3,8,1,9,2]→(i=5,j=1交換)[5,2,8,1,9,3]→(i=4,j=4交換なし)→(i=3,j=0交換)[1,2,8,5,9,3]→(i=2,j=2交換なし)→(i=1,j=0交換)[2,1,8,5,9,3]という最終結果になる。
**確認事項**: ループの範囲をi>0ではなくi>=0にすると、範囲(0からiまで)が常に1要素しかない交換(自分自身との交換)が余分に発生するだけで結果は変わらないが、逆にjの範囲を「0からlen(A)-1」のように全体から選ぶ誤実装をすると、均等な確率でシャッフルされない(Fisher-Yatesでない別の分布になる)ことが知られているため、jの範囲は必ず「0からiまで」に限定する。
---
### KNOW-F-0271 range(範囲生成)の型
**構造の型**:
```
B = []
for i = start; i < end; i += step:
B.push(i)
```
開始値・終了値・刻み幅から、等差数列の配列を生成する構造。終了値は含まない半開区間を既定とする実装が多い。
**使いどころ**: 添字の並びやテスト用の連番データを手で書き並べる代わりに生成したいときに使う。既存の配列から連番を作る必要はなく、あくまで「値そのものが不要で連番の並びだけが欲しい」場面に限定して使う。
**組合せ例**: range(1,5)は終了値5を含まないため[1,2,3,4]になる。range(0,10,2)のように刻み幅2を指定すると[0,2,4,6,8]という偶数列が得られ、これはfilter(KNOW-F-0253)で「2で割り切れる」条件をかけた結果と一致することを検算できる。
**確認事項**: 終了値を含むか含まないかは実装によって異なる場合があるため、range(1,5)が[1,2,3,4]なのか[1,2,3,4,5]なのかを使用する処理系の仕様で必ず確認する。刻み幅を0にすると無限ループになる典型的な罠がある。
---
### KNOW-F-0272 prefix sum(累積和)の型
**構造の型**:
```
S = [A[0]]
for i = 1; i < len(A); i += 1:
S.push(S[i-1] + A[i])
```
配列の先頭からi番目までの合計を、あらかじめ全添字について計算しておく構造。
**使いどころ**: 「区間[l,r)の合計」を何度も問い合わせる場合、毎回その区間を走査すると遅いが、累積和を1回だけ前計算しておけばS[r-1]-S[l-1]という引き算だけで区間和が求まる。1回しか合計を使わないなら前計算のコストが無駄になる。
**組合せ例**: A=[5,3,8,1,9,2]の累積和は[5,8,16,17,26,28]になる(5, 5+3=8, 8+8=16, 16+1=17, 17+9=26, 26+2=28)。添字1から3まで(値3,8,1)の区間和を求めたい場合、S[3]-S[0]=17-5=12となり、実際に3+8+1=12と一致することを検算できる。
**確認事項**: 区間和の引き算で使う添字は「累積和配列のどこからどこまでを引くか」で1つずれる誤りが起こりやすいため、必ず小さな具体例(上の12の検算のような)で境界を確認してから本番のデータに適用する。
---
### KNOW-F-0273 スタック操作(LIFO)の型
**構造の型**:
```
stack.push(x) // 末尾に積む
stack.pop() // 末尾を取り出す(最後に積んだものが最初に出る)
```
最後に入れたものが最初に出る(Last In, First Out)という規律を持つ、配列の末尾だけを使った操作構造。
**使いどころ**: 元に戻す操作(undo)の履歴管理や、対応する括弧の検査、深さ優先探索(KNOW-F-0333)の反復実装のように「直前の状態に戻る」性質が必要な処理に使う。
**組合せ例**: 空のスタックにpush(5), push(3), push(8)の順で積むと内部は[5,3,8]になり、続けてpopを1回呼ぶと8が返り内部は[5,3]に戻る。この「最後に積んだ8が最初に出る」性質を使うと、括弧列"(()"のような文字列の対応チェック(KNOW-F-0358のネスト構造検証と関連)が実装できる。
**確認事項**: 空のスタックに対してpopを呼ぶとエラーになるか、undefined相当の値が返るかは実装によって異なるため、pop前には必ず空でないことを確認する。push/popを配列の先頭で行うと要素の移動コストがかかり末尾操作より遅くなる実装が多いため、スタックは末尾操作で統一する。
---
### KNOW-F-0274 キュー操作(FIFO)の型
**構造の型**:
```
queue.push(x) // 末尾に追加(enqueue)
queue.shift() // 先頭を取り出す(dequeue、最初に入れたものが最初に出る)
```
最初に入れたものが最初に出る(First In, First Out)という規律を持つ、配列の両端を使う操作構造。
**使いどころ**: 順番待ちの処理(印刷待ち、タスクの順次実行)や、幅優先探索(KNOW-F-0334)のように「入れた順番のまま処理したい」場面で使う。
**組合せ例**: 空のキューにenqueue(5), enqueue(3), enqueue(8)の順で追加すると内部は[5,3,8]になり、続けてdequeueを1回呼ぶと最初に入れた5が返り内部は[3,8]に戻る。スタック(KNOW-F-0273)のpopが末尾の8を返すのに対し、キューのdequeueは先頭の5を返すという対比が両者の本質的な違いになる。
**確認事項**: 配列の先頭からの取り出し(shift相当)は、残った要素すべてを1つずつ前へ詰め直すコストがかかる実装が多く、大量の要素を扱う場面では両端キュー専用のデータ構造を使うほうが効率的な場合がある。用途が単発の少量処理であれば配列のshiftで十分実務上問題にならない。
---
### KNOW-F-0275 配列操作の型まとめ(第1章・分類比較表)
**構造の型(章内の分類表)**:
| 分類 | 該当KNOW-F | 元配列を変更するか |
|---|---|---|
| 走査 | 0251, 0252 | しない(副作用は処理内容次第) |
| フィルタ/写像/畳み込み | 0253, 0254, 0255 | しない(新しい配列・値を返す) |
| 探索 | 0256, 0257, 0260 | しない |
| 整列 | 0258, 0259 | 実装により破壊/非破壊が分かれる |
| 部分抽出/挿入削除 | 0261, 0262 | sliceは非破壊、spliceは破壊的 |
| 結合/平坦化/分割 | 0263, 0264, 0265, 0266 | しない(新しい配列を返す) |
| 集合演算/重複除去/逆順/乱択 | 0267, 0268, 0269, 0270 | reverseのみ実装依存で破壊的な場合あり |
| 生成/累積 | 0271, 0272 | しない(新しい配列を返す) |
| スタック/キュー | 0273, 0274 | する(末尾または先頭を直接変更) |
**使いどころ(章全体の使い分け方針)**: 「元の配列を変えてよいか」が最初の分岐点であり、他の変数から同じ配列が参照されている可能性があるなら非破壊操作(slice・concat・スプレッド構文)を優先する。次に「1件だけ欲しいか(find/some)」「全件を絞りたいか(filter)」「形を変えたいか(map)」「1つの値にまとめたいか(reduce)」という目的で系統を選ぶ。
**組合せ例(代表的な組合せの並記)**: filter→map(KNOW-F-0253→0254)で絞ってから変換、sort→binary search(KNOW-F-0258→0260)で整列してから高速探索、chunk→flat(KNOW-F-0265→0264)で分割してから復元、という3つの往復が第1章全体を通じて繰り返し登場する基本パターンである。
**確認事項(章全体で共有される検証原則)**: 配列操作全般で最も多いバグは「破壊的操作と非破壊操作の取り違え」と「添字の境界(含む/含まない)の思い違い」の2つである。共通サンプルA=[5,3,8,1,9,2](合計28)を使って、各操作の前後で長さと合計がどう変わるかを都度検算する習慣が、第1章全体の結びとして特に重要になる。
---
---
## 第2章 文字列処理の型(KNOW-F-0276〜0300)
文字列は「文字が並んだ配列」に見えて、実際には改行コード・全角半角・Unicodeの結合文字・サロゲートペアといった、配列とは異なる固有の罠を多く抱える構造である。第2章では共通サンプルS=" Hello, World! "(前後に半角空白2つずつ、trim後の中身は13文字)を軸に、分解・正規化・エスケープ・テンプレートという4系統を24種の型として並べる。
### KNOW-F-0276 split(分割)の型
**構造の型**:
```
B = S.split(区切り文字)
```
文字列を指定した区切り文字(または正規表現)で切り分け、文字列の配列を作る構造。
**使いどころ**: CSVの1行をカンマで分けたい、文章を単語ごとに分けたいときに使う。区切り文字が複数種類ある、あるいは区切り文字自体が引用符の中に含まれる可能性がある場合は、単純なsplitではなくCSVエスケープ(KNOW-F-0294)を考慮した専用の解析が必要になる。
**組合せ例**: S.trim()で前後の空白を除いた"Hello, World!"をカンマで分割すると["Hello"," World!"](2番目の要素の先頭に空白が残る)になる。続けてtrim(KNOW-F-0278)を各要素にmap(KNOW-F-0254)適用すると["Hello","World!"]という整った配列が得られる。
**確認事項**: 区切り文字が見つからない場合、splitは元の文字列1つだけを含む配列を返す(空配列にはならない)。区切り文字を空文字""にすると1文字ずつに分解される実装が多く、意図せず全文字分解になっていないか確認する。
---
### KNOW-F-0277 join(結合)の型
**構造の型**:
```
S2 = ["a","b","c"].join(区切り文字)
```
文字列の配列を、指定した区切り文字を挟みながら1本の文字列に結合する構造。splitの逆操作にあたる。
**使いどころ**: 配列で保持していたデータを表示用の1本の文字列に戻したいときに使う。区切り文字なしで単純に連結したいだけなら区切り文字に空文字""を渡す。
**組合せ例**: ["Hello","World!"]をjoin(", ")で結合すると"Hello, World!"になり、これはKNOW-F-0276でsplit(",")した結果(の整形版)を再結合すると元の内容に戻ることを確認する往復検算になる。
**確認事項**: 配列の要素がnullやundefinedを含む場合、多くの実装では空文字として扱われるため、["a",null,"b"].join("-")は"a--b"のように区切り文字だけが並ぶ箇所ができる。意図しない空要素が混入していないか事前に確認する。
---
### KNOW-F-0278 trim(前後空白除去)の型
**構造の型**:
```
S2 = S.trim() // 前後両方
S2 = S.trimStart() // 先頭のみ
S2 = S.trimEnd() // 末尾のみ
```
文字列の先頭・末尾にある空白文字(半角スペース・タブ・改行など)を取り除く構造。
**使いどころ**: ユーザーが入力フォームに余分な空白を含めて入力した値を正規化したいときに使う。文字列の途中にある連続空白を1つにまとめたい場合はtrimではなく正規表現置換(KNOW-F-0286)が必要になる。
**組合せ例**: 共通サンプルS=" Hello, World! "(前後に半角空白2つずつ、全長17文字)にtrimを適用すると"Hello, World!"(13文字)になる。除去された文字数は17-13=4であり、前後2つずつの空白の合計と一致することを検算できる。
**確認事項**: trimは文字列の「両端」だけを対象とし、文中の空白には触れない。全角スペース(U+3000)を空白として扱うかどうかは実装によって差があるため、日本語混じりの入力を扱う場合は全角半角正規化(KNOW-F-0296)を先に行っておくと挙動が安定する。
---
### KNOW-F-0279 大文字小文字正規化の型
**構造の型**:
```
S2 = S.toLowerCase() // 全て小文字化
S2 = S.toUpperCase() // 全て大文字化
```
アルファベットの大文字と小文字の表記ゆれを1種類にそろえる構造。
**使いどころ**: ユーザーIDやメールアドレスの一致判定のように、大文字小文字を区別したくない比較の前処理として使う。表示上の見た目を変える目的(タイトルケース化など)には専用の変換が別途必要になる。
**組合せ例**: "Hello, World!"をtoLowerCase()すると"hello, world!"になる。2つの文字列"World"と"WORLD"を単純比較すると不一致だが、両方をtoLowerCase()してから比較すると"world"同士で一致する、というのが大文字小文字を無視した比較の標準的な組合せ方である。
**確認事項**: 一部の言語(トルコ語の"I"と"i"の対応など)では単純なtoLowerCase/toUpperCaseが期待通りの結果にならない場合があるとされ、多言語対応が必要なシステムではロケールを指定する変換関数の使用を検討する。
---
### KNOW-F-0280 Unicode正規化(NFC/NFD)の型
**構造の型**:
```
S2 = S.normalize("NFC") // 合成済み形式へ統一(1文字1コードポイント)
S2 = S.normalize("NFD") // 分解形式へ統一(基底文字+結合文字)
```
見た目が同じ文字でも内部表現が複数通りありうるUnicode文字列を、決められた1つの形式に統一する構造。
**使いどころ**: 「é」のような合成文字を含む文字列の一致判定・検索・ソートを行う前に必ず適用する。正規化せずに比較すると、見た目が同じでも内部のコードポイント列が異なるため不一致と判定される静かなバグを生む。
**組合せ例**: "é"はNFC形式では1コードポイント(U+00E9)で表現されるが、NFD形式では基底文字"e"(U+0065)と結合用アクセント記号(U+0301)の2コードポイントに分解される。同じ見た目の文字列でも、片方がNFC・もう片方がNFDで保存されていると、正規化前は文字数(length)が1と2で異なり、単純な等値比較(===)は失敗する。
**確認事項**: ファイルシステムやOSによって既定の正規化形式が異なる場合がある(特に日本語・アクセント記号を含む多言語環境)。外部から受け取った文字列を検索キーや一意キーとして使う前には、必ず同じ正規化形式(通常はNFC)にそろえてから比較・保存する。
---
### KNOW-F-0281 HTMLエスケープの型
**構造の型**:
```
置換表: & -> &, < -> <, > -> >, " -> ", ' -> '
```
文字列中のHTML特殊文字を、画面上に文字そのものとして表示されるよう安全な表記に置き換える構造。置換の順序が重要で、&(アンパサンド)を最初に変換しないと、後から追加した<等の&まで二重にエスケープされてしまう。
**使いどころ**: ユーザーが入力した文字列をWebページに埋め込んで表示する直前に必ず適用する。埋め込み先がHTML属性値なのかテキストノードなのか、あるいはJavaScriptの文字列リテラル内なのかによって必要なエスケープ規則が異なる点に注意する。
**組合せ例**: 入力文字列"<div>"をHTMLエスケープすると"<div>"になり、ブラウザ上では危険なタグとして解釈されず、文字どおり"<div>"という文字列が表示される。この処理を怠ると、悪意ある入力によって想定外のタグやスクリプトがページに挿入される脆弱性(クロスサイトスクリプティング)につながるとされる。
**確認事項**: 置換の順序を誤ると二重エスケープが起こる。"<"という文字列(すでにエスケープ済み)に対して再度エスケープをかけると"&lt;"となり画面には"<"という文字そのものが表示されてしまう。エスケープは「一度だけ、出力の直前で」行うのが原則である。
---
### KNOW-F-0282 アンエスケープ(デコード)の型
**構造の型**:
```
置換表(逆): & -> &, < -> <, > -> >, " -> ", ' -> '
```
HTMLエスケープ(KNOW-F-0281)された文字列を元の文字に戻す、エスケープの逆操作にあたる構造。こちらは&を**最後**に変換しないと、他の実体参照の一部を誤って壊してしまう。
**使いどころ**: 外部APIやファイルから受け取ったエスケープ済みの文字列を、プログラム内部で元のテキストとして扱いたいときに使う。信頼できない入力をアンエスケープしてから別の出力先(SQL文字列など)にそのまま埋め込むと、エスケープの意味がなくなる点に注意する。
**組合せ例**: "<div>"をアンエスケープすると"<div>"に戻る。KNOW-F-0281のエスケープとKNOW-F-0282のアンエスケープを続けて適用すると元の文字列に戻る(往復性)ことが、実装の正しさを確かめる基本的な検算になる。
**確認事項**: HTMLの実体参照には&のような名前つき参照のほかに、'や'のような数値参照(10進・16進)もあり、両方に対応していないと一部の文字だけがデコードされずに残る。対応範囲を確認事項として明記しておく。
---
### KNOW-F-0283 テンプレート文字列補間の型
**構造の型**:
```
name = "World"
S2 = `Hello, ${name}!` // ${...}の中の式を評価して埋め込む
```
文字列リテラルの中に変数や式を直接埋め込み、実行時に評価した値へ置き換える構造。
**使いどころ**: 文字列の連結(+演算子の繰り返し)よりも読みやすく書きたいときに使う。埋め込む値がユーザー入力由来でHTML等に出力される場合は、テンプレート補間そのものがエスケープを行うわけではない点に注意し、必要ならHTMLエスケープ(KNOW-F-0281)を別途組み合わせる。
**組合せ例**: name="World"のとき`Hello, ${name}!`を評価すると"Hello, World!"になり、共通サンプルSをtrimしたものと一致する(検算: trim(S)="Hello, World!"、補間結果も"Hello, World!"で完全一致)。式の部分には`${1+2}`のような計算式も書け、この場合は評価結果の"3"が文字列として埋め込まれる。
**確認事項**: テンプレート補間は自動でエスケープを行わない実装が多いため、ユーザー入力をそのままHTMLのテンプレートに埋め込むとクロスサイトスクリプティングの経路になりうる。埋め込み先の文脈に応じたエスケープ(KNOW-F-0281)を必ず挟む。
---
### KNOW-F-0284 部分文字列抽出(substring)の型
**構造の型**:
```
S2 = S.substring(start, end) // endは含まない(半開区間)
```
文字列の指定した添字範囲だけを取り出す構造。配列のslice(KNOW-F-0261)の文字列版にあたる。
**使いどころ**: 固定長のコードの一部(先頭3文字を種別コードとして扱う等)を取り出したいときに使う。区切り文字を基準に取り出したいならsplit(KNOW-F-0276)や正規表現マッチ(KNOW-F-0287)のほうが適切な場合が多い。
**組合せ例**: "Hello, World!"(添字0始まり、H=0,e=1,...,W=7,o=8,r=9,l=10,d=11,!=12)に対しsubstring(7,12)を適用すると添字7〜11の文字"World"が得られる。substring(0,5)なら"Hello"が得られ、これはsplit(",")の最初の要素と一致する。
**確認事項**: substringは負の値や開始>終了のような不正な引数を渡しても例外を投げず、内部で値を入れ替えたり0に丸めたりして動作を継続する実装が多く、意図しない範囲を静かに返すことがある。境界値は具体例で必ず検算する。
---
### KNOW-F-0285 検索(indexOf/includes)の型
**構造の型**:
```
i = S.indexOf(part) // 見つかった開始位置、なければ-1
has = S.includes(part) // 含むかどうかの真偽値
```
文字列中に指定した部分文字列が含まれるか、含まれるならどこにあるかを調べる構造。
**使いどころ**: 存在の有無だけでよいならincludes、位置(添字)も必要ならindexOfを使う。パターンが固定の文字列でなく可変のルール(数字だけ、特定の形式だけ)であれば正規表現マッチ(KNOW-F-0287)に切り替える。
**組合せ例**: "Hello, World!".indexOf("World")は7を返し、これはKNOW-F-0284のsubstring(7,12)="World"の開始位置と一致する(検算: indexOfで求めた添字をそのままsubstringの引数に使うと元の部分文字列を再現できる)。
**確認事項**: indexOfは見つからない場合-1を返すため、`if (S.indexOf(part))`のように戻り値を単純な真偽値として扱うと、位置0で見つかった場合(0は偽と評価される言語がある)を「見つからなかった」と誤判定するバグになりうる。存在確認にはincludesを使うほうが誤読を避けられる。
---
### KNOW-F-0286 置換(replace/replaceAll)の型
**構造の型**:
```
S2 = S.replace(part, newPart) // 最初の1箇所だけ置換
S2 = S.replaceAll(part, newPart) // 見つかった全箇所を置換
```
文字列中の指定パターンを別の文字列に置き換える構造。
**使いどころ**: 特定の単語をすべて置き換えたい(replaceAll)のか、最初の1箇所だけでよいのか(replace)を明確に区別して使う。連続する空白を1つにまとめたいときは正規表現(KNOW-F-0287)と組み合わせて`replaceAll(/\s+/g, " ")`のような使い方をする。
**組合せ例**: "Hello, World!".replace("World", "PC")は"Hello, PC!"になる。この置換結果は共通サンプルSの内容とは意味的に対をなす例であり、テンプレート補間(KNOW-F-0283)の`Hello, ${name}!`にname="PC"を渡した結果とも一致する。
**確認事項**: replaceに正規表現を渡さず文字列をそのまま渡した場合、多くの実装では最初の1箇所しか置換されない(replaceAllとの取り違えが典型的なバグ)。置換対象の文字列に正規表現の特殊文字(.や*など)が含まれる場合、意図せずパターンとして解釈されないよう注意する。
---
### KNOW-F-0287 正規表現マッチの型
**構造の型**:
```
m = S.match(/\d+/) // 最初の1致のみ
ms = S.matchAll(/\d+/g) // すべての一致(gフラグ必須)
```
文字列の中からパターンに一致する部分を検出する構造。パターンは固定の文字列ではなく「数字の連続」「英字で始まる」といった規則で指定できる。
**使いどころ**: 固定文字列の検索ではカバーできない、形式による検索(郵便番号らしき並び、メールアドレスらしき並びなど)に使う。過度に複雑な正規表現は可読性と実行速度の両面で問題になりやすく、複数の単純な検証(KNOW-F-0355の正規表現フォーマット検査)に分解する設計も検討する。
**組合せ例**: 文字列"abc123def456"に対し/\d+/(数字の連続)でmatchを適用すると最初の一致"123"が得られる。matchAllを使うと"123"と"456"の両方が得られ、続けてmap(KNOW-F-0254)で数値化すると[123,456]という配列になる。
**確認事項**: matchAllを使うにはグローバルフラグ(g)を正規表現に付ける必要があり、付け忘れると実行時エラーになる実装がある。正規表現の`.`は既定で改行にマッチしない、`^`と`$`は複数行モードでないと文字列全体の先頭・末尾を指す、といった仕様の細部は事前にドキュメントで確認する。
---
### KNOW-F-0288 パディング(padStart/padEnd)の型
**構造の型**:
```
S2 = "7".padStart(3, "0") // "007"
S2 = "7".padEnd(3, "0") // "700"
```
文字列が指定した長さに満たない場合、指定した文字を先頭または末尾に詰めて長さをそろえる構造。
**使いどころ**: 連番の桁数をそろえて表示したい(001, 002, ...)、固定幅のログ列を整形したいときに使う。数値そのものの桁数を変えるわけではなく、あくまで表示用の文字列としての整形である点を混同しない。
**組合せ例**: 数値7を文字列化して"7".padStart(3,"0")を適用すると"007"になる。連番1〜12をこの型で整形すると"001"〜"012"という3桁固定のIDが得られ、sort(KNOW-F-0258)を文字列比較のまま適用しても"010"が"09"より辞書順で正しく後ろに来る(桁数をそろえたことで文字列比較でも数値順と一致する)という副次的な利点が生まれる。
**確認事項**: 目標の長さより元の文字列がすでに長い場合、padStart/padEndは何も変更せず元の文字列をそのまま返す(切り詰めは行わない)。桁あふれ的な文字列(たとえば"12345"を3桁にパディングしようとする)を渡していないか、事前に長さを検証しておく。
---
### KNOW-F-0289 数値の書式整形の型
**構造の型**:
```
S2 = n.toFixed(2) // 小数点以下2桁固定 "3.14"
S2 = n.toLocaleString() // 桁区切り "1,234,567"
```
数値を、人間が読みやすい表記(小数点以下の桁数固定、3桁ごとの区切りなど)の文字列に変換する構造。
**使いどころ**: 画面に金額や統計値を表示する直前の最終整形として使う。整形後の文字列を再び計算に使ってはならない点が重要で、計算は常に整形前の数値(あるいは第3章で扱う整数演算への還元)で行う。
**組合せ例**: 数値1234567に対しtoLocaleString()を適用すると"1,234,567"になる。数値3.14159にtoFixed(2)を適用すると"3.14"になり、これは四捨五入/切り捨て/切り上げの型(KNOW-F-0302)のうち四捨五入に相当する丸めを内部で行っていることに注意する(3.14159の小数第3位5は切り上げの対象になり3.14ではなく3.142→3.14…実際には3桁目が1なので3.142への影響はなく3.14が正しい)。
**確認事項**: toFixed(2)は丸めた「文字列」を返すのであって数値ではないため、その戻り値をそのまま次の計算に使うと暗黙の型変換によるずれが生じうる。桁区切りの区切り文字(カンマかピリオドか)は表示するロケールによって異なるため、国際化対応が必要なシステムでは明示的にロケールを指定する。
---
### KNOW-F-0290 サロゲートペア対応の型
**構造の型**:
```
len_naive = S.length // UTF-16のコード単位数(絵文字は2とカウントされうる)
len_true = [...S].length // イテレータ経由でコードポイント単位に数える
```
基本多言語面(BMP)を超える文字(多くの絵文字など)を、内部表現の都合(UTF-16では1文字が2つのコード単位=サロゲートペアで表される)を踏まえて正しく数える構造。
**使いどころ**: 絵文字を含む文字列の「見た目の文字数」を正確に数えたい、あるいは文字列を安全に途中で区切りたい(サロゲートペアの片方だけを切り離すと文字化けする)ときに使う。
**組合せ例**: 絵文字" "は単純な.length参照では2という値になる(UTF-16のサロゲートペアとして2コード単位で表現されるため)が、スプレッド構文でコードポイント単位に展開してから数えると1になる。"a b"という文字列ではlen_naive=4(a=1, =2,b=1)、len_true=3(a, ,b)となり、差の1がサロゲートペアの余剰分と一致する。
**確認事項**: substring(KNOW-F-0284)のような添字ベースの操作をサロゲートペアの途中で行うと、片方のコード単位だけが切り出され、表示が崩れた文字(いわゆる文字化けの一種)になる。絵文字や一部の異体字を扱う文字列を切り詰める処理では、コードポイント単位での操作を優先する。
---
### KNOW-F-0291 改行コード正規化の型
**構造の型**:
```
S2 = S.replaceAll("\r\n", "\n").replaceAll("\r", "\n")
```
Windows由来の改行(CRLF、\r\n)やMac Classic由来の改行(CR、\r)を、Unix由来の改行(LF、\n)のような単一の表現に統一する構造。置換の順序を守り、CRLFを先に処理してから単独のCRを処理する。
**使いどころ**: 異なるOSで作成されたテキストファイルを取り込んで行数を数えたい、行ごとに分割したい(split("\n"))ときに、事前に必ず適用する。
**組合せ例**: "行1\r\n行2\r行3\n"のような混在改行の文字列に本型を適用すると"行1\n行2\n行3\n"に統一され、続けてsplit("\n")すると["行1","行2","行3",""]という一貫した行の配列が得られる(末尾の空文字列は最後の改行の後に何もないことを示す)。
**確認事項**: 正規化を行わずにsplit("\n")だけを実行すると、CRLFで保存されたファイルでは各行の末尾に見えない"\r"が残り、後続の等値比較やtrim漏れの原因になる(trimは前後の空白文字として\rも除去対象になる実装が多いため、trimと組み合わせれば影響を軽減できる場合もある)。
---
### KNOW-F-0292 URLエンコード/デコードの型
**構造の型**:
```
S2 = encodeURIComponent(S) // 特殊文字を%XX形式に変換
S2 = decodeURIComponent(S2) // 元に戻す
```
URLの一部として安全に使えない文字(空白、&、日本語などの非ASCII文字)を、%記号に続く16進数の並びに変換する構造。
**使いどころ**: 検索キーワードや任意の文字列をURLのクエリパラメータに埋め込みたいときに使う。URL全体(スキームやパス区切りの/を含む)をまとめてエンコードすると、必要な区切り文字まで壊れてしまうため、パラメータの値の部分だけに適用する。
**組合せ例**: 文字列"a b&c"にencodeURIComponentを適用すると空白は"%20"、&は"%26"に変換され"a%20b%26c"になる。decodeURIComponentで元に戻すと"a b&c"に一致することが往復検算になる。
**確認事項**: 空白の変換方式には%20方式と+(プラス記号)方式の2つの慣習があり、フォーム送信(application/x-www-form-urlencoded)では+が使われる場合があるため、どちらの慣習で送られたデータかを事前に確認しないとデコード結果に空白の代わりに+が残るバグになる。
---
### KNOW-F-0293 Base64エンコード/デコードの型
**構造の型**:
```
S2 = base64encode(S) // バイト列を64種の印字可能文字だけの表現に変換
S2 = base64decode(S2) // 元のバイト列に戻す
```
任意のバイト列(画像データなど、そのままではテキストとして扱いにくいデータ)を、64種類の英数字と記号だけで表現し直す構造。3バイトの入力を4文字の出力に変換する規則を持つ。
**使いどころ**: 画像やバイナリデータをJSONやXMLのようなテキストベースの形式に埋め込みたいときに使う。文字列としてのサイズは元のバイト列よりおよそ4/3(約33%)大きくなる点をデータ量の見積もりに含める。
**組合せ例**: 文字列"Hello"(5バイト、ASCII)をBase64エンコードすると"SGVsbG8="になる(末尾の"="はパディング記号で、3の倍数バイトに満たない端数を埋めている)。デコードすると"Hello"に戻ることが往復検算になる。
**確認事項**: Base64は暗号化ではなく単なる表現の変換であり、誰でも同じ規則でデコードできるため、機密情報をBase64化しただけで安全になったと誤解しないよう注意する。パディング記号"="の有無を要求する・しないの違いは実装によって差があるため、外部システムと連携する際は仕様を確認する。
---
### KNOW-F-0294 CSVエスケープの型
**構造の型**:
```
if フィールドがカンマ・改行・二重引用符を含む:
フィールド内の " を "" に置換し、全体を " で囲む
```
CSV(カンマ区切り値)形式で、フィールドの値自体にカンマや改行、引用符が含まれる場合に、区切り文字と値の中身を区別できるようにする構造。
**使いどころ**: 表計算ソフトやデータベースからエクスポートしたデータをCSVとして書き出すときに使う。読み込み側もこの規則(ダブルクォートのエスケープは""という2つの引用符で表す)に対応している必要があり、単純なsplit(",")だけでは正しく読み戻せない。
**組合せ例**: フィールドの値`Say "Hi", please`(カンマと二重引用符を含む)をCSVエスケープすると、内部の`"`を`""`に置換したうえで全体を`"`で囲み、`"Say ""Hi"", please"`という1つのCSVフィールドになる。この1フィールドをCSVパーサーで読み戻すと元の`Say "Hi", please`に一致する。
**確認事項**: 単純に「カンマを含むかどうか」だけを見て引用符で囲むかを判断すると、改行や二重引用符を含む場合を見落とす。CSVの改行コード(KNOW-F-0291参照)がフィールド内に含まれる場合、そのフィールドを引用符で囲まないと行の区切りと誤認されてデータが壊れる。
---
### KNOW-F-0295 JSON文字列化エスケープの型
**構造の型**:
```
置換表: " -> \", \ -> \\, 改行 -> \n, タブ -> \t, 制御文字 -> \uXXXX
```
JSON形式の文字列リテラルとして安全に埋め込めるよう、二重引用符・バックスラッシュ・制御文字を所定のエスケープシーケンスに変換する構造。多くの言語では標準ライブラリのJSON変換関数がこの処理を自動で行う。
**使いどころ**: 手組みでJSON文字列を組み立てる場面(標準のJSON変換関数が使えない特殊な環境など)で必要になる。通常は自前でエスケープを実装せず、信頼できる標準のJSON変換関数に任せるのが安全である。
**組合せ例**: 文字列`He said "hi"`をJSON文字列としてエスケープすると`He said \"hi\"`になり、これを二重引用符で囲んだ`"He said \"hi\""`が正しいJSON文字列リテラルになる。改行を含む文字列`行1\n行2`(実際の改行文字)は、JSON上では`行1\\n行2`のようにバックスラッシュとnの2文字に変換される(実際の改行文字ではなく、改行を表す2文字のエスケープシーケンスになる)点に注意する。
**確認事項**: 手組みでエスケープを実装する場合、バックスラッシュ自体のエスケープ(\ -> \\)を最初に行わないと、後から追加した\"や\nの\までさらにエスケープされてしまう二重エスケープの罠がある(KNOW-F-0281のHTMLエスケープにおける&の扱いと同種の罠)。
---
### KNOW-F-0296 全角半角正規化の型
**構造の型**:
```
S2 = 全角英数字・記号 を 半角 に変換(コードポイントのオフセットで対応づけ)
```
日本語入力でよく混入する全角英数字(A1&など)を、半角(A1&)に統一する構造。逆方向(半角→全角)の変換も同じ考え方で定義できる。
**使いどころ**: フォームの入力欄で、ユーザーが意図せず全角で数字や記号を入力した場合の正規化に使う。全角カタカナと半角カタカナのように文字種そのものが変わる変換は別の変換表が必要になり、単純なオフセット対応では扱えない場合がある。
**組合せ例**: 全角の"A"(U+FF21)を半角正規化すると"A"(U+0041)になる。ユーザーが入力した郵便番号"123-4567"(全角数字とハイフン)を正規化すると"123-4567"になり、続けて正規表現フォーマット検査(KNOW-F-0355)にかけられる形になる。
**確認事項**: 全角半角の対応表を自前で持つ場合、変換対象の範囲(英数字だけか、記号も含むか、カタカナも含むか)を明確にしておかないと、意図しない文字まで変換してしまう。既存の正規化ライブラリがあるならUnicode正規化(KNOW-F-0280)とあわせてそちらを優先的に検討する。
---
### KNOW-F-0297 トークナイズ(単語分割)の型
**構造の型**:
```
tokens = S.trim().split(/\s+/) // 連続する空白をまとめて区切り文字とみなす
```
文章を、意味のある最小単位(単語やトークン)の配列に分割する構造。単純な空白区切りは英語のような分かち書きの言語には有効だが、日本語のように単語間に空白がない言語では形態素解析という専用の技術が必要になる。
**使いどころ**: 単語の出現回数を数えたい、簡易的な検索インデックスを作りたいときに使う。日本語や中国語のような言語を扱う場合、本型(空白区切り)だけでは不十分であることを設計段階で認識しておく。
**組合せ例**: "the quick brown fox"をトークナイズすると["the","quick","brown","fox"](4トークン)になる。続けてグループ化(KNOW-F-0328)で単語ごとの出現回数を数えると、この例では全単語が1回ずつなので{the:1,quick:1,brown:1,fox:1}になる。
**確認事項**: 単純な`split(" ")`(半角スペース1文字だけの区切り)は、連続する複数の空白やタブ・改行が混在する文章で空文字列のトークンを生んでしまう。正規表現`/\s+/`(1文字以上の空白文字の連続)を区切りに使うことでこの問題を避けられる。
---
### KNOW-F-0298 テンプレートエンジン(プレースホルダ置換)の型
**構造の型**:
```
S2 = テンプレート.replace(/\{\{(\w+)\}\}/g, (match, key) => データ[key])
```
`{{name}}`のような専用の記法(プレースホルダ)を文中に埋め込んでおき、実行時にデータオブジェクトの対応する値へ一括置換する構造。テンプレート文字列補間(KNOW-F-0283)がプログラムのソースコードに直接埋め込む方式であるのに対し、こちらはテンプレート自体を外部の文字列(ファイルやデータベース)として保持できる点が異なる。
**使いどころ**: メールの本文テンプレートや通知文のように、テンプレート自体を非エンジニアが編集したい場合や、実行時までテンプレートの内容が決まらない場合に使う。
**組合せ例**: テンプレート"Hello, {{name}}!"にデータ{name:"World"}を適用すると"Hello, World!"になり、KNOW-F-0283のテンプレート補間と同じ最終結果を得られる。プレースホルダに対応するキーがデータに存在しない場合の既定値(空文字にするか、プレースホルダをそのまま残すか)を仕様として決めておく。
**確認事項**: プレースホルダ置換で得た値をそのままHTMLへ出力する場合、テンプレート補間(KNOW-F-0283)と同様にエスケープ(KNOW-F-0281)を怠るとクロスサイトスクリプティングの経路になる。テンプレートエンジンによっては既定でエスケープを行うものと行わないものがあり、どちらの既定動作かを必ず確認する。
---
### KNOW-F-0299 ロケール依存ソート(文字列比較)の型
**構造の型**:
```
配列.sort((a, b) => a.localeCompare(b, ロケール))
```
コードポイントの単純な大小比較ではなく、指定した言語・地域の慣習(大文字小文字を同列に扱う、アクセント記号を無視するなど)に従って文字列の順序を決める構造。
**使いどころ**: 人名や地名のような、人が読んで自然な順に並べたい一覧を作るときに使う。機械的なID文字列の比較(完全一致・辞書順の判定だけでよい場合)には、ロケール比較のコストをかけずに単純比較で十分な場合が多い。
**組合せ例**: ["Banana","apple","éclair"]を単純なコードポイント比較でsort(KNOW-F-0258)すると、大文字"B"(コードポイント66)が小文字"a"(97)より小さいために["Banana","apple","éclair"]という、人の感覚では不自然な順序になる。localeCompareによるロケール比較を使うと、大文字小文字とアクセントを無視した自然な辞書順["apple","Banana","éclair"]が得られる。
**確認事項**: ロケール比較は単純比較よりも計算コストが高い場合があり、大量の要素を頻繁にソートする場面ではあらかじめ比較キー(正規化済みの文字列)を1回だけ計算してから単純比較でソートする(比較のたびにlocaleCompareを呼ばない)工夫が有効とされる。
---
### KNOW-F-0300 文字列処理の型まとめ(第2章・分類比較表)
**構造の型(章内の分類表)**:
| 分類 | 該当KNOW-F | 主な用途 |
|---|---|---|
| 分解/結合 | 0276, 0277, 0284, 0285, 0297 | 配列との相互変換・部分取得・検索 |
| 正規化 | 0278, 0279, 0280, 0291, 0296, 0299 | 表記ゆれ・改行・大小文字・全角半角の統一 |
| エスケープ/デコード | 0281, 0282, 0292, 0293, 0294, 0295 | 安全な出力・別形式への変換 |
| テンプレート | 0283, 0298 | 変数の埋め込み |
| 検索/置換 | 0286, 0287 | パターンによる検出と書き換え |
| 整形 | 0288, 0289 | 表示用の桁そろえ・書式 |
| 特殊表現対応 | 0290 | サロゲートペア |
**使いどころ(章全体の使い分け方針)**: ユーザー入力を受け取ったら、まず正規化系(trim・大文字小文字・Unicode正規化・全角半角)で表記ゆれを取り除き、次に検証(第5章)へ渡し、出力の直前でエスケープ系を適用する、という「入力時に正規化・出力時にエスケープ」の順序が第2章全体を貫く原則になる。
**組合せ例(代表的な組合せの並記)**: trim→大文字小文字正規化→比較(KNOW-F-0278→0279)でユーザーIDの一致判定、split→trim→join(KNOW-F-0276→0278→0277)でCSV風データの整形、テンプレート補間→HTMLエスケープ(KNOW-F-0283→0281)で安全な画面表示、という3つの流れが繰り返し登場する。
**確認事項(章全体で共有される検証原則)**: 文字列処理で最も見落とされやすいのは「エスケープの二重適用・未適用」と「正規化の順序違い(先にtrimすべきかUnicode正規化すべきか)」である。共通サンプルSの前後空白除去後の長さ13文字を基準に、各変換の前後で長さがどう変わるかを都度検算する習慣が、第2章全体の結びとして特に重要になる。
---
---
## 第3章 数値精度の型(KNOW-F-0301〜0325)
PCの内部で数値は有限のビット数で表現されるため、数学的に正しい値と、実際にメモリ上に記録される値との間には、しばしばずれが生じる。このずれを「知らずに踏む罠」にしないための型が第3章の主題である。本章の数値例はすべて検算過程を明示し、誇張なく実測または手計算で確認できる範囲にとどめる。
### KNOW-F-0301 浮動小数点の丸め誤差の型(0.1+0.2問題)
**構造の型**:
```
0.1 + 0.2 == 0.3 ? → 多くの処理系で false
0.1 + 0.2 → 0.30000000000000004 (表示上)
```
10進数の0.1や0.2は、2進数の有限ビット(IEEE754倍精度浮動小数点)では正確に表現できない循環小数になるため、演算結果にごくわずかな誤差が生じる構造。
**使いどころ**: この型そのものを「使う」のではなく、以降のすべての数値精度の型(丸め・整数化・イプシロン比較)がこの現象への対処として存在することを理解するための出発点として位置づける。
**組合せ例**: 0.1+0.2を計算すると、多くの主要な処理系で0.30000000000000004という値が得られ、これは0.3という値そのものとは一致しない(0.1+0.2 === 0.3はfalseと評価される)。この誤差はイプシロン比較(KNOW-F-0309)で吸収するか、そもそも整数演算への還元(KNOW-F-0304)で回避するかの二択で対処する。
**確認事項**: 「浮動小数点は不正確だから使うべきでない」という極端な結論に飛びつかないこと。整数として表現できる範囲(後述のBigInt・KNOW-F-0312で扱う限界まで)や、そもそも誤差が結果に影響しない用途では浮動小数点で全く問題ない。問題になるのは「金額の合計を厳密に一致させたい」「等値比較で分岐する」といった、誤差を許容できない場面だけである。
---
### KNOW-F-0302 四捨五入/切り捨て/切り上げの型
**構造の型**:
```
round(x) // 四捨五入(0から遠い方向へ丸める方式の場合)
floor(x) // 切り捨て(負の無限大方向)
ceil(x) // 切り上げ(正の無限大方向)
```
小数を整数(または指定した桁数)へ丸める3つの基本方式。負の数を扱うときに「0に近づける」のか「小さい(負の無限大)方向へ寄せる」のかで floor と「0方向への切り捨て(truncate)」が別物になる点に注意する。
**使いどころ**: 表示桁数を整えたい・在庫数のように整数でなければならない値を丸めたいときに使う。金額のように「多く見積もりすぎない」ことが重要な場面ではfloor、「少なく見積もらない」ことが重要な場面ではceilを選ぶというように、丸め方向自体に業務上の意味を持たせる場合がある。
**組合せ例**: 2.5に対しround(四捨五入・0から遠い方向)を適用すると3、floorを適用すると2、ceilを適用すると3になる。負の値-2.5では、floorは-3(より小さい整数)、ceilは-2(より大きい整数)になり、floorとceilはゼロを挟んで非対称に動くことが確認できる。
**確認事項**: プログラミング言語によっては切り捨て(truncate、0に近づける)とfloor(負の無限大方向)を同じ関数名で提供していない場合があり、負の数を扱うコードでは必ずどちらの方式かをドキュメントで確認する。floor(-2.5)=-3とtruncate(-2.5)=-2は異なる値になる(検算: -3<-2.5<-2の関係から、floorはより小さい方の-3、truncateは0に近い-2を返すことが分かる)。
---
### KNOW-F-0303 銀行丸め(round half to even)の型
**構造の型**:
```
roundHalfToEven(x):
ちょうど0.5の端数のときだけ、丸めた結果が偶数になる方向を選ぶ
それ以外(0.5でない端数)は通常の四捨五入と同じ
```
「ちょうど半分」の端数が出たときに常に切り上げるのではなく、丸めた結果が偶数になるほうを選ぶことで、大量のデータを丸めたときに丸め誤差が一方向に偏らないようにする方式。
**使いどころ**: 金融機関の帳票や統計処理のように、大量の丸め処理を繰り返した結果の合計に系統的な偏りを出したくない場面で採用されることがあるとされる。1回限りの丸めでは通常の四捨五入との違いはほとんど問題にならない。
**組合せ例**: 2.5を銀行丸めすると、丸めた結果の候補2と3のうち偶数である2が選ばれる。3.5を銀行丸めすると、候補3と4のうち偶数である4が選ばれる。同じ0.5の端数でも、隣り合う整数のどちらが偶数かによって丸める方向が変わる(2.5→2、3.5→4)点が通常の四捨五入(2.5→3、3.5→4のように常に切り上げ)との違いになる。
**確認事項**: 銀行丸めは「常に偶数へ丸める」のではなく「ちょうど0.5のときだけ偶数を選ぶ」方式である点を混同しないこと。0.5でない端数(2.4や2.6)は通常の四捨五入と全く同じ結果になるため、2.4→2、2.6→3という丸めは銀行丸めでも変わらない。
---
### KNOW-F-0304 整数演算への還元(セント単位金額)の型
**構造の型**:
```
金額(円やドル) を 最小単位(銭・セント)の整数 として保持し、
表示直前だけ 100で割って小数表示に戻す
```
小数のまま金額を扱わず、最小の貨幣単位(たとえば1セント、日本円なら1円が最小単位)を1とする整数に換算してから加減乗算を行う構造。整数演算は浮動小数点のような丸め誤差を原理的に持たない。
**使いどころ**: 金額の合計・税額計算・分割払いの端数配分など、1円単位のずれも許されない会計処理全般に使う。逆に、誤差が許容される統計値や物理量の近似計算では、整数化のための桁の見積もりコストのほうが割高になる場合がある。
**組合せ例**: 19.99ドルの商品を3個購入する場合、セント単位の整数1999(セント)を3倍すると5997セントになり、100で割って表示すると59.97ドルになる。浮動小数点のまま19.99を10進表記の感覚で複数回加算すると、内部表現の丸めが蓄積し、表示直前の桁で合計がわずかにずれる可能性が理論上残るが、整数セントでの計算はこの可能性を原理的に排除する。
**確認事項**: 整数化する際の「最小単位」の取り違え(セントのつもりが実は1000分の1単位だった、等)は重大な計算ミスに直結するため、通貨の最小単位(小数点以下の桁数)を仕様書で必ず確認する。日本円のように補助単位(銭)が実務上使われない通貨では、最小単位=1円としてそのまま整数運用できる。
---
### KNOW-F-0305 桁あふれ(オーバーフロー)の型
**構造の型**:
```
32bit符号付き整数の最大値 = 2^31 - 1 = 2147483647
2147483647 + 1 → -2147483648 (二の補数表現での折り返し)
```
決められたビット数で表現できる範囲を超えた計算結果が、符号が反転したような予期しない値に「折り返る」現象。
**使いどころ**: この型を積極的に「使う」場面は少なく、むしろ「桁あふれが起こりうる演算を事前に見抜き、より大きな型(64bit整数やBigInt、KNOW-F-0312)へ切り替える」判断のために型として認識しておく。
**組合せ例**: 32bit符号付き整数の最大値2147483647(2^31−1)に1を加えると、二の補数表現では最上位ビットが立って符号が反転し、-2147483648(最小値)に折り返る。この現象はカウンタやIDの採番処理で「あり得ないはずの負の値が現れる」というバグとして表面化することがある。
**確認事項**: 桁あふれは実行時にエラーを出さず、静かに誤った値を生成する点が最も危険である。カウンタが十分に大きくなりうる設計(アクセス数・IDの連番など)では、あらかじめビット幅を見積もり、上限に近づく前により大きな型へ移行する、あるいは最初から64bit整数を使う設計にしておく。
---
### KNOW-F-0306 アンダーフロー(underflow)の型
**構造の型**:
```
0に非常に近い正の小さな値を繰り返し半分にしていくと、
表現できる最小の値を下回った時点で 0 に丸められる
```
オーバーフローが「大きすぎて表現できない」現象であるのに対し、アンダーフローは「0に近すぎて表現できる最小の刻み幅を下回る」現象である。
**使いどころ**: 極端に小さい値を反復して掛け合わせる・割り続けるアルゴリズム(確率の連続積、指数関数的減衰のシミュレーションなど)で、値が知らないうちに0に潰れていないかを確認する視点として使う。
**組合せ例**: 表現可能な最小の正の浮動小数点値をさらに2で割ると、結果は0に丸められる(それ以上小さい値を区別して表現するビットが残っていないため)。確率pを何度も掛け合わせるシミュレーション(p^n)で、nが大きくなるにつれ値が0に潰れてしまう場合、対数を取って和の計算(log(p)の合計)に置き換えるという回避策が使われることがあるとされる。
**確認事項**: アンダーフローで0になった値をその後の除算の分母に使うと、ゼロ割り(KNOW-F-0313)を誘発する。極端に小さい値を扱う計算では、途中経過をログに出し、想定より早く0に落ち込んでいないかを確認する。
---
### KNOW-F-0307 固定小数点表現の型
**構造の型**:
```
実際の値 = 内部整数 ÷ スケール(例: 100)
19.99 を 保持するとき、内部整数 1999、スケール 100
```
小数を「整数×スケール」の組で表現し、演算はすべて整数のまま行い、表示のときだけスケールで割り戻す構造。整数演算への還元(KNOW-F-0304)を一般化した表現方式である。
**使いどころ**: 金額のように桁数が固定されているデータ全般に使う。スケールを可変にしたい(桁数が場面によって変わる)場合は、固定小数点よりも浮動小数点かBigIntベースの専用の数値型を検討する。
**組合せ例**: 19.99をスケール100の固定小数点で表すと内部整数1999になる。2.5倍する計算をしたい場合、1999×2.5=4997.5となり整数にならないため、スケールをさらに10倍(1000)にした19990として計算するか、乗算後にあらためて丸める(KNOW-F-0302)処理を挟む必要がある。
**確認事項**: 異なるスケールの固定小数点値同士をそのまま加減算すると、桁がそろっていないため誤った結果になる(スケール100の1999とスケール1000の19990を単純に足すと21989という無意味な値になる)。演算前に必ずスケールをそろえる。
---
### KNOW-F-0308 有効数字と誤差伝播の型
**構造の型**:
```
測定値の有効数字の桁数のうち、最も少ない桁数に結果の有効数字を合わせる
```
実測値には測定精度の限界があり、有効数字の桁数が異なる値同士を掛け合わせたり足し合わせたりした結果は、最も精度の低い測定値の桁数を超えて「正確なふり」をしてはならないという考え方。
**使いどころ**: 物理量やセンサーの測定値を扱う計算で、計算結果の桁数を測定精度以上に見せかけないために使う。純粋に整数やあらかじめ定義された定数同士の計算では有効数字の概念は不要である。
**組合せ例**: 有効数字3桁の測定値3.14と有効数字2桁の測定値2.0を掛け合わせると、数学的な積は6.28になるが、有効数字の少ないほう(2桁)に合わせて6.3と報告するのが有効数字の考え方に沿った扱いになる(検算: 3.14×2.0=6.28、これを2桁に丸めると6.3)。
**確認事項**: プログラム内部では6.28という値のまま保持して計算を続け、表示・報告する最終段階でだけ有効数字に丸めるのが一般的な設計である。途中の計算段階で早々に丸めてしまうと、後続の計算にさらに誤差が積み重なる(誤差伝播が余分に増える)ため、丸めは最後にまとめて行う。
---
### KNOW-F-0309 イプシロン比較(絶対誤差/相対誤差)の型
**構造の型**:
```
almostEqual(a, b, epsilon) = abs(a - b) < epsilon
```
浮動小数点同士を完全一致(==)で比較する代わりに、「ごく小さい許容誤差(イプシロン)の範囲内なら等しいとみなす」比較方式。
**使いどころ**: KNOW-F-0301で示した0.1+0.2のような演算結果を、期待値と比較する単体テストやアルゴリズムの収束判定に使う。金額のように「1円単位のずれも許されない」場面ではイプシロン比較ではなく整数演算への還元(KNOW-F-0304)を優先する。
**組合せ例**: 0.1+0.2の計算結果0.30000000000000004と0.3の差は、10のマイナス17乗程度というごくわずかな値になる。イプシロンを1e-9(10億分の1)として絶対誤差比較を行うと、この差はイプシロンよりはるかに小さいため「ほぼ等しい」と判定される。
**確認事項**: 絶対誤差(差の大きさ)だけで比較すると、非常に大きな数同士(100万と100万.001)や非常に小さな数同士で判定基準が不適切になる場合があり、値の大きさに応じてイプシロンを相対的にスケールする相対誤差比較(差を値の大きさで割ってから比較する)を使う設計もある。イプシロンの値は用途ごとに適切な桁を選ぶ必要があり、常に同じ値を流用すると別の場面で判定を誤る。
---
### KNOW-F-0310 NaN伝播とチェックの型
**構造の型**:
```
0 / 0 → NaN (Not a Number)
NaN + 任意の数 → NaN (伝播する)
NaN === NaN → false (通常の等値比較では判定できない)
isNaN(x) → NaNかどうかを判定する専用関数
```
「数値として定義できない結果」を表す特別な値NaNが、その後の計算に一度でも混ざると、後続のすべての計算結果もNaNに汚染されていく構造。
**使いどころ**: 不正な入力(数値に変換できない文字列など)が計算の途中に紛れ込んだことを、結果がNaNになることで検出したいときに使う。ただし、どの時点でNaNが混入したかを特定するには、伝播した後の結果だけを見ても分からないため、入力段階での検証(第5章)を組み合わせる。
**組合せ例**: 0を0で割るとNaNになり、そのNaNに5を加えてもNaN、さらに配列の合計(reduce、KNOW-F-0255)にNaNが1つでも混ざると合計全体がNaNになる。これは「1件の異常データが全体の集計結果を無効にする」という伝播の典型例であり、集計前のフィルタ(KNOW-F-0253)でNaNを除外するか、そもそも入力段階で検証(KNOW-F-0357)する対策が必要になる。
**確認事項**: NaN===NaNがfalseになるという性質(NaNは自分自身とすら等しくないと定義されている)を知らずに`if (x === NaN)`のような判定を書くと、NaNを検出できずに素通りしてしまう静かなバグになる。NaNの判定には専用のisNaN関数(あるいは同等の判定手段)を必ず使う。
---
### KNOW-F-0311 Infinity処理の型
**構造の型**:
```
1 / 0 → Infinity (正の無限大)
-1 / 0 → -Infinity (負の無限大)
Infinity - Infinity → NaN (無限大同士の引き算は不定)
```
非常に大きな値を表現しきれない場合や、正の数をゼロで割った場合に現れる、通常の数値演算の範囲を超えた特別な値を扱う構造。
**使いどころ**: 「上限が存在しない」ことを表現したい初期値(最小値を探すループの初期値をInfinityにする等)として積極的に使う場合と、意図せず発生してしまう異常値として検出・排除したい場合の両方がある。
**組合せ例**: 配列の中から最小値を探すreduce(KNOW-F-0255)の初期値をInfinityに設定しておくと、どんな実際の値もInfinityより小さいため、最初の比較で必ず置き換わり、初期値のInfinityが結果に残る心配がない。逆に、意図せずゼロ除算でInfinityが発生した場合、Infinity-Infinityを計算するとNaN(KNOW-F-0310)になり、異常が別の形の異常値へ変質してしまう。
**確認事項**: InfinityはisFinite(有限かどうかを判定する関数)で検出できるが、NaNもisFiniteではfalse(有限でない)と判定される点に注意し、「Infinityだけを検出したいのかNaNも含めて検出したいのか」を判定関数の選択で明確に区別する。
---
### KNOW-F-0312 大きな整数(BigInt)の型
**構造の型**:
```
Number.MAX_SAFE_INTEGER = 2^53 - 1 = 9007199254740991
9007199254740992 + 1 → 通常の数値型では 9007199254740992 のまま変化しない(精度限界)
9007199254740992n + 1n → BigIntなら 9007199254740993n と正しく計算できる
```
通常の浮動小数点数値型が整数を正確に表現できる範囲(2の53乗−1まで)を超えるような、非常に大きな整数を正確に扱うための専用の数値型。
**使いどころ**: 暗号処理の鍵、大規模IDの採番、天文学的な桁数のカウンタなど、2の53乗を超える整数を正確に扱う必要がある場面で使う。通常の金額計算や日常的なカウンタでは、この上限に達することはまずないため、常用する必要はない。
**組合せ例**: 通常の数値型でNumber.MAX_SAFE_INTEGER(9007199254740991)に2を加えようとすると、内部の精度限界により正しい結果9007199254740993を表現できず、隣接する偶数9007199254740992のような不正確な値になることがある。BigIntで同じ計算を行うと、桁数に制限なく正確な9007199254740993という値が得られる。
**確認事項**: BigIntと通常の数値型は多くの言語処理系で暗黙の混在演算ができない(型を明示的にそろえる必要がある)仕様になっており、うっかり両者を混ぜて演算しようとすると実行時エラーになる場合がある。BigIntは通常の数値型より演算が遅い実装が多いため、精度が本当に必要な箇所だけに限定して使う。
---
### KNOW-F-0313 ゼロ割り回避の型
**構造の型**:
```
if 分母 == 0:
エラーとして扱う、または既定値を返す
else:
分子 / 分母
```
除算を実行する前に、分母がゼロになっていないかを必ず確認してから計算する防御的な構造。
**使いどころ**: 平均値の計算(件数で割る)、比率の計算(分母が0件になりうる集計)など、分母が動的に決まる除算全般に使う。分母が定数であらかじめゼロでないと分かっている場合は、この確認は不要である。
**組合せ例**: 集計対象の件数が0件のときに合計÷件数で平均を求めようとすると、整数演算ではエラー(実行時例外)になる処理系が多く、浮動小数点演算ではInfinityまたはNaN(KNOW-F-0310・0311)になる処理系が多い。いずれの挙動になるにせよ、件数0のケースを事前に検証(KNOW-F-0353の範囲検査)で弾き、「対象データなし」という意味のある表示に置き換えるのが安全な設計である。
**確認事項**: 整数のゼロ除算と浮動小数点のゼロ除算では挙動が異なる(前者は例外、後者はInfinity/NaNになることが多い)処理系が存在するため、扱っている数値の型がどちらかを意識してエラー処理を設計する。「分母が0のときは0を返す」という安易な既定値も、業務的な意味(平均が本当に0なのか、対象がないだけなのか)を混同させるため慎重に選ぶ。
---
### KNOW-F-0314 浮動小数点加算の非結合性(累積誤差)の型
**構造の型**:
```
(0.1 + 0.2) + 0.3 → 0.6000000000000001
0.1 + (0.2 + 0.3) → 0.6
```
数学的な加法の結合法則(どの順に足しても結果は同じ)が、浮動小数点演算では厳密には成り立たない現象。計算する順序によって、最後の桁にごくわずかな違いが生じうる。
**使いどころ**: 大量の数値を合計するプログラムで、集計順序(データベースのクエリ結果の並び順やスレッドの実行順など)によって最終結果が実行のたびに微妙に異なるという再現性の問題を理解するために使う。金額集計のように厳密な一致が必要な場面では、整数演算への還元(KNOW-F-0304)で結合法則の崩れそのものを回避する。
**組合せ例**: (0.1+0.2)+0.3を計算すると、まず0.1+0.2が0.30000000000000004になり、それに0.3を足すと0.6000000000000001になる。一方0.1+(0.2+0.3)を計算すると、0.2+0.3がちょうど0.5になり、それに0.1を足すと0.6になる。同じ3つの値の和でも、計算する順序によって最後の桁が0.6000000000000001と0.6という異なる結果になる(検算: 両者の差は0.0000000000000001程度のごく小さい値だが、厳密な等値比較では不一致と判定される)。
**確認事項**: この非結合性は「バグ」ではなくIEEE754浮動小数点の仕様上の性質であるため、修正しようとするのではなく、イプシロン比較(KNOW-F-0309)や整数演算への還元(KNOW-F-0304)で影響を受けない設計にすることが対処になる。合計処理の実装を並列化・順序変更する最適化を行う際は、この非結合性により結果がビット単位では変わりうることを認識しておく。
---
### KNOW-F-0315 数値文字列変換の境界(parseFloat/Number)の型
**構造の型**:
```
parseFloat("3.14abc") → 3.14 (先頭から解釈できる部分だけを数値化し、残りは無視)
Number("3.14abc") → NaN (文字列全体が数値として妥当でなければ失敗)
```
文字列を数値に変換する関数には、「先頭部分だけ解釈して残りを無視する」ものと、「文字列全体が完全に数値でなければ失敗する」ものの2系統があり、挙動が大きく異なる。
**使いどころ**: ユーザー入力のように末尾に単位や余分な文字が付きうる文字列を寛容に解釈したいならparseFloat系、フォームの値のように厳密に数値だけであることを保証したいならNumber系(または後述の検証の型と組み合わせた専用の変換)を使う。
**組合せ例**: "3.14abc"をparseFloatで変換すると3.14が得られる(先頭の"3.14"の部分だけを解釈し、"abc"は無視される)。同じ文字列をNumberで変換するとNaN(KNOW-F-0310)になる(文字列全体が数値として妥当でないため失敗と判定される)。この違いを知らずにNumber関数の結果をparseFloat相当の寛容な変換だと誤解すると、想定と異なる箇所でNaNが発生する。
**確認事項**: 空文字列""をNumberで変換すると0になる(NaNにはならない)処理系が多く、「未入力」を意味するつもりの空文字列が数値の0として計算に混入する典型的な罠になる。未入力かどうかは変換前にnull/undefined検査(KNOW-F-0352)で別途判定しておく。
---
### KNOW-F-0316 単位変換の精度保持の型
**構造の型**:
```
基準となる最小単位(たとえばミリメートル)を整数で保持し、
表示のときだけ メートルやセンチメートル に換算して割り算する
```
複数の単位(メートル・センチメートル・ミリメートル)を行き来する量を、その都度小数で変換するのではなく、最も細かい単位を基準の整数として保持し、必要なときだけ換算する構造。整数演算への還元(KNOW-F-0304)の単位版にあたる。
**使いどころ**: 距離・重量・時間のように複数の単位系で表示されうる量を、変換のたびに誤差が積み重なることなく扱いたいときに使う。単位が1種類しかなく変換の必要がない量には、この型を適用する必要はない。
**組合せ例**: 1100ミリメートルという長さを基準の整数として保持しておけば、メートル表示が必要なときは1100÷1000=1.1メートル、センチメートル表示が必要なときは1100÷10=110センチメートルと、その都度整数除算(または最後の一度だけの小数変換)で求められる。逆に1.1メートルという小数を基準にして都度100倍・1000倍を繰り返す設計は、変換のたびに浮動小数点演算(KNOW-F-0301)を経由することになり、誤差が乗る余地を増やす。
**確認事項**: 「最も細かい単位」をどこに置くかは業務要件次第であり、必要以上に細かい単位(距離をナノメートル単位で持つ等)を基準にすると、通常の整数型の表現範囲(KNOW-F-0305の桁あふれ)にすぐ到達してしまう。扱う量の現実的な範囲を見積もったうえで基準単位を決める。
---
### KNOW-F-0317 比較演算子と浮動小数点順序の罠の型
**構造の型**:
```
0.1 + 0.2 > 0.3 → true (数学的には等しいはずが、内部表現のずれで「大きい」と判定される)
```
浮動小数点の丸め誤差(KNOW-F-0301)は等値比較だけでなく、大小比較(<, >)の結果にも影響を及ぼしうるという構造。
**使いどころ**: この型自体は「避けるべき罠」として認識するために使う。ループの終了条件や閾値判定に浮動小数点の大小比較を使う設計では、境界付近の値でわずかな誤差により条件が想定と逆に評価される可能性を考慮する。
**組合せ例**: 0.1+0.2の計算結果0.30000000000000004は、0.3という値そのものよりわずかに大きいため、0.1+0.2 > 0.3という比較はtrueと評価される。数学的には0.1+0.2は0.3に等しいはずだが、内部表現のずれによって「大きい」という誤解を招く比較結果が返る。
**確認事項**: 「0.1ずつ加算して合計が1.0になったらループを終了する」のような浮動小数点の等値・大小比較に依存した終了条件は、誤差の蓄積(KNOW-F-0314)により想定回数でループが終了しない可能性がある。ループの回数管理は浮動小数点の値そのものではなく、整数のカウンタ(何回加算したか)で行うほうが安全である。
---
### KNOW-F-0318 通貨計算の整数セント方式の型
**構造の型**:
```
セント単位の整数で計算し、税額のような比率計算だけ最後に1回だけ丸める
```
整数演算への還元(KNOW-F-0304)を、税計算のような複数ステップの実務計算に具体的に適用した構造。
**使いどころ**: 小計・税額・合計というように複数段階を経る金額計算で、各段階ごとに丸めると誤差が積み重なる(KNOW-F-0319のパーセンテージ計算の丸め順序と同じ問題)ため、丸めは最終段階に1回だけ行う設計に使う。
**組合せ例**: 19.99ドルの商品を3個購入し、8%の税がかかる場合、まずセント単位で小計1999×3=5997セントを求める。これに1.08を掛けると5997×1.08=6476.76セントになり、ここで初めて丸めを行うと6477セント(端数0.76を四捨五入)になる。ドル表示に戻すと64.77ドルであり、各段階(単価・数量・税率)ではなく最終合計にだけ丸めを適用したことになる。
**確認事項**: 商品ごとに税額を個別に計算してから合算する設計と、小計に対して一括で税額を計算する設計とでは、丸めの回数が異なるため最終的な合計が1セント単位でずれる可能性がある。どちらの方式を採用するかは会計上のルール(税法や社内規程)で決まっている場合が多く、実装側で勝手に選ばない。
---
### KNOW-F-0319 パーセンテージ計算の丸め順序の型
**構造の型**:
```
100を3人で均等に丸めて配分する場合:
各自の取り分を先に丸めてから合計する方式 → 合計が100からずれることがある
合計100を保ったまま端数だけ最後に調整する方式 → 合計は必ず100になる
```
比率の計算を先に丸めてから合計すると、丸めによる端数の欠落や超過が積み重なり、全体の合計が本来あるべき値からずれる「配分問題」を扱う構造。
**使いどころ**: 議席配分・予算の按分・在庫の均等割りなど、「全体の合計が特定の値に一致しなければならない」制約がある配分計算で使う。合計が一致しなくてもよい単発の統計表示では、単純に各値を丸めるだけで十分である。
**組合せ例**: 100を3等分すると1人あたり100÷3=33.333…になり、これを小数点以下2桁に丸めると33.33になる。3人分をそのまま合計すると33.33×3=99.99であり、100.00にはならない(0.01が不足する)。この不足分0.01を、端数の大きい1人(または決められたルールに従って特定の1人)に上乗せして配分し直すことで、合計をちょうど100.00に一致させる調整が必要になる。
**確認事項**: 「各自の取り分を丸めてから合計する」設計のまま、合計値を別の場所でも独立に(丸めずに)100として扱っていると、画面表示上の内訳の合計と、別画面に表示される総合計が食い違うという整合性の不具合になりやすい。内訳と合計のどちらを正とするかを設計段階で決め、正としないほうを差分調整で合わせる。
---
### KNOW-F-0320 平均・分散の数値安定性の型
**構造の型**:
```
分散 = ( (x1-平均)^2 + (x2-平均)^2 + ... ) / n
(平均からの偏差を使う、数値的に安定した式)
```
分散を計算する式には「2乗の平均引く平均の2乗」という短い式もあるが、値がすべて大きく偏差が小さいデータでは、大きな数同士の引き算により有効桁が失われる(桁落ち)ことがあるため、平均からの偏差を先に取る式のほうが数値的に安定する。
**使いどころ**: センサーの測定値のように、値そのものは大きいがばらつき(分散)は小さいデータを統計処理するときに使う。値の大きさとばらつきの大きさが近い一般的なデータでは、どちらの式でも実用上大きな違いは出にくい。
**組合せ例**: 3つの測定値1000000.1、1000000.2、1000000.3の平均は、合計3000000.6を3で割って1000000.2になる。平均からの偏差はそれぞれ-0.1、0、0.1であり、偏差の2乗の平均は(0.01+0+0.01)÷3=0.02÷3=0.006666…になる。この計算では偏差という小さな数だけを扱うため桁落ちが起きにくいが、「2乗の平均引く平均の2乗」の式では、1000000.1の2乗のような巨大な数同士の引き算を経由するため、有効桁の一部が失われるリスクが生じる。
**確認事項**: 桁落ちは実行時エラーを出さずに静かに精度を落とすため、大きな値のわずかなばらつきを扱う統計処理では、平均からの偏差を使う式(または逐次更新型のより安定したアルゴリズム)を優先して選ぶ。
---
### KNOW-F-0321 指数表記(科学的記数法)変換の型
**構造の型**:
```
123456789 → 1.23456789 × 10^8
0.00001234 → 1.234 × 10^-5
```
非常に大きい、あるいは非常に小さい数値を、仮数部(1以上10未満の数)と指数部の組で表現し直す構造。
**使いどころ**: 表示桁数が極端に長くなる数値(天文学的に大きい値、原子レベルの極小値など)を人が読みやすい形に整形したいときに使う。日常的な範囲の数値(1〜数百万程度)をあえて指数表記にすると、かえって読みにくくなる場合が多い。
**組合せ例**: 123456789を指数表記に変換すると1.23456789×10の8乗になる(小数点を先頭の1桁の後ろまで8桁分左に動かしたため指数は8)。0.00001234を指数表記に変換すると1.234×10のマイナス5乗になる(小数点を1が現れる位置まで5桁分右に動かしたため指数はマイナス5)。
**確認事項**: 指数表記の文字列("1.23e8"のような表現)をそのまま別のシステムへ渡すと、指数表記に対応していない受け取り側では文字列としてしか解釈されず、数値として扱われない場合がある。システム間でデータを受け渡す際は、指数表記を使うかどうかを事前に取り決めておく。
---
### KNOW-F-0322 進数変換(2進/8進/16進)の型
**構造の型**:
```
10進数26 = 2進数11010 = 8進数32 = 16進数1A
```
同じ数量を、10種類の記号(0〜9)を使う10進表記だけでなく、2種類(2進)、8種類(8進)、16種類(16進、0〜9とA〜F)の記号を使う表記へ変換する構造。
**使いどころ**: メモリ番地や色コード(16進数)、ビット演算の結果(2進数)を人が読みやすい形で確認したいときに使う。通常の計算処理そのものは内部的にどの表記でも同じ2進数のビット列として扱われており、進数変換は「人間向けの見せ方」の変換である点を理解しておく。
**組合せ例**: 10進数の26は、2進数では16+8+2の組合せとして11010(1が16の位・8の位・2の位に立つ)になる。8進数では3×8+2=26より32、16進数では1×16+10(Aで表す)=26より1Aになる。同じ26という量を4通りの記号列で表現できることが、この変換の往復性の検算になる(2進11010→10進は16+8+0+2+0=26で一致)。
**確認事項**: 16進数の"1A"を10進数の10や1Aという別の数値と読み違えないよう、進数を明示する接頭辞(0xなど)をつけて区別する習慣が実務では一般的である。負の数を2進数で表現する際は二の補数表現(KNOW-F-0305の桁あふれの説明で使った表現)が使われることが多く、単純に符号ビットだけを反転させる表現とは異なる点に注意する。
---
### KNOW-F-0323 ハッシュ用整数演算(オーバーフロー許容)の型
**構造の型**:
```
h = 0
for c of 文字列:
h = h * 31 + 文字コード(c) // 桁あふれ(オーバーフロー)しても構わない
```
文字列などの入力から固定長の整数(ハッシュ値)を作る計算で、桁あふれ(KNOW-F-0305)が発生しても、それを異常とみなさず、むしろ折り返った値も含めて「ハッシュ値の一部」として積極的に利用する構造。
**使いどころ**: ハッシュテーブルの索引計算や、大量データの簡易的な同一性チェックのように、値そのものの正確な大きさではなく「ばらつきよく分散した固定長の値」が欲しい場面で使う。金額計算のように正確な数量が必要な場面では、この型のオーバーフロー許容という考え方を絶対に流用しない。
**組合せ例**: 文字列の各文字コードを31倍しながら積算していくハッシュ計算は、文字列が長くなるにつれて値がどんどん大きくなるが、固定ビット幅の整数で計算しているため、桁あふれが起きてもエラーにはならず、折り返った値がそのままハッシュ値として使われる。同じ文字列に対しては常に同じ折り返り方をするため、ハッシュ値としての一貫性(同じ入力からは常に同じ出力)は保たれる。
**確認事項**: この型の「桁あふれを許容する」という考え方は、KNOW-F-0305で警告した「意図しない桁あふれ」とは正反対の、意図して利用する設計である点を混同しないこと。ハッシュ値の計算にオーバーフローを許容しない厳密な整数型(BigIntなど)を使うと、かえって計算コストが増えるだけで利点がない。
---
### KNOW-F-0324 浮動小数点の等値判定回避設計の型
**構造の型**:
```
API設計として、浮動小数点の生の値を比較させるのではなく、
「閾値を超えたか」を真偽値で返す関数を用意する
```
KNOW-F-0301〜0317で見てきた浮動小数点特有の罠を、利用者に「イプシロンを毎回自分で選んでもらう」形で押し付けるのではなく、関数やAPIの設計自体で吸収してしまう考え方。
**使いどころ**: 複数の開発者が同じ数値比較のロジックを何度も書く可能性がある共通処理(在庫が閾値を下回ったか、進捗が完了とみなせる範囲に達したか等)を設計するときに使う。1箇所でしか使わない使い捨ての比較には、この設計の手間をかける必要はない。
**組合せ例**: 「残高がほぼゼロとみなせるか」を判定する関数isNearlyZero(x)を用意し、内部でイプシロン比較(KNOW-F-0309)を1箇所にまとめておけば、呼び出し側は`if (isNearlyZero(残高))`と書くだけでよく、イプシロンの値を各所でばらばらに選んでしまう不整合を防げる。
**確認事項**: 共通関数の内部で使うイプシロンの値を後から変更すると、その関数を呼び出しているすべての箇所の判定基準が一斉に変わる。影響範囲が広い共通処理であるほど、イプシロンの値を変更する際は既存の呼び出し箇所への影響を洗い出してから行う。
---
### KNOW-F-0325 数値精度の型まとめ(第3章・分類比較表)
**構造の型(章内の分類表)**:
| 分類 | 該当KNOW-F | 対処の方向性 |
|---|---|---|
| 誤差の発生源 | 0301, 0305, 0306, 0314, 0320 | 現象の理解(丸め・桁あふれ・アンダーフロー・非結合性・桁落ち) |
| 丸めの方式 | 0302, 0303, 0319 | 用途に応じた丸め方向・タイミングの選択 |
| 誤差を避ける表現 | 0304, 0307, 0316, 0318 | 整数・固定小数点への還元 |
| 特殊値の扱い | 0310, 0311, 0313 | NaN・Infinity・ゼロ除算の検出と防御 |
| 比較の設計 | 0309, 0317, 0324 | イプシロン比較・比較APIの設計 |
| 表現範囲の拡張/変換 | 0308, 0312, 0315, 0321, 0322, 0323 | 有効数字・BigInt・変換・進数・ハッシュ |
**使いどころ(章全体の使い分け方針)**: 「誤差が結果に実害を及ぼすか」を最初に判定する。実害がある(金額・カウンタ・議席配分など)なら整数演算への還元(0304・0307・0318・0319)を優先し、実害がない(表示・統計の近似値)ならイプシロン比較(0309)や有効数字の丸め(0308)で十分とする。
**組合せ例(代表的な組合せの並記)**: 0.1+0.2問題(0301)→イプシロン比較(0309)で単体テストの期待値判定、整数セント方式(0304・0318)→パーセンテージ丸め順序(0319)で税額計算、桁あふれ(0305)→BigInt(0312)でIDの上限対策、という3つの流れが第3章全体を通じて繰り返し登場する。
**確認事項(章全体で共有される検証原則)**: 第3章のすべての型に共通する原則は「数値例は必ず自分の手で検算してから使う」ことである。0.1+0.2=0.30000000000000004、(0.1+0.2)+0.3=0.6000000000000001、Number.MAX_SAFE_INTEGER=9007199254740991といった本章の数値は、いずれも実際に計算して確認できる値であり、伝聞や記憶だけで金額計算などの実務コードに転用しないことが、第3章全体の結びとして特に重要になる。
---
---
## 第4章 構造変換の型(KNOW-F-0326〜0350)
配列や文字列や数値が「値そのもの」の変換だったのに対し、第4章が扱うのは「値同士の関係(入れ子・親子・キーと値の対応)」の変換である。共通サンプルT(木構造)とU(ユーザー配列)を軸に、ネスト⇄フラット・グループ化・索引作りという3系統を24種の型として並べる。
### KNOW-F-0326 ネスト→フラット化の型
**構造の型**:
```
{a:1, b:{c:2, d:{e:3}}}
→ {"a":1, "b.c":2, "b.d.e":3} (キーをドット区切りのパスに変換)
```
深く入れ子になったオブジェクトを、キーの経路(パス)を1本の文字列にした、入れ子のない平らな(フラットな)オブジェクトへ変換する構造。
**使いどころ**: 設定ファイルの差分比較や、フォームの入力項目名(input要素のname属性など)のように、入れ子構造をそのまま扱えない形式へデータを渡したいときに使う。入れ子構造自体を保ったまま扱える形式であれば、あえてフラット化する必要はない。
**組合せ例**: {a:1, b:{c:2, d:{e:3}}}をフラット化すると{"a":1, "b.c":2, "b.d.e":3}になる。続けてフラット→ネスト復元(KNOW-F-0327)を適用すると元の{a:1, b:{c:2, d:{e:3}}}に戻ることが往復検算になる。
**確認事項**: キーの中にすでにドットを含む文字列(例: "user.name"というキー自体が存在する場合)があると、フラット化後のパスと衝突して復元時に誤った構造になる。区切り文字にドット以外の記号(業務データに絶対現れない文字)を選ぶ、あるいは事前にキーの検証(KNOW-F-0351)を行う対策が必要になる。
---
### KNOW-F-0327 フラット→ネスト復元の型
**構造の型**:
```
{"a":1, "b.c":2, "b.d.e":3}
→ 各キーをドットで分割し、経路をたどりながらオブジェクトを組み立て直す
→ {a:1, b:{c:2, d:{e:3}}}
```
フラット化(KNOW-F-0326)されたオブジェクトのキーのパスを読み解き、元の入れ子構造を組み立て直す構造。フラット化の逆操作にあたる。
**使いどころ**: フォームの入力値(name="b.c"のような属性名)から、送信先のAPIが期待する入れ子構造のJSONを組み立て直したいときに使う。
**組合せ例**: {"a":1, "b.c":2, "b.d.e":3}を復元すると、まず"a"は最上位のキーとしてそのまま1が入り、"b.c"はドットで["b","c"]に分割してb.cという経路に2を、"b.d.e"は["b","d","e"]に分割してb.d.eという経路に3を格納する。3つのキーを処理し終えると{a:1, b:{c:2, d:{e:3}}}という元の構造が完成する。
**確認事項**: 経路の途中(たとえばb)がすでに別の型の値(オブジェクトでなく数値など)として存在している場合、そこにさらに入れ子を作ろうとすると矛盾が生じる。復元処理では、経路の途中のキーが存在しなければ空オブジェクトを新規作成し、すでにオブジェクトとして存在すればそれを再利用する、という分岐を必ず入れる。
---
### KNOW-F-0328 グループ化(groupBy)の型
**構造の型**:
```
groups = {}
for x of 配列:
key = キー関数(x)
if key not in groups: groups[key] = []
groups[key].push(x)
```
配列の各要素を、指定したキー関数の戻り値ごとに束ね、キーごとの配列を持つオブジェクトへ変換する構造。
**使いどころ**: 部署別の社員一覧、日付別のログ件数のように、「同じ性質を持つものをまとめて見たい」集計処理全般に使う。1件だけを高速に取り出したいなら索引作り(KNOW-F-0329)を、まとめではなく件数だけが欲しいならreduce(KNOW-F-0255)で直接カウントするほうが簡潔な場合がある。
**組合せ例**: 共通サンプルU(3名、うち佐藤と高橋が営業、鈴木が開発)を部署(dept)でグループ化すると、{"営業":[佐藤,高橋], "開発":[鈴木]}になる。続けて各グループにmap(KNOW-F-0254)で件数を数えると{"営業":2, "開発":1}という部署別人数の集計が得られ、合計2+1=3が元のUの件数3と一致することを検算できる。
**確認事項**: キー関数が返す値の型(文字列と数値など)が混在していると、意図せず異なるキーとして扱われる場合がある(数値の1と文字列の"1"が別グループになる等)。キー関数の戻り値の型は事前にそろえておく。
---
### KNOW-F-0329 索引作り(indexBy/keyBy)の型
**構造の型**:
```
index = {}
for x of 配列:
index[x.id] = x
```
配列の各要素を、一意なキー(通常はID)を見出しにしたオブジェクトへ変換し、find(KNOW-F-0256)のような線形探索なしにO(1)相当の速さで特定の要素を取り出せるようにする構造。
**使いどころ**: 同じ配列に対して何度もID検索(findやfilter)を行う場面で使う。1回しか検索しない、あるいは配列が非常に小さい場合は、索引を作るコスト自体が線形探索より高くつく場合がある。
**組合せ例**: 共通サンプルUをidで索引作りすると{1:{id:1,name:"佐藤",...}, 2:{id:2,name:"鈴木",...}, 3:{id:3,name:"高橋",...}}になる。id=2のユーザーを取り出したいとき、find(KNOW-F-0256)でUを毎回先頭から線形探索する代わりに、索引[2]と書くだけで直接アクセスできる。
**確認事項**: 索引のキーに使う値(id等)が配列内で重複していると、後から出てきた要素が先の要素を上書きしてしまい、静かにデータが失われる。索引を作る前に一意性検査(KNOW-F-0366)を行っておくと、この種の取りこぼしに早期に気づける。
---
### KNOW-F-0330 オブジェクト⇄配列変換の型
**構造の型**:
```
entries(obj) = {a:1,b:2} → [["a",1],["b",2]] (キーと値の組の配列へ)
fromEntries(entries) = [["a",1],["b",2]] → {a:1,b:2} (組の配列からオブジェクトへ)
```
オブジェクト(キーと値の対応)と、キー・値の組を並べた配列とを相互に変換する構造。オブジェクトのままでは使えない配列専用の操作(map・filter・sortなど)をキーと値のペアに対して適用したいときの橋渡しになる。
**使いどころ**: オブジェクトの値だけを一括で変換したい(すべての値を2倍にする等)、キーの一覧で絞り込みたいときに、一度配列に変換してから配列操作の型を適用し、最後にオブジェクトへ戻すという流れで使う。
**組合せ例**: {a:1,b:2}をentriesで配列化すると[["a",1],["b",2]]になる。この配列にmap(KNOW-F-0254)で値だけを2倍にする変換をかけると[["a",2],["b",4]]になり、fromEntriesでオブジェクトに戻すと{a:2,b:4}になる(元のオブジェクトの各値がちょうど2倍になっていることを検算できる)。
**確認事項**: fromEntriesで同じキーが複数回現れる配列を変換すると、後に出てきたキーの値で上書きされ、先の値は失われる(索引作りKNOW-F-0329と同種の上書きの罠)。キーの重複がありうるデータでは、事前に重複検査(KNOW-F-0366)を行う。
---
### KNOW-F-0331 ディープコピーの型
**構造の型**:
```
浅いコピー: {...obj} // 1階層目だけ複製、内側の入れ子は参照共有のまま
深いコピー: 再帰的にすべての階層を複製し、参照の共有を完全に断ち切る
```
オブジェクトや配列を複製する際、1階層目だけをコピーする「浅いコピー」と、入れ子のすべての階層を再帰的に複製する「深いコピー」を区別する構造。
**使いどころ**: 複製したデータを独立して変更したい(元のデータに影響を与えたくない)場合に深いコピーを使う。1階層目しか変更しない、あるいは内側のオブジェクトを意図的に共有したい場合は浅いコピー(KNOW-F-0263の結合の型でも触れた性質)で十分であり、余分な複製コストをかけない。
**組合せ例**: T(木構造サンプル)を浅いコピーすると、最上位のidやchildrenへの参照は複製されるが、childrenの中の各要素オブジェクト自体は元のTと同じ参照を指したままになる。浅いコピーした側でchildren[0].idを書き換えると、元のTのchildren[0].idも一緒に変わってしまう。深いコピーであれば、この書き換えは複製側だけにとどまり、元のTには影響しない。
**確認事項**: 深いコピーの自前実装は、循環参照(KNOW-F-0345)を含むデータに対して無限再帰に陥る危険がある。標準ライブラリの構造化複製機構(循環参照に対応したもの)が利用できる場合はそちらを優先し、自前実装が必要な場合は訪問済みオブジェクトを記録する仕組みを必ず組み込む。
---
### KNOW-F-0332 ディープマージの型
**構造の型**:
```
浅いマージ: {...obj1, ...obj2} // 同じキーの入れ子オブジェクトは丸ごと上書き
深いマージ: 同じキーが両方にオブジェクトとして存在する場合、さらに内側まで再帰的に統合
```
2つのオブジェクトを統合する際、同じキーの値が両方ともオブジェクトであれば、その内側までさらに統合していく構造。
**使いどころ**: 既定の設定オブジェクトに、ユーザーが指定した一部の設定だけを上書きしたい(指定していない項目は既定値を保ちたい)場面で使う。同じキーの値を常に完全に置き換えたいだけなら浅いマージで十分である。
**組合せ例**: obj1={a:{x:1,y:2}}とobj2={a:{y:3,z:4}}を浅いマージ({...obj1,...obj2})すると、キーaの値がobj2のa全体({y:3,z:4})でまるごと置き換わり、xが失われて{a:{y:3,z:4}}になる。同じ2つのオブジェクトを深いマージすると、aの内側のxとyとzがそれぞれ個別に統合され{a:{x:1,y:3,z:4}}になる(xはobj1由来のまま残り、yはobj2の値3で上書き、zはobj2由来で新規追加)。
**確認事項**: 深いマージにおいて、片方が配列でもう片方がオブジェクトのように型が食い違う場合、どちらを優先するかのルールを事前に決めておかないと、実装によって挙動が変わる不安定な処理になる。既定の設定を扱う場面では、後から渡した値(ユーザー指定側)を優先するのが一般的な取り決めである。
---
### KNOW-F-0333 木構造の深さ優先走査(DFS)の型
**構造の型**:
```
DFS(node):
訪問(node)
for child of node.children:
DFS(child) // 再帰、または明示的なスタック(KNOW-F-0273)で実装
```
根から出発し、1本の枝を子・孫とできるだけ深くまでたどってから、次の枝に戻る走査順序。
**使いどころ**: フォルダ構造の全ファイルを列挙する、式の構文木を評価する(内側の部分式から先に計算する)など、「深いところから先に処理する必要がある」場面で使う。階層の浅い順(層ごと)に処理したいなら幅優先探索(KNOW-F-0334)を使う。
**組合せ例**: 共通サンプルTにid=2の子としてid=5を1つ追加した拡張版T'(id1の子がid2とid3、id2の子がid5、id3の子がid4)にDFSを適用すると、訪問順は1→2→5→3→4になる(id2に着いたらその子id5を先に訪れてから、id2の兄弟であるid3に移る)。
**確認事項**: 再帰で実装する場合、木の深さが極端に大きいとスタック領域を使い切るエラー(スタックオーバーフロー)を起こす可能性があるため、深さが不明な外部データを扱う場合は、スタック(KNOW-F-0273)を明示的に使う反復実装に切り替える設計も検討する。
---
### KNOW-F-0334 木構造の幅優先走査(BFS)の型
**構造の型**:
```
BFS(root):
キュー = [root]
while キューが空でない:
node = キュー.dequeue()
訪問(node)
for child of node.children:
キュー.enqueue(child)
```
根から出発し、同じ階層(深さ)にあるノードをすべて訪問してから、次の階層へ進む走査順序。キュー(KNOW-F-0274)を使って実装するのが典型的である。
**使いどころ**: 「根から最短で何ステップで到達できるか」を調べたい探索(最短経路の探索など)、階層ごとに区切った表示(組織図を役職の階層順に表示する等)に使う。深いところの情報を先に処理したいならDFS(KNOW-F-0333)を使う。
**組合せ例**: KNOW-F-0333で使った拡張版T'(id1の子がid2とid3、id2の子がid5、id3の子がid4)にBFSを適用すると、訪問順は1→2→3→5→4になる。同じ木でもDFSの訪問順1→2→5→3→4とは3番目の要素(DFSは5、BFSは3)から違いが生まれ、これが2つの走査順序の本質的な違いを示す具体例になる。
**確認事項**: BFSの実装でキューではなくスタックを誤って使ってしまうと、実質的にDFSと同じ動作になってしまう(KNOW-F-0273のスタックとKNOW-F-0274のキューの取り違えが典型的な実装ミスになる)。階層ごとの区切りを明示的に扱いたい場合は、キューに「その階層の残り件数」を記録しながら処理する工夫が使われることがある。
---
### KNOW-F-0335 木構造→配列フラット化(親子ID付き)の型
**構造の型**:
```
flatten(node, parentId):
結果.push({id: node.id, parentId: parentId})
for child of node.children:
flatten(child, node.id)
```
入れ子になった木構造を、各要素が「自分のID」と「親のID」だけを持つ、平らな配列(データベースのテーブルに保存しやすい形)へ変換する構造。KNOW-F-0326の汎用フラット化を、親子関係を持つ木構造に特化させたものである。
**使いどころ**: 木構造をリレーショナルデータベースのテーブル(1行1レコード)に保存したいときに使う。木構造のままJSON等で保存できる環境であれば、あえてこの変換を行う必要はない。
**組合せ例**: KNOW-F-0333のDFSで使った拡張版T'をこの型でフラット化すると[{id:1,parentId:null}, {id:2,parentId:1}, {id:5,parentId:2}, {id:3,parentId:1}, {id:4,parentId:3}]という5件のフラットな配列になる(DFSの訪問順1,2,5,3,4と一致する順序で記録している)。
**確認事項**: ルートノード(最上位)のparentIdをnullにするか0にするかは実装上の取り決めであり、後段の配列→木構造復元(KNOW-F-0336)がその取り決めと一致していないと、ルートを正しく見つけられない。取り決めはコメントや仕様書に明記する。
---
### KNOW-F-0336 配列→木構造復元の型
**構造の型**:
```
index = 配列をidで索引作り(KNOW-F-0329)、各要素にchildren:[]を追加
for x of 配列:
if x.parentId is null: ルート.push(index[x.id])
else: index[x.parentId].children.push(index[x.id])
```
KNOW-F-0335でフラット化された親子ID付きの配列から、元の入れ子構造を組み立て直す構造。索引作り(KNOW-F-0329)と組み合わせて使うのが典型的な実装である。
**使いどころ**: データベースから取得したフラットなテーブルの行を、画面表示用の木構造(階層メニューやツリービューなど)に組み立て直したいときに使う。
**組合せ例**: KNOW-F-0335でフラット化した[{id:1,parentId:null}, {id:2,parentId:1}, {id:5,parentId:2}, {id:3,parentId:1}, {id:4,parentId:3}]を復元すると、まずid索引を作り、parentIdがnullのid1をルートとし、id2とid3をid1のchildrenに、id5をid2のchildrenに、id4をid3のchildrenに、それぞれ登録していくことで、KNOW-F-0333・0334で使った拡張版T'と同じ入れ子構造が再現される。
**確認事項**: フラット配列の中に、存在しないparentIdを指す行(親が見つからない孤立データ)が混ざっていると、その行がどこにも接続されず木から漏れ落ちる。復元処理の最後に「配列の件数」と「木を再帰的に数え上げた件数」が一致するかを検算し、漏れがないかを確認する習慣が有効である。
---
### KNOW-F-0337 正規化(ID参照化)の型
**構造の型**:
```
正規化前: 注文の中に顧客情報が丸ごと埋め込まれている(同じ顧客情報が複数の注文に重複して存在)
正規化後: 顧客テーブルを1本にまとめ、注文側は顧客IDだけを参照として持つ
```
同じデータ(顧客情報など)が複数箇所に埋め込まれて重複している状態から、重複部分を1箇所にまとめ、他の箇所からはIDによる参照だけにする構造。
**使いどころ**: 同じ実体(顧客・商品など)が複数のレコードに繰り返し登場するデータを保存・更新するときに使う。埋め込まれた情報を更新するたびに、全箇所を漏れなく書き換える手間と矛盾のリスクを避けられる。表示のたびにIDから実体を引き直すコストが問題になる場合は非正規化(KNOW-F-0338)を検討する。
**組合せ例**: 正規化前は注文1と注文2の両方に顧客(id:1,name:"佐藤")という同じ内容のオブジェクトが埋め込まれている。正規化後は顧客テーブル{1:{id:1,name:"佐藤"}}を1本用意し、注文側は{orderId:101,customerId:1,total:1000}、{orderId:102,customerId:1,total:2000}のように顧客IDだけを持つ。顧客の名前が変わった場合、正規化前なら埋め込まれた全注文を書き換える必要があるが、正規化後は顧客テーブルの1件を書き換えるだけで済む。
**確認事項**: 正規化のしすぎ(過度に細かくテーブルを分割すること)は、表示のたびに多数のID参照を実体に引き直す処理(非正規化、KNOW-F-0338)の手間を増やす。読み取り頻度と更新頻度のバランスを見て、どこまで正規化するかを判断する。
---
### KNOW-F-0338 非正規化(埋め込み復元)の型
**構造の型**:
```
非正規化(注文, 顧客索引):
注文.customer = 顧客索引[注文.customerId]
return 注文
```
正規化(KNOW-F-0337)されたID参照だけのデータに、参照先の実体を埋め込み直し、表示や1件のオブジェクトとして扱いやすい形に戻す構造。索引作り(KNOW-F-0329)と組み合わせて使う。
**使いどころ**: 画面に注文一覧を表示する際、注文ごとに顧客名も一緒に表示したい場合、正規化されたデータのままでは毎回IDから顧客を探す手間がかかるため、事前に顧客索引を作ってから一括で埋め込んでおく。
**組合せ例**: KNOW-F-0337で正規化した注文{orderId:101,customerId:1,total:1000}に、顧客索引{1:{id:1,name:"佐藤"}}を使って非正規化を適用すると{orderId:101,customerId:1,total:1000,customer:{id:1,name:"佐藤"}}のように顧客情報が埋め込まれた形に戻る。
**確認事項**: 非正規化して埋め込んだ顧客情報を注文側で直接書き換えてしまうと、正規化された本来の顧客テーブルとは別のコピーを書き換えたことになり、データの一貫性が崩れる。非正規化した埋め込みデータは「表示専用の複製」であり、更新は必ず正規化された側(正のデータ)に対して行う。
---
### KNOW-F-0339 ピボット変換(行列転置)の型
**構造の型**:
```
transpose(M):
結果[j][i] = M[i][j] (行と列を入れ替える)
```
2次元配列(行列)の行と列を入れ替える構造。
**使いどころ**: 「行が項目・列が日付」のデータを「行が日付・列が項目」に組み替えたいときのように、表の見せ方の軸を入れ替えたい場面で使う。
**組合せ例**: 2行3列の行列M=[[1,2,3],[4,5,6]]を転置すると、3行2列の[[1,4],[2,5],[3,6]]になる(M[0][0]=1とM[1][0]=4が新しい1行目、M[0][1]=2とM[1][1]=5が新しい2行目、M[0][2]=3とM[1][2]=6が新しい3行目)。転置を2回行うと元の行列に戻ることが往復検算になる。
**確認事項**: 行列が正方形(行数と列数が同じ)でない場合、転置後は行数と列数が入れ替わる(2行3列は3行2列になる)ため、転置前後で同じ添字アクセスをそのまま使うと範囲外エラーになる。転置後の次元を都度確認してからアクセスする。
---
### KNOW-F-0340 集計テーブル生成(crosstab)の型
**構造の型**:
```
crosstab = {}
for record of 明細:
row = record[行キー]; col = record[列キー]
if row not in crosstab: crosstab[row] = {}
crosstab[row][col] = (crosstab[row][col] || 0) + record[値]
```
明細データ(1行1件の記録)を、行方向のキーと列方向のキーの組合せごとに値を集計した、行×列の表(クロス集計表)へ変換する構造。グループ化(KNOW-F-0328)を2段階(行キー・列キー)に拡張したものにあたる。
**使いどころ**: 「部署別×月別の売上」のように、2つの軸で同時に集計した表を作りたいときに使う。1つの軸だけで集計するならグループ化(KNOW-F-0328)だけで十分である。
**組合せ例**: 明細[{dept:"営業",month:"1月",amount:100}, {dept:"営業",month:"2月",amount:150}, {dept:"開発",month:"1月",amount:80}]を部署(行)×月(列)でcrosstabすると{"営業":{"1月":100,"2月":150}, "開発":{"1月":80}}になる。全体の合計100+150+80=330が、明細3件のamountの合計と一致することを検算できる。
**確認事項**: ある行×列の組合せに該当する明細が1件もない場合(この例では「開発」×「2月」)、crosstabの結果にそのキー自体が存在しない(0件ではなくキー欠落)ことがあり、後続処理でそのキーに直接アクセスするとエラーになる。存在しない組合せは0として扱うデフォルト値補完(KNOW-F-0347)を組み合わせておくと安全である。
---
### KNOW-F-0341 キー名変換(camelCase⇄snake_case)の型
**構造の型**:
```
snake→camel: user_name → userName (アンダースコアを除去し、次の文字を大文字化)
camel→snake: userName → user_name (大文字の前にアンダースコアを挿入し、小文字化)
```
プログラミング言語やシステムごとに異なる命名規則(単語をアンダースコアでつなぐsnake_caseと、単語の先頭を大文字にしてつなぐcamelCase)の間で、オブジェクトのキー名を変換する構造。
**使いどころ**: バックエンドのAPIがsnake_caseでフィールド名を返し、フロントエンドの言語の慣習がcamelCaseである、というように、システム間で命名規則が異なる場合の橋渡しとして使う。
**組合せ例**: {user_name:"太郎", user_age:20}をsnake→camel変換すると{userName:"太郎", userAge:20}になる。逆にcamel→snake変換を適用すると元の{user_name:"太郎", user_age:20}に戻ることが往復検算になる。
**確認事項**: すでに大文字を含むキー(略語を含むAPIIDのようなキー)や、数字を含むキー(item2Name等)の変換規則は事前に取り決めておかないと、変換の実装によって結果がぶれる。ネストしたオブジェクトの内側のキーまで変換対象にするかどうかも仕様として明記しておく。
---
### KNOW-F-0342 スキーマ間マッピング(DTO変換)の型
**構造の型**:
```
mapToDto(internal):
return {
user_id: internal.id,
name: internal.fullName,
created: internal.createdAt
}
```
プログラム内部で使うデータの形(内部モデル)と、外部に公開するAPIの形(DTO、データ転送オブジェクト)が異なる場合に、両者を対応づけて変換する構造。単なるキー名変換(KNOW-F-0341)よりも一般化されており、フィールドの追加・削除・値の加工も含む。
**使いどころ**: 内部のデータ構造をそのまま外部に公開すると、内部の実装変更が外部の利用者に直接影響してしまうため、公開用の形(DTO)を内部モデルとは独立に保ちたいときに使う。
**組合せ例**: 内部モデル{id:1, fullName:"佐藤太郎", createdAt:"2026-07-10", internalNote:"社内メモ"}を外部向けDTOにマッピングすると{user_id:1, name:"佐藤太郎", created:"2026-07-10"}になり、内部専用のinternalNoteフィールドはDTOには含まれない(意図的に除外されている)。
**確認事項**: マッピング関数に新しいフィールドを内部モデル側に追加しても、マッピング関数自体を修正しない限りDTO側には反映されない(自動的には同期しない)。内部モデルの変更時にマッピング関数の見直しが必要かどうかを、変更のたびにチェックリストとして確認する運用が有効である。
---
### KNOW-F-0343 差分抽出(diff)の型
**構造の型**:
```
diff(old, new):
added = newのキーのうちoldに存在しないもの
removed = oldのキーのうちnewに存在しないもの
changed = 両方に存在するが値が異なるキー
```
2つのオブジェクトを比較し、「追加されたもの」「削除されたもの」「変更されたもの」の3種類に分類する構造。
**使いどころ**: 編集前後のデータを比較して変更履歴を記録したい、同期処理で送るべき差分だけを抽出したいときに使う。
**組合せ例**: old={a:1,b:2,c:3}とnew={a:1,b:5,d:4}を比較すると、キーcはnewに存在しないためremoved({c:3})、キーdはoldに存在しないためadded({d:4})、キーbは両方に存在するが値が2から5に変わっているためchanged({b:{old:2,new:5}})、キーaは値が変わっていないため差分には含まれない、という分類になる。
**確認事項**: 値がオブジェクトや配列である場合、単純な等値比較(===)では常に「異なる」と判定される(参照が異なるため、内容が同じでも不一致)。ネストした値の差分を正しく検出するには、再帰的にdiffを適用するか、ディープコピー(KNOW-F-0331)と組み合わせた内容比較が必要になる。
---
### KNOW-F-0344 パッチ適用(merge)の型
**構造の型**:
```
applyPatch(old, patch):
結果 = old のコピー
for key, value of patch:
if value == 削除マーカー: 結果から key を削除
else: 結果[key] = value
return 結果
```
差分抽出(KNOW-F-0343)で得られた変更内容(パッチ)を、元のデータに適用して新しい状態を作る構造。diffとpatchは、diff(old,new)で得たパッチをoldに適用するとnewが再現できるという、対になる関係にある。
**使いどころ**: 変更履歴(パッチの列)を保存しておき、必要なときに元データへ順番に適用して任意の時点の状態を復元したいときに使う。通信量を減らすため、変更されたフィールドだけを送受信したい同期処理にも使う。
**組合せ例**: KNOW-F-0343のdiff結果(added:{d:4}, removed:{c:3}, changed:{b:{old:2,new:5}})をパッチとしてold={a:1,b:2,c:3}に適用すると、bを5に変更し、cを削除し、dを4として追加した結果{a:1,b:5,d:4}になり、これはKNOW-F-0343で比較した元のnewと完全に一致する(往復検算)。
**確認事項**: パッチを適用する順序が複数ある場合、後から適用したパッチが先のパッチを上書きすることがあるため、パッチには適用順序(タイムスタンプや連番)を持たせておく。同じキーに対する複数のパッチが競合する場合の解決ルール(最後勝ちか、手動でのマージか)も事前に決めておく。
---
### KNOW-F-0345 循環参照検出の型
**構造の型**:
```
traverse(obj, 訪問済み = 新しい集合):
if obj が 訪問済み に含まれる: 循環参照として処理を打ち切る
訪問済み.add(obj)
obj の各値について再帰的に traverse
```
オブジェクトの内部が、直接または間接的に自分自身を参照している(a.ref=b, b.ref=aのように輪を作っている)状態を検出し、無限ループに陥る前に処理を打ち切る構造。
**使いどころ**: ディープコピー(KNOW-F-0331)・差分抽出(KNOW-F-0343)・JSON文字列化(KNOW-F-0295)など、オブジェクトを再帰的にたどるあらゆる処理の安全装置として使う。外部から受け取ったデータのように、循環参照が絶対に含まれないと保証できない場合には必ず組み込む。
**組合せ例**: a={name:"A"}、b={name:"B", ref:a}という2つのオブジェクトを作り、続けてa.ref=bとして相互に参照させると、aから出発してa.ref(=b)、b.ref(=a)とたどると再びaに戻ってくる循環ができる。訪問済み集合を使わずに単純な再帰でJSON文字列化のような処理を行うと、この循環をたどり続けて無限再帰(スタックオーバーフロー)に陥る。訪問済み集合にaとbを登録しておけば、2周目にaへ戻ってきた時点で「訪問済み」と検出して打ち切れる。
**確認事項**: 訪問済みの判定には、値の内容ではなく「同じオブジェクトの参照であるかどうか」を使う必要がある。内容が同じでも別の参照であるオブジェクト同士を誤って「循環」と判定してしまうと、循環していない正常なデータの処理まで途中で打ち切られてしまう。
---
### KNOW-F-0346 部分集合抽出(pick/omit)の型
**構造の型**:
```
pick(obj, keys) = keysに指定したキーだけを残したオブジェクト
omit(obj, keys) = keysに指定したキーだけを除いたオブジェクト
```
オブジェクトから、必要なキーだけを選び出す(pick)か、不要なキーだけを取り除く(omit)ことで、フィールド数を絞り込んだ新しいオブジェクトを作る構造。
**使いどころ**: 外部に公開してよいフィールドだけを残したい(pick)、内部専用のフィールドだけを取り除きたい(omit)というように、スキーマ間マッピング(KNOW-F-0342)の簡易版として使う。マッピング先で名前を変えたり値を加工したりする必要がなく、単に絞り込むだけでよい場合に選ぶ。
**組合せ例**: obj={id:1,name:"佐藤",dept:"営業",salary:500000}に対しpick(obj,["id","name"])を適用すると{id:1,name:"佐藤"}になり、omit(obj,["salary"])を適用すると{id:1,name:"佐藤",dept:"営業"}になる。給与のように機密性の高いフィールドを画面表示用のデータから確実に除きたい場合、omitで除外リストを管理するよりpickで許可リストを管理するほうが、新しいフィールドが追加されたときに意図せず漏れる事故を防ぎやすい。
**確認事項**: omit方式は「今あるフィールドを除く」設計であるため、後から追加された新しいフィールド(将来salaryと同じくらい機密性の高い項目が追加された場合)が除外リストに入っていないと、意図せず公開されてしまう。機密情報を扱う場面ではpick方式(許可リスト、KNOW-F-0370のホワイトリスト方式検証と同じ考え方)を優先する。
---
### KNOW-F-0347 デフォルト値補完(defaults)の型
**構造の型**:
```
結果 = { ...既定値のオブジェクト, ...入力オブジェクト }
(入力オブジェクトに値があればそちらが優先され、なければ既定値が残る)
```
入力データに一部の項目が欠けている場合、あらかじめ用意した既定値で不足分を補い、完全な形のオブジェクトを作る構造。
**使いどころ**: 設定ファイルやフォーム入力のように、すべての項目が必ず埋まっているとは限らないデータを、後続処理が扱いやすい完全な形に整えたいときに使う。
**組合せ例**: 既定値{name:"名無し", age:0, dept:"未所属"}に対し、入力{name:"佐藤"}を補完すると{name:"佐藤", age:0, dept:"未所属"}になる(nameは入力の値が優先され、ageとdeptは入力になかったため既定値のまま残る)。
**確認事項**: 浅いマージ(スプレッド構文による1階層だけの合成)を使う場合、既定値の中の入れ子オブジェクトの一部だけを入力で上書きしようとすると、KNOW-F-0332のディープマージと同じ問題(入れ子全体が丸ごと置き換わる)が起こる。既定値に入れ子がある場合はディープマージを使う。
---
### KNOW-F-0348 座標変換(2D⇄1Dインデックス)の型
**構造の型**:
```
2D→1D: index = row * 幅 + col
1D→2D: row = floor(index / 幅), col = index mod 幅
```
2次元の格子(行と列)上の位置を、1本のメモリ配列上の添字と相互に変換する構造。PC創造大全の脊椎a部「メモリ番地=巨大な配列」の考え方を、2次元データ(画像・盤面ゲームなど)に具体的に適用したものである。
**使いどころ**: 画像のピクセルデータやゲームの盤面のように、概念上は2次元だが実際には1本の連続したメモリ領域に格納されているデータへアクセスするときに使う。
**組合せ例**: 幅5の格子で(行2, 列3)の位置を1次元添字に変換すると、2×5+3=13になる。逆に添字13から2次元位置を復元すると、13÷5=2あまり3より、行は2(13を5で割った商を切り捨て)、列は3(13を5で割った余り)となり、元の(行2, 列3)に一致する(検算: 2×5+3=13で往復が確認できる)。
**確認事項**: 幅の値を取り違える(実際の格子の幅と異なる値で変換する)と、全く別の位置を指してしまう静かなバグになる。行・列のどちらを先に掛けるか(row*幅+colか、col*高さ+rowか)は実装ごとの取り決めであり、格子の向き(横に並ぶのが行か列か)と合わせて必ず統一する。
---
### KNOW-F-0349 グラフ隣接リスト構築の型
**構造の型**:
```
adjacency = {}
for [u, v] of 辺の配列:
if u not in adjacency: adjacency[u] = []
if v not in adjacency: adjacency[v] = []
adjacency[u].push(v)
adjacency[v].push(u) // 無向グラフの場合、両方向に登録
```
「頂点と頂点をつなぐ辺」の一覧(辺リスト)から、各頂点ごとに「つながっている相手の一覧」を持つオブジェクト(隣接リスト)へ変換する構造。木構造(親子関係のみ)よりも一般的な、双方向・多対多の関係を表現できる。
**使いどころ**: 友人関係・部品同士の依存関係のように、木構造では表現しきれない多対多の関係を扱いたいときに使う。DFS(KNOW-F-0333)やBFS(KNOW-F-0334)は、木構造だけでなくこの隣接リストの形のグラフに対しても同じ考え方で適用できる(訪問済み集合を併用して同じ頂点を2回訪れないようにする点が木構造の走査との違いになる)。
**組合せ例**: 辺リスト[[1,2],[1,3],[2,3]](頂点1-2、1-3、2-3がそれぞれつながっている)から隣接リストを構築すると{1:[2,3], 2:[1,3], 3:[1,2]}になる。頂点1から出ている辺の本数は隣接リストの1の配列の長さ2と一致し、辺リスト全体の本数3の2倍(無向グラフでは各辺が両端点から1回ずつ数えられる)である6と、全頂点の隣接リストの長さの合計2+2+2=6が一致することを検算できる。
**確認事項**: 有向グラフ(一方通行の関係)を扱う場合、両方向への登録(adjacency[v].push(u)の行)を行ってはならない。無向グラフ用の構築コードをそのまま有向グラフに流用すると、存在しない逆方向の関係が紛れ込む典型的な誤りになる。
---
### KNOW-F-0350 構造変換の型まとめ(第4章・分類比較表)
**構造の型(章内の分類表)**:
| 分類 | 該当KNOW-F | 逆操作となる型 |
|---|---|---|
| ネスト⇄フラット | 0326, 0327 | 互いに逆操作 |
| グループ化/索引作り | 0328, 0329, 0330 | (逆操作なし、集約系) |
| 複製/統合 | 0331, 0332 | (逆操作なし、独立化と統合) |
| 木構造の走査 | 0333, 0334 | (逆操作なし、走査順序の違い) |
| 木構造⇄フラット配列 | 0335, 0336 | 互いに逆操作 |
| 正規化⇄非正規化 | 0337, 0338 | 互いに逆操作 |
| 行列/集計変換 | 0339, 0340 | 転置は自己逆操作、crosstabは逆操作なし |
| 命名/スキーマ変換 | 0341, 0342 | 0341は互いに逆操作可能、0342は非対称な場合あり |
| 差分/パッチ | 0343, 0344 | 互いに逆操作(diffしてpatchすると元に戻る) |
| 安全対策/抽出/補完 | 0345, 0346, 0347 | (安全装置・絞り込み・補完) |
| 座標/グラフ変換 | 0348, 0349 | 座標変換は互いに逆操作 |
**使いどころ(章全体の使い分け方針)**: 「往復できる変換(ネスト⇄フラット、正規化⇄非正規化、diff⇄patch、座標変換)」と「往復できない変換(グループ化、木の走査、集計)」を区別することが第4章の要になる。往復可能な変換は必ずどちらの方向にも実装し、検算(変換して戻すと元に一致するか)で正しさを確認する。
**組合せ例(代表的な組合せの並記)**: 正規化(0337)→索引作り(0329)→非正規化(0338)でAPI応答の組み立て、木構造→フラット化(0335)→データベース保存→配列→木構造復元(0336)で階層メニューの永続化、diff(0343)→パッチ配列の保存→パッチ適用(0344)で編集履歴の管理、という3つの往復が第4章全体を通じて繰り返し登場する。
**確認事項(章全体で共有される検証原則)**: 第4章の変換全般に共通する検算原則は「元の件数・合計・階層構造が変換の前後で保たれているか」を数値で確認することである。木構造の全ノード数、集計テーブルの値の合計、diff→patchで元のオブジェクトに戻るかといった具体的な数値・内容の一致を都度確認する習慣が、第4章全体の結びとして特に重要になる。
---
---
## 第5章 検証の型(KNOW-F-0351〜0375)
第1〜4章がすべて「正しい形のデータをどう変換するか」を扱ったのに対し、第5章は「そのデータが本当に正しい形をしているかをどう確かめるか」を扱う。共通サンプルV={name:"", age:17, email:"a@b"}(名前が空文字・年齢17歳・メールアドレスが不完全)を軸に、入力検証とスキーマ的検査という2系統を24種の型として並べる。
### KNOW-F-0351 型検査(typeof)の型
**構造の型**:
```
typeof V.age === "number" // true
typeof V.name === "string" // true(中身が空文字でも型はstring)
```
値がどの基本型(文字列・数値・真偽値・オブジェクトなど)であるかを確認する、最も基礎的な検証構造。
**使いどころ**: 外部(JSONの解析結果やユーザー入力)から受け取った値が、期待する型であることを最初に確認したいときに使う。型が正しいことは値が「妥当」であることを意味しない点に注意し、範囲検査(KNOW-F-0353)や必須項目検査(KNOW-F-0354)と組み合わせて使う。
**組合せ例**: 共通サンプルVのageに対しtypeof検査を行うとtrue(numberである)を返すが、値そのものは17であり、これが「大人として妥当な年齢か」はKNOW-F-0353の範囲検査で別途確認する必要がある。型検査は「土俵に上がる資格があるか」の一次確認にすぎない。
**確認事項**: typeof null が"object"を返す(nullなのに"null"型ではなく"object"型と判定される)という言語仕様上の落とし穴が広く知られており、typeofだけでnullを弾こうとすると失敗する。null/undefined検査(KNOW-F-0352)は型検査とは別に必ず行う。
---
### KNOW-F-0352 null/undefined検査の型
**構造の型**:
```
"middleName" in V // false(そもそもキーが存在しない)
V.name === "" // true(キーは存在するが値が空文字)
V.name == null // false(空文字はnullでもundefinedでもない)
```
「値が存在しない(未定義)」「値が空である」「値が意図的に無効を表す特殊値(null)」という、似て非なる3つの状態を区別する構造。
**使いどころ**: 「入力されなかった」のか「入力されたが空だった」のかで後続処理を分けたい場面で使う。フォームの必須項目チェックでは両方とも「未入力」として扱ってよい場合が多いが、APIのレスポンスでは「フィールド自体が存在しない」ことに別の意味(そもそも計算されていない)を持たせる設計もある。
**組合せ例**: 共通サンプルVには"middleName"というキー自体が存在しないため`"middleName" in V`はfalseになる。一方nameキーは存在するが値が空文字""であるため`V.name === ""`はtrueになり、`V.name == null`はfalse(空文字はnullと等しくない)になる。この3状態を区別しないまま「未入力」判定を書くと、意図しない分岐に落ちる。
**確認事項**: 多くの言語で緩やかな等価演算子(== )はnullとundefinedを等しいとみなすが、空文字や0とは等しいとみなさない。この境界を正確に理解していないと「0という正当な入力値」を「未入力」と誤判定するバグ(空文字・0・falseを一緒くたに「無効」として弾いてしまう)が起こりやすい。
---
### KNOW-F-0353 範囲検査(min/max)の型
**構造の型**:
```
isInRange(x, min, max) = (x >= min) and (x <= max)
```
数値が指定した最小値と最大値の範囲(境界値を含む)に収まっているかを確認する構造。
**使いどころ**: 年齢・数量・パーセンテージのように、意味のある値の範囲があらかじめ決まっている数値項目の検証に使う。範囲の境界を「含むか含まないか」(以上・以下か、より大きい・より小さいか)を仕様として明確にしておく。
**組合せ例**: 共通サンプルVのage=17に対し「成人(18歳以上)であること」という範囲検査(min=18、maxなし)を適用すると、17は18以上ではないため検証は失敗する(17<18)。この失敗を必須項目検査(KNOW-F-0354)の失敗と混同せず、「入力はあるが範囲外」という別種のエラーとして区別して報告する。
**確認事項**: min・maxの境界値そのもの(この例ではちょうど18歳)が検査を通過するかどうかは、「以上」なのか「より大きい」なのかで結果が変わるため、境界値検査(KNOW-F-0364)で必ず個別にテストする。範囲の上限・下限を後から仕様変更する際は、境界値のテストケースも合わせて更新する。
---
### KNOW-F-0354 必須項目検査の型
**構造の型**:
```
isRequired(x) = (x != null) and (x != "") // 文字列項目の場合の典型例
```
その項目が必ず値を持たなければならない(空であってはならない)ことを確認する構造。
**使いどころ**: フォームの入力項目のうち、業務上省略が許されない項目(氏名、注文数量など)の検証に使う。省略が許される任意項目には、この検査を適用しない(適用すると常に失敗してしまう)。
**組合せ例**: 共通サンプルVのname=""に必須項目検査を適用すると、空文字であるため検査は失敗する。同じVのage=17は値が存在するため必須項目検査自体は通過するが、範囲検査(KNOW-F-0353)では別途失敗する、というように、1つの値が複数の検査のうち一部だけを通過することがある。
**確認事項**: 空白文字だけの入力(" "のような、目に見える文字がないがtrimすると空になる文字列)を、必須項目検査の前にtrim(KNOW-F-0278)しておかないと、見た目は未入力なのに「値がある」と誤判定されてしまう。サニタイズ(正規化)と検証の順序(KNOW-F-0362)を意識する。
---
### KNOW-F-0355 正規表現フォーマット検査の型
**構造の型**:
```
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(V.email)
```
値が、正規表現で表現された特定の書式(メールアドレスらしい形、電話番号らしい形など)に一致しているかを確認する構造。
**使いどころ**: 書式が明確に定義できる項目(メールアドレス、郵便番号、電話番号)の形式チェックに使う。「実在するメールアドレスかどうか」まではこの検査だけでは分からず、実際に確認メールを送るなど別の手段が必要になる点は区別しておく。
**組合せ例**: 共通サンプルVのemail="a@b"に対し、上記の正規表現(アットマークの前後に文字があり、かつアットマークの後にドットで区切られたドメイン部分がある形)でフォーマット検査を行うと、"a@b"にはドットで区切られたドメイン部分がないため一致せず、検査は失敗する。"a@b.com"であれば同じ正規表現に一致し成功する。
**確認事項**: メールアドレスの正確な書式を完全に検証する正規表現は非常に複雑になることが知られており、簡略化した正規表現は正当なアドレスを誤って弾く(過剰に厳しい)か、不正なアドレスを通してしまう(緩すぎる)かのどちらかに寄りやすい。実務では「明らかにおかしい形式だけを弾く」程度の緩やかな正規表現検査と、確認メールの送信のような実質的な検証を組み合わせることが多いとされる。
---
### KNOW-F-0356 列挙値検査(許可リスト)の型
**構造の型**:
```
isValidEnum(x, 許可リスト) = 許可リスト.includes(x)
```
値が、あらかじめ決められた選択肢の集合(列挙値)のいずれかと一致しているかを確認する構造。
**使いどころ**: ステータス(active/inactive/pendingなど)、都道府県名、性別区分のように、取りうる値が有限で決まっている項目の検証に使う。取りうる値が事実上無限にある(自由記述のテキストなど)項目には適用できない。
**組合せ例**: 許可リスト["active","inactive","pending"]に対し、値"deleted"で列挙値検査を行うと、リストに含まれないため検査は失敗する。列挙値検査の許可リストと、部分集合抽出(KNOW-F-0346)のpickで使うキーの許可リストは、どちらも「あらかじめ決めた集合に含まれるかどうか」を判定するという同じ構造を共有している。
**確認事項**: 許可リストに新しい値(新しいステータス区分の追加など)が必要になった場合、検証コード側の許可リストを更新し忘れると、正当な新しい値まで検査に失敗してしまう。許可リストは検証コードの中に直接書き込むのではなく、設定として一元管理し、コードとデータの両方から同じ定義を参照する設計が望ましい。
---
### KNOW-F-0357 配列要素の一括検証の型
**構造の型**:
```
results = 配列.map(x => 検証関数(x))
全体の妥当性 = results.every(r => r.valid)
```
配列の各要素に対して同じ検証を適用し、全要素が妥当かどうか、あるいはどの要素が妥当でないかを一括で確認する構造。配列操作のmap(KNOW-F-0254)とevery(KNOW-F-0257)を検証の文脈で組み合わせたものである。
**使いどころ**: 一括登録するデータの全件を事前にチェックしたい、CSVの各行を取り込み前に検証したいときに使う。
**組合せ例**: 年齢の配列[17,25,30,-5]に対し「0以上120以下」という範囲検査(KNOW-F-0353)を各要素に適用すると、17と-5が範囲外(17は本来の成人条件18以上ではないが0以上120以下という単純な範囲では通過する点に注意、-5は0未満のため明確に失敗)になる。この例では-5だけが「0以上120以下」の範囲検査には失敗し、17は範囲検査自体は通過することを区別して確認する。
**確認事項**: 配列の一部だけが不正な場合に、全体をまとめて「無効」と扱うのか、有効な要素だけを取り込み不正な要素だけを報告するのかは業務要件次第であり、事前に方針を決めておく。エラー集約(KNOW-F-0361)と組み合わせて、どの添字のどの要素が失敗したかまで報告できるようにしておくと、利用者が修正しやすくなる。
---
### KNOW-F-0358 ネスト構造の再帰検証の型
**構造の型**:
```
validateNested(obj, スキーマ):
for キー, ルール of スキーマ:
if ルールがネストしたスキーマ: validateNested(obj[キー], ルール) // 再帰
else: 単一の検証ルールを適用
```
オブジェクトの中にさらにオブジェクトが入れ子になっている構造(住所オブジェクトの中に郵便番号や都道府県といったさらに細かい項目がある等)を、再帰的にたどりながら検証する構造。木構造の走査(KNOW-F-0333)を検証の文脈に応用したものである。
**使いどころ**: フォームの入力項目が階層構造を持つ場合(注文情報の中に配送先住所というオブジェクトが入っている等)に使う。フラットな項目だけのデータには単純な必須項目検査(KNOW-F-0354)の繰り返しで十分である。
**組合せ例**: {name:"佐藤", address:{zip:"1234", pref:""}}という入れ子構造を検証する場合、まずnameを単一のルールで検証し、addressについては「zipとprefを持つオブジェクトである」というネストしたスキーマに従って再帰的にzipとprefをそれぞれ検証する。この例ではprefが空文字であるため、address.prefの必須項目検査(KNOW-F-0354)が失敗する。
**確認事項**: 再帰検証は循環参照(KNOW-F-0345・0365)を含むデータに対して無限再帰に陥る危険を、木構造の走査と同様に抱えている。外部から受け取った信頼できないデータを検証する場合は、訪問済み集合による安全装置を必ず組み込む。
---
### KNOW-F-0359 スキーマ定義検証の型
**構造の型**:
```
schema = {
name: { type:"string", required:true },
age: { type:"number", min:18 },
email: { type:"string", pattern:/^[^\s@]+@[^\s@]+\.[^\s@]+$/ }
}
```
個々の検証ルール(型・必須・範囲・書式)をその都度バラバラに書くのではなく、項目名ごとにルールをまとめた「スキーマ」として宣言的に定義し、汎用の検証エンジンにそのスキーマを渡して一括検証させる構造。
**使いどころ**: 検証すべき項目数が多いフォームやAPIの入力を扱う場合、個別に検証コードを書くよりスキーマを1箇所にまとめたほうが見通しがよく、項目の追加・変更にも対応しやすい。項目数が少ない単純なチェックには、スキーマを用意するオーバーヘッドのほうが大きい場合がある。
**組合せ例**: 上記のスキーマを共通サンプルVに適用すると、nameは必須だが空文字のため失敗、ageは型は数値で正しいがmin18に対し17は範囲外のため失敗、emailは型は文字列で正しいがpattern(KNOW-F-0355のフォーマット検査)に一致しないため失敗、という3件のエラーが検出される。
**確認事項**: スキーマ定義自体に誤り(min:18のつもりがmin:"18"のように型を取り違えて書いてしまう等)があると、検証エンジンが正しく動作しない。スキーマ自体のテスト(妥当な入力が確かに通り、不当な入力が確かに弾かれることを確認するテスト)を用意しておくことが望ましい。
---
### KNOW-F-0360 カスタムバリデータ合成の型
**構造の型**:
```
compose(必須, 範囲, 書式)(x) = 必須(x) and 範囲(x) and 書式(x)
(いずれか1つでも失敗した時点でfalseを返す、短絡評価)
```
複数の単純な検証関数を論理積(AND)で組み合わせ、1つの項目に対する複合的な検証ルールを作る構造。
**使いどころ**: 1つの項目に「必須かつ範囲内かつ特定の書式」のように複数条件を課したいときに使う。スキーマ定義検証(KNOW-F-0359)がフォーム全体を宣言的に扱うのに対し、本型は1つの項目の検証ロジックをより細かく合成する場面に向く。
**組合せ例**: 必須項目検査(KNOW-F-0354)と範囲検査(KNOW-F-0353、18以上)を合成した検証関数をage=17に適用すると、必須項目検査自体は通過する(値は存在する)が、続く範囲検査で失敗するため、合成した検証関数全体としては失敗になる。短絡評価により、最初に失敗した検証以降の検証は実行されない。
**確認事項**: 短絡評価(最初の失敗で打ち切る)を使う設計では、2つ目以降の検証エラーが実行されずに隠れてしまうため、どのルールに違反しているかを利用者にすべて伝えたい場面ではエラー集約(KNOW-F-0361)の設計に切り替える必要がある。合成の順序(どのルールを先に評価するか)によって、どのエラーメッセージが最初に表示されるかが変わる点も設計上の考慮点になる。
---
### KNOW-F-0361 エラー集約(全件収集)の型
**構造の型**:
```
errors = []
for ルール of ルール一覧:
if not ルール(x): errors.push(ルールの説明)
return errors // 空配列なら妥当、1件以上あれば不正
```
最初に見つかったエラーで打ち切る(短絡評価)のではなく、すべてのルールを最後まで評価し、違反したルールをすべて収集する構造。
**使いどころ**: フォームの入力エラーを一度にまとめて利用者へ提示したい(1つ直して再送信するたびに次のエラーが1つずつ出てくる、という体験を避けたい)場面で使う。処理速度が重要で、最初のエラーで即座に打ち切りたい内部処理にはKNOW-F-0360の短絡評価のほうが向く。
**組合せ例**: 共通サンプルVに対しname(必須)・age(範囲18以上)・email(書式)の3つのルールを全件評価すると、いずれも失敗するため、errorsには3件のエラー("nameは必須です","ageは18以上である必要があります","emailの形式が正しくありません")が集まる。利用者はこの3件をまとめて確認し、1回の修正ですべて直すことができる。
**確認事項**: 全件評価は短絡評価よりも計算コストがかかる(必ずすべてのルールを実行する)ため、ルールの数が非常に多い場合や、1つのルールの実行コストが高い場合(外部APIへの問い合わせを伴う検証など)には、処理時間への影響を考慮する。
---
### KNOW-F-0362 サニタイズと検証の分離の型
**構造の型**:
```
サニタイズ(値) = 値を変換して整える(trim・正規化)処理
検証(値) = 値が妥当かどうかを判定するだけの処理(値そのものは変更しない)
入力 → サニタイズ → 検証 → 後続処理
```
「値を書き換える処理」と「値が正しいかを判定するだけの処理」を、1つの関数にまとめず明確に分離する構造。
**使いどころ**: 検証ロジックを単純に保ちたい(検証関数は常に「変更せず判定するだけ」という約束を守る)場合に使う。サニタイズを検証の中に混ぜてしまうと、検証関数を呼ぶたびに値が書き換わるという予測しにくい副作用が生まれる。
**組合せ例**: " a@b.com "(前後に空白を含むメールアドレス)を検証する場合、先にtrim(KNOW-F-0278)というサニタイズ処理で"a@b.com"に整えてから、正規表現フォーマット検査(KNOW-F-0355)という検証処理にかける。検証関数自体はtrimのような変換を一切行わず、渡された値をそのまま判定するだけにとどめる。
**確認事項**: サニタイズの順序(trimしてから大文字小文字を正規化するのか、その逆か)によって最終的に検証にかけられる値が変わりうるため、サニタイズの手順は固定した順序で一貫して適用する。サニタイズしすぎる(本来は不正な入力だったものを、変換によって偶然「妥当」に見えるまで加工してしまう)ことがないよう、サニタイズの範囲は最小限にとどめる。
---
### KNOW-F-0363 型ガード関数の型
**構造の型**:
```
isString(x) = (typeof x === "string")
isNumber(x) = (typeof x === "number") and not isNaN(x)
```
複数の型が混在しうる値(文字列かもしれないし数値かもしれない、というような曖昧な入力)を、以降の処理の分岐の中で「この先はこの型として扱ってよい」と保証するための判定関数。
**使いどころ**: 外部から受け取ったデータの型があらかじめ確定していない場合、以降の処理でその型に固有の操作(文字列ならtrim、数値なら範囲検査)を安全に行いたいときに使う。型ガード関数はNaN伝播とチェックの型(KNOW-F-0310)とも関係が深く、isNumberの実装では単なるtypeof判定だけでなくNaNの除外も併せて行うのが安全である。
**組合せ例**: 値xがisString(x)を満たせばtrim(KNOW-F-0278)のような文字列専用の処理を、isNumber(x)を満たせば範囲検査(KNOW-F-0353)のような数値専用の処理を、それぞれ安全に呼び出せる。どちらの型ガードも満たさない値(オブジェクトや配列など)は、想定外の入力としてエラー集約(KNOW-F-0361)に記録する。
**確認事項**: typeof演算子はNaNに対しても"number"を返す(NaNは数値型に属するが、意味のある数値ではない)ため、isNumberの型ガードでNaNを明示的に除外しないと、後続の範囲検査でNaNとの比較(常にfalseになる、KNOW-F-0310参照)という別の罠に落ちる。
---
### KNOW-F-0364 境界値検査の型
**構造の型**:
```
テストケース = [min-1(不正), min(正常), min+1(正常), max-1(正常), max(正常), max+1(不正)]
```
検査の合否が切り替わる「境界」の直前・直後の値を重点的にテストする構造。範囲検査(KNOW-F-0353)のような「以上・以下」の判定に、意図した境界と実装が一致しているかを確認するために使う。
**使いどころ**: min/maxのような境界を持つすべての検証ルールに対して、実装が完了した直後に必ず行うテスト手法として使う。境界を含まない検証(単純な列挙値検査など)には適用の必要がない。
**組合せ例**: 「18歳以上」という範囲検査(KNOW-F-0353)に対し、17(境界の直前、不正であるべき)・18(境界そのもの、正常であるべき)・19(境界の直後、正常であるべき)の3つをテストすると、共通サンプルVのage=17がまさに「境界の直前」のテストケースに該当し、不正と判定されることが確認できる。もし実装の比較演算子を誤って`>`(より大きい)にしていた場合、18歳ちょうどの人が誤って不正と判定される、というバグを境界値検査で発見できる。
**確認事項**: 境界値検査は「1つずれる」誤り(off-by-oneエラー、以上とより大きいの取り違え)を発見するための手法であり、境界から離れた値だけをテストしていると、この種のバグを見逃す。新しい範囲検査ルールを追加するたびに、境界の直前・直後のテストケースをセットで用意する習慣をつける。
---
### KNOW-F-0365 循環参照データの検証回避の型
**構造の型**:
```
validateWithGuard(obj, 訪問済み = 新しい集合):
if obj が 訪問済み に含まれる: 検証を打ち切り、循環を検出したことだけ記録
訪問済み.add(obj)
ネスト構造の再帰検証(KNOW-F-0358)を継続
```
ネスト構造の再帰検証(KNOW-F-0358)を、循環参照(KNOW-F-0345)を含むデータに対しても安全に行えるようにする安全装置つきの構造。
**使いどころ**: 外部から受け取った、内部構造が完全には信頼できないデータ(ユーザーが自由に組み立てられるJSON構造など)を再帰検証する場合に、必ず組み込む。内部でのみ生成され循環参照が絶対に発生しないと保証できるデータには不要である。
**組合せ例**: KNOW-F-0345で示したa.ref=b, b.ref=aという循環参照を持つデータに、訪問済み集合のない単純な再帰検証をかけると無限再帰に陥る。訪問済み集合を組み込んだ本型を使えば、2周目にaへ戻ってきた時点で「循環を検出した」というエラーを記録し、そこで検証を打ち切って処理を継続できる。
**確認事項**: 循環を検出した場合、検証全体を「不正」として扱うのか、循環している部分だけを除いて残りを検証するのかは業務要件次第である。多くの場合、循環参照そのものがデータの構造として想定外であるため、検証エラーとして明確に報告し、データの生成元を調査する対応が取られる。
---
### KNOW-F-0366 一意性制約検査の型
**構造の型**:
```
seen = 新しい集合
for x of 配列:
if x[キー] in seen: エラーとして記録(重複)
else: seen.add(x[キー])
```
配列の中に、本来一意であるべきキー(メールアドレス、社員番号など)の重複がないかを確認する構造。重複除去(KNOW-F-0267)が「重複を取り除いて通す」のに対し、一意性制約検査は「重複があること自体をエラーとして報告する」点が異なる。
**使いどころ**: 一括登録するユーザーデータの中に同じメールアドレスが複数含まれていないかを事前チェックしたいときに使う。重複があっても後から自動的に1件にまとめてよい場合はKNOW-F-0267の重複除去を使う。
**組合せ例**: メールアドレスの配列["a@x.com","b@x.com","a@x.com"]に一意性制約検査を適用すると、3件目の"a@x.com"が1件目と重複しているため、3件目(またはそのキー)がエラーとして記録される。索引作り(KNOW-F-0329)を行う直前にこの検査を挟んでおくと、索引作成時に静かに上書きされてしまうデータ消失を事前に検出できる。
**確認事項**: 大文字小文字の違い(A@x.comとa@x.com)を同一とみなすかどうかは業務要件次第であり、メールアドレスのように大文字小文字を無視して同一視すべき項目では、比較前に大文字小文字正規化(KNOW-F-0279)を適用してから一意性を判定する。
---
### KNOW-F-0367 条件付き必須項目検証の型
**構造の型**:
```
if V.hasChildren == true:
numberOfChildrenを必須項目検査(KNOW-F-0354)にかける
else:
numberOfChildrenは未入力でもよい
```
ある項目の値によって、別の項目が必須になったり不要になったりする、項目同士の依存関係を検証する構造。
**使いどころ**: 「配送方法が『指定日あり』の場合のみ配送希望日が必須」のように、選択によって必須項目が変わるフォームの検証に使う。すべての項目が常に必須または常に任意である単純なフォームには不要な複雑さである。
**組合せ例**: hasChildren=trueかつnumberOfChildrenが未入力(null)の入力は、条件付き必須項目検証によってエラーになる。一方hasChildren=falseでnumberOfChildrenが未入力の入力は、この項目自体が不要であるため検証を通過する。同じ「numberOfChildrenが未入力」という状態でも、hasChildrenの値次第で合否が変わる点が単純な必須項目検査(KNOW-F-0354)との違いになる。
**確認事項**: 条件付きの依存関係が複数重なると(A→B必須、B→C必須、のような連鎖)、検証ルールの見通しが悪くなりやすい。依存関係が複雑になる場合は、スキーマ定義検証(KNOW-F-0359)の中に条件分岐を明示的な形で記述し、暗黙のif文をコード中に散らばらせない設計が望ましい。
---
### KNOW-F-0368 日付・時刻フォーマット検証の型
**構造の型**:
```
形式検査: /^\d{4}-\d{2}-\d{2}$/.test("2026-07-10") // 桁数と区切りの形だけを確認
実在検査: 月が1〜12の範囲か、日がその月の実際の日数以内か(うるう年を含む)
```
日付や時刻の文字列が、まず「見た目の形式」(桁数と区切り文字)に一致しているかを確認し、次に「実在する日付か」(2月30日のような存在しない日付でないか)を確認する、2段階の検証構造。
**使いどころ**: フォームで日付を文字列として受け取る場合の検証に使う。形式検査だけでは"2026-13-40"のような形は正しいが実在しない日付を見逃してしまうため、実在検査を必ず組み合わせる。
**組合せ例**: "2026-07-10"は形式検査(4桁-2桁-2桁の形)に一致し、実在検査でも7月10日は実在する日付であるため両方を通過する。"2026-13-40"は形式検査(桁数と区切りの形)には一致してしまうが、13月という月は実在しないため実在検査で失敗する。形式検査だけで満足せず、必ず両段階を実施する必要があることがこの例で分かる。
**確認事項**: うるう年の判定(4で割り切れるが100で割り切れる年は平年、ただし400で割り切れる年はうるう年、という規則)を誤って実装すると、2月29日の実在検査が特定の年だけ誤った結果になる。日付の実在検査は自前で実装せず、信頼できる標準ライブラリの日付解析機能に判定を委ねるのが安全である。
---
### KNOW-F-0369 数値文字列検証(符号・先頭ゼロ)の型
**構造の型**:
```
郵便番号のような桁固定コード: 先頭ゼロを許容する(例: "007"は妥当)
数量のような量を表す数値: 先頭ゼロを許容しない(例: "007"は不正、"7"が正しい)
```
数字だけからなる文字列を検証する際、その文字列が「コード(識別子)」なのか「数量(量)」なのかによって、先頭ゼロや符号の扱いを変える必要があるという構造。
**使いどころ**: 郵便番号・社員番号・電話番号のような「見た目は数字だが実際にはコード」の項目と、個数・金額のような「本当の数量」の項目を区別して検証したいときに使う。両者を同じ「数値として妥当か」という単純な基準だけで検証すると、片方の要件を満たせない。
**組合せ例**: 郵便番号の文字列"0123"は、先頭ゼロを含むコードとして妥当だが、これを単純にNumber変換すると123という数値になり先頭ゼロの情報(4桁であるという体裁)が失われる。数量を表す入力"+5"(符号つき)や"007"(先頭ゼロ)は、業務によっては不正な入力として弾く対象になり、正規表現`/^[1-9]\d*$/`(先頭が1〜9で始まる)のような形式検査で先頭ゼロを禁止する設計が使われることがある。
**確認事項**: コードとして扱うべき数字文字列を誤って数値型に変換してしまうと、先頭ゼロが失われるだけでなく、非常に長い数字コード(20桁のシリアル番号など)では数値の精度限界(KNOW-F-0312のBigIntで扱った限界)にも抵触しうる。数字だけで構成されていても意味が「コード」である項目は、文字列型のまま保持し、数値としての演算を行わない設計にする。
---
### KNOW-F-0370 ホワイトリスト方式検証の型
**構造の型**:
```
isValid(x) = 許可リスト.includes(x) // 許可されたものだけを通す
```
「安全である」「妥当である」と確認できたものだけを通過させ、それ以外はすべて拒否する検証方式。列挙値検査(KNOW-F-0356)や部分集合抽出のpick(KNOW-F-0346)の根底にある考え方を、検証方式の分類として一般化したものである。
**使いどころ**: 取りうる値の集合があらかじめ明確に定義できる場面(ステータス値、許可されたファイル拡張子、公開してよいフィールド名)で、安全性を優先したいときに使う。取りうる値が事実上無限にある(自由記述の文章)場面では適用できない。
**組合せ例**: アップロードを許可するファイルの拡張子を[".jpg",".png",".gif"]というホワイトリストで管理する場合、".exe"のような未知の拡張子は自動的に拒否される(リストに載っていないため)。新しい安全な拡張子(".webp"など)を許可したくなった場合は、明示的にリストへ追加する作業が必要になる。
**確認事項**: ホワイトリスト方式は「安全と確認したものだけ通す」という設計思想上、新しく追加する必要のあるものを追加し忘れると、正当な入力まで拒否してしまう(利便性が下がる)副作用がある。安全性を最優先すべき場面(セキュリティに関わる項目)では、この副作用を受け入れてでもホワイトリスト方式を選ぶのが原則である。
---
### KNOW-F-0371 ブラックリスト方式の限界と型
**構造の型**:
```
isValid(x) = not 禁止リスト.includes(x) // 禁止されたものだけを拒否し、それ以外は通す
```
「危険である」「不正である」と確認できたものだけを拒否し、それ以外はすべて通過させる検証方式。ホワイトリスト方式(KNOW-F-0370)とは正反対の考え方に立つ。
**使いどころ**: 禁止すべきものが少数かつ明確に列挙できる場面(NGワードの一覧など)で、利便性(新しい正当な値を都度追加登録しなくてよい)を優先したいときに使う。安全性が最優先される場面(セキュリティに関わる検証)では、ブラックリスト方式は原則として避ける。
**組合せ例**: 拡張子の検証をホワイトリスト([".jpg",".png",".gif"]のみ許可)ではなくブラックリスト([".exe",".bat"]のみ拒否)で行うと、リストに載っていない未知の危険な拡張子(新しく登場したマルウェアの拡張子など)がすべて素通りしてしまう。ホワイトリスト方式(KNOW-F-0370)であれば、リストに載っていないものは自動的に拒否されるため、この種の見落としが起こらない。
**確認事項**: ブラックリスト方式の本質的な限界は「将来登場する未知の危険」を事前に列挙できない点にある。セキュリティに関わる入力検証では、ブラックリスト方式を主たる防御手段にせず、ホワイトリスト方式(KNOW-F-0370)を優先し、ブラックリストは補助的な追加チェックとしてのみ用いる。
---
### KNOW-F-0372 検証結果表現(Result型/例外)の型
**構造の型**:
```
例外方式: 検証(x) が失敗したら 例外を投げる(呼び出し元は try/catch で受け止める)
Result方式: 検証(x) は常に {valid: true/false, errors: [...]} のような値を返す
```
検証が失敗したことを、プログラムの制御を強制的に中断する例外として表現するか、あるいは通常の戻り値(成功/失敗の情報を含む値)として表現するか、という2つの流儀を扱う構造。
**使いどころ**: 「検証に失敗したらそれ以上処理を進めるべきではない」という状況(データベースへの書き込み直前の最終チェックなど)では例外方式が処理の流れを単純にする。「検証に失敗しても、失敗の詳細を利用者に見せながら処理を続けたい」状況(フォームの入力チェック)ではResult方式のほうが、失敗情報(エラー集約、KNOW-F-0361)を扱いやすい。
**組合せ例**: 共通サンプルVをResult方式で検証すると{valid:false, errors:["nameは必須です","ageは18以上である必要があります","emailの形式が正しくありません"]}のような値が返り、呼び出し元はerrorsの中身を画面に表示できる。同じ検証を例外方式で行うと、最初のエラー(nameの必須違反)を検出した時点で例外が投げられ、後続のageとemailの検証は(呼び出し元がキャッチして再試行しない限り)実行されないままになる。
**確認事項**: 1つのシステムの中で例外方式とResult方式が無秩序に混在すると、呼び出し元がどちらの流儀を期待すればよいか分からなくなる。検証系の関数群は、原則としてどちらか一方の流儀に統一し、途中で混在させる場合は境界(例外をResult型に変換する層など)を明確にする。
---
### KNOW-F-0373 非同期検証(重複確認)の型
**構造の型**:
```
async function isUsernameAvailable(name):
存在確認 = await データベースに問い合わせ(name)
return not 存在確認
```
検証の判定に、その場では完結しない処理(データベースへの問い合わせ、外部APIの呼び出しなど)を必要とする、時間のかかる検証を扱う構造。
**使いどころ**: ユーザー名の重複チェックのように、検証対象のデータ(すでに登録されている全ユーザー名)がプログラムのメモリ上になく、外部に問い合わせないと判定できない検証に使う。メモリ上の値だけで即座に判定できる検証(必須項目検査など)には非同期処理は不要であり、余分な複雑さを持ち込まない。
**組合せ例**: フォームの入力検証で、name(必須項目検査、KNOW-F-0354)やemail(フォーマット検査、KNOW-F-0355)のような即座に判定できる検証をまず同期的に行い、それらがすべて通過した後で初めて、コストの高い非同期の重複確認(KNOW-F-0366の一意性制約検査を、配列ではなくデータベース全体に対して行う版)を実行する、という順序づけが典型的な設計になる。
**確認事項**: 非同期検証の結果が返ってくるまでの間に、利用者が入力を変更したり、複数の検証を同時に実行してしまったりすると、古い問い合わせ結果に基づいて誤った判定を表示する競合状態(レースコンディション)が起こりうる。最新の問い合わせだけを有効とする(古い問い合わせの結果が後から返ってきても無視する)工夫が必要になる。
---
### KNOW-F-0374 検証ルールの再利用合成の型
**構造の型**:
```
ルール一覧 = { required, minLength(n), maxLength(n), pattern(re), range(min,max) }
// 各ルールは「値を受け取り、妥当ならtrueを返す」という共通の形(インターフェース)を持つ
// 複数のフォーム・複数のスキーマ定義(KNOW-F-0359)から、同じルール関数を使い回す
```
required・範囲・書式といった個別の検証ロジック(KNOW-F-0353〜0356など)を、特定の1つのフォームに固定せず、名前つきの部品として切り出し、複数のスキーマ定義(KNOW-F-0359)から共通で呼び出せるようにする構造。カスタムバリデータ合成(KNOW-F-0360)が「1つの項目の中でルールを組み合わせる」ことに焦点があるのに対し、本型は「ルールそのものをシステム全体で使い回す」ことに焦点がある。
**使いどころ**: 同じ検証ロジック(たとえばメールアドレスの書式検査)が複数の画面・複数のフォームで必要になる場合に使う。1つの画面でしか使わない特殊な検証ルールをあえて汎用化する必要はない。
**組合せ例**: required・range(18, null)・pattern(メール正規表現)という3つの再利用可能なルールを部品として用意しておけば、共通サンプルVを検証するスキーマも、別の画面(たとえば会員プロフィール編集フォーム)のスキーマも、同じ部品を組み合わせて定義できる。片方のフォームでrangeルールにバグが見つかり修正した場合、同じ部品を使っているすべてのフォームに修正が自動的に反映される。
**確認事項**: 再利用可能なルール部品の仕様(引数の順序、エラーメッセージの文言)を後から変更すると、その部品を使っているすべてのフォームの挙動が一斉に変わる。影響範囲が広い共通部品であるほど、変更前に利用箇所を洗い出し、意図しない挙動変化がないかを確認する。
---
### KNOW-F-0375 検証の型まとめ(第5章・分類比較表)
**構造の型(章内の分類表)**:
| 分類 | 該当KNOW-F | 検証の対象 |
|---|---|---|
| 基礎検査 | 0351, 0352, 0353, 0354, 0363, 0364 | 単一の値の型・存在・範囲 |
| 書式/列挙検査 | 0355, 0356, 0368, 0369 | 値の形式・許容される選択肢 |
| 構造検査 | 0357, 0358, 0365 | 配列/ネスト/循環参照 |
| 検証の組み立て方 | 0359, 0360, 0361, 0374 | スキーマ・合成・集約・再利用 |
| 運用上の分離/方針 | 0362, 0370, 0371, 0372 | サニタイズ分離・許可/拒否リスト・結果表現 |
| 項目間/外部依存 | 0366, 0367, 0373 | 一意性・条件付き必須・非同期 |
**使いどころ(章全体の使い分け方針)**: 検証は「速く安く判定できるものから先に行う」のが基本方針である。まず基礎検査(型・必須・範囲)を同期的に行い、次に書式検査、最後にコストの高い非同期検証(重複確認など)を行うという順序づけにより、無駄なコストを避けつつ早期にエラーを検出できる。
**組合せ例(代表的な組合せの並記)**: サニタイズ→基礎検査→書式検査(KNOW-F-0362→0354→0355)でユーザー入力の標準的な検証パイプライン、スキーマ定義→エラー集約(KNOW-F-0359→0361)でフォーム全体の一括検証結果の提示、ホワイトリスト→部分集合抽出(KNOW-F-0370→0346)で公開データの安全な絞り込み、という3つの流れが第5章全体を通じて繰り返し登場する。
**確認事項(章全体で共有される検証原則)**: 検証の型全般に共通する原則は「検証は値を変更しない(サニタイズと役割を分ける、KNOW-F-0362)」「境界値は必ず個別にテストする(KNOW-F-0364)」「セキュリティに関わる場面ではホワイトリストを優先する(KNOW-F-0370)」の3点である。共通サンプルV={name:"", age:17, email:"a@b"}が第5章のほぼ全項目を通じて一貫して3件のエラー(必須違反・範囲外・書式不一致)を検出され続けたことが、検証の型が組み合わさっても矛盾なく同じ結論に到達することの確認になっている。
---
---
<!-- SECTION:OUTRO -->
---
<!-- SECTION:INDEX -->
---
<!-- SECTION:REFINFO -->
# BOOK-0358m PC創造大全 目録III データ変換の型125種