[3] [[Unicode]] では、実際には同じ意味を表す列を複数の[[文字]]の列で表せることがあります。
この時、そのうちの一つの表現を代表として定めた上で、それへの変換方法を規定することができ、
その表現、あるいは変換方法を[DFN[[RUBYB[正規化形]@en[normalization form]]]]といいます。
[[正規化形]]に変換することを[DFN[[RUBYB[正規化]@en[normalization]]]]といいます。

* 仕様書

[REFS[
- [6] [CITE@en-us[UAX #15: Unicode Normalization Forms]] ([TIME[2010-09-18 09:52:06 +09:00]] 版) <http://www.unicode.org/reports/tr15/>
- [88] [CITE[[[The Unicode Standard]], Version 13.0 - ch02.pdf]], [TIME[2020-03-09T17:53:32.000Z]], [TIME[2020-12-31T08:27:48.757Z]] <https://www.unicode.org/versions/latest/ch02.pdf#G27986>
- [53] <http://www.unicode.org/versions/latest/ch02.pdf#page=41>
- [54] [[Unicode Standard]] ([TIME[2016-07-19 02:38:02 +09:00]]) <http://www.unicode.org/versions/Unicode9.0.0/ch03.pdf#page=69>
- [164] [CITE[The Unicode Standard, Version 13.0 - ch07.pdf]], [TIME[2020-03-09T17:53:38.000Z]], [TIME[2020-12-07T09:15:13.901Z]] <https://www.unicode.org/versions/latest/ch07.pdf#M9.37081.HeadingBreak.79.Combining.Marks>
- [9] [CITE@en-us[Unicode Character Encoding Stability Policy]] ([TIME[2010-12-28 03:43:17 +09:00]] 版) <http://www.unicode.org/policies/stability_policy.html#Normalization>
- [75] [CITE@en-us[UAX #44: Unicode Character Database]], [TIME[2020-03-06T22:23:11.000Z]], [TIME[2020-10-21T08:38:06.672Z]] <https://www.unicode.org/reports/tr44/#Decompositions_and_Normalization>
]REFS]

* 正規化形

[4] [[正規化形]]にはいくつかのバリエーションがあります。
[FIG(short list)[
- [[NFC]]
- [[NFKC]]
- [[NFD]]
- [[NFKD]]
- [[HFS+のNFD]]
- [[FCC]]
- [[FCD]]
]FIG]

[123] 
[[Unicode正規化]]と他の文字列[[正規化]]を組み合わせたもの、
[[応用]]の[[正規化]]と組み合わせたもの、
[[Unicode正規化]]とは異なる適用範囲での[[正規化]]、
[[Unicode]] 以外の[[文字コード]]の[[正規化]]などについては、
[[文字列正規化]]を参照。



* 正規化形の性質

** 固有性

[24] [RUBYB[固有性]@en[uniqueness]]は [[Unicode]] [[正規化形]]の最も重要な[[設計目標]]とされています。
2つの等価な[[文字列]]の[[正規化形]]は完全に一致します [SRC[>>6 7]]。すなわち、
- [25] 2つの[[文字列]]が[RUBYB[[[正準等価]]]@en[canonical equivalent]]なら、
両者に [[NFC]] を適用した結果は[[一致]]します。また、両者に [[NFD]]
を適用した結果は[[一致]]します。 [SRC[>>6 7]]
- [26] 2つの[[文字列]]が[RUBYB[[[互換性等価]]]@en[compatibility equivalent]]なら、
両者に [[NFKC]] を適用した結果は[[一致]]します。また、両者に [[NFKD]]
を適用した結果は[[一致]]します。 [SRC[>>6 7]]
- [27] [[NFC]], [[NFD]], [[NFKC]], [[NFKD]] はいずれも[[冪等]]です。 [SRC[>>6 7]]
-- [28] これは >>25、>>26 から導かれます。 [SRC[>>6 7]]
-- [46] [[訂正 #5]] による変更以前は実は[[冪等]]でないケースが存在しました。

** 安定性

[29] ここでいう[RUBYB[安定性]@en[stability]]は[[正規化]]に直接関係しない[[文字]]がそのまま無変更で残ることをいいます。具体的には、
- [30] [[互換性分解]]を持った[[文字]]は、 [[NFC]] や [[NFD]] を適用しても元の[[文字]]のまま結果に含まれます。 [SRC[>>6 7]]
- [31] [[結合文字]]が含まれていなければ、 [[NFC]] によって[[文字列]]は変化しないことを原則とします。 [SRC[>>6 7]]
-- [32] [[合成除外表]]に含まれるものは例外です。 [SRC[>>6 7]]
- [33] [[合成]]に無関係な[[結合文字]]が含まれていても、[[合成]]の結果には影響しません。 [SRC[>>6 7]]
-- [34] [[合成済文字]]に対応する[[基底文字]]と[[結合文字]]に加え、更に別の[[結合文字]]があったとしても、
[[結合文字]]同士の順序の如何を問わず、結局[[合成]]は行われ、それに加えてその別の[[結合文字]]が残ります。

** 効率性

[35] [[正規化]]は[RUBYB[効率的]@en[efficiency]]に実装可能であるとされています [SRC[>>6 7]]。
具体的には、
- [36] [[正規化形]]が効率良く実装可能であって、とりわけ既に [[NFC]] または [[NFD]]
である[[文字列]]に対して [[NFC]] を高速に得ることが可能です。 [SRC[>>6 7]]
- [37] [[合成]]を行う[[正規化形]]は、必ずしも最初の形を生成するものではありません。
最小形の計算は高価である可能性があるためです。 [SRC[>>6 7]]

* 安定性

[7] [[Unicode Consortium]] の規定する [[Unicode]] の[[正規化形]]、[[NFC]]、[[NFD]]、
[[NFKC]]、[[NFKD]] については、'''[[安定性]]'''、つまり [[Unicode]] 
の改訂を通じて[[正規化]]に非互換な変更が加わらないことがある程度保証されています。

[58] 基本的には、[[安定性]]は[[文字]]が定義されている[[符号位置]]に関するものです。
新たな [[Unicodeの版]]で新しい[[文字]]が追加されると、その[[符号位置]]の[[正規化]]の結果は変化するかもしれません。

** 強い正規化安定性

[10] [DFN[[RUBYB[[[強い正規化安定性]]]@en[strong normalization stability]]]]: [[Unicode]] 4.1 とそれ以降において、
ある版で割り当て済みの[[文字]]のみから構成される[[文字列]]を[[正規化]]した結果は、
その[[文字列]]を以降の任意の版で[[正規化]]した結果と一致します。
[SRC[>>9]]

[11] そのために、一旦割り当てられた[[文字]]の[[分解写像]]と[[正準結合クラス]]が改訂によって変化しないことが保証されています。
[SRC[>>9]]

[12] この安定性は割り当て済みの[[文字]]のみで構成される場合についてのものであり、
[[未割当]]の[[符号位置]]が含まれているときには必ずしも保証されません。

[38] この安定性が保証されるのは [[Unicode]] 4.1 以降ですが、実際には [[Unicode]] 3 以降においても
[[Corrigendum #2]], [[Corrigendum #3]], [[Corrigendum #4]], [[Corrigendum #5]]
の影響を受けない範囲では成立します。 [SRC[>>6 11.2]]

** 弱い正規化安定性

[13] [DFN[[RUBYB[[[弱い正規化安定性]]]@en[weak normalization stability]]]]:
[[Unicode]] 3.1 とそれ以降において、ある版で割り当て済みの[[文字]]のみから構成される[[文字列]]を[[正規化]]した結果得られる[[文字列]]は、
以降の任意の版においても[[正規化]]済みです。また、それ以前で [[Unicode]] 3.1 までの版であって、
その[[文字列]]に含まれる[[文字]]すべてが含まれる版においてもまた、[[正規化]]済みです。
[SRC[>>9、>>6 11.1]]

[14] そのために、一旦割り当てられた[[文字]]の[[分解写像]]がいくつかの例外ケースを除き改訂によって変化しないこと、
[[正準結合クラス]]が改訂によって変化しないことが保証されています。 [SRC[>>9]]

;; [8] [[Unicode]] [[正規化形]]の[DFN[[RUBYB[[[合成版]]]@en[composition version]]]]は「[[UCD]]
3.1.0」であると規定されています [SRC[>>6 3]]。これは[[弱い正規化安定性]]が 3.1.0 
以降について成立するということです。

[15] [[強い正規化安定性]]が保証されれていれば、[[弱い正規化安定性]]もまた保証されます。

[18] 「XY」の2文字から「Z」の1文字への[[合成]]を追加する場合、
[[弱い正規化安定性]]が満たされるためには、
3文字すべてが新しい[[文字]]であるか、または [VAR[X]] と [VAR[Y]] 
のどちらかだけが古い[[文字]]であるかでなければなりません。 [SRC[>>6 3]]

[20] また、[[正規化]]に影響するような既存の[[文字]]の[[特性]]の変更も認められないことになります。
[SRC[>>6 3]]

*** 例

[16] 「Q + caron」という[[文字]] (の列) を考えます。[[合成版]]である 3.1.0 
にはこれを1[[符号位置]]で表す[[合成済文字]]は含まれていません。
[[基底文字]]と[[結合文字]]の2文字で表すしかなく、これが[[正規形]]です。

[17] その後の版で、「Q + caron」を1文字で表す[[合成済文字]]が追加されたとしましょう。
自然に考えれば「Q-caron」 → 「Q」 + 「caron」という[[合成]] ([[正準分解]]) を追加したいところですが、
そうすると以前の版で [[NFC]] だった「Q」 + 「caron」の2文字の表現が [[NFC]]
ではなくなり、新しい「Q-caron」に[[正規化]]しなければならなくなってしまいます。
これは[[弱い正規化安定性]]の定義に反します。

;; [19] [[Unicode Consortium]] は新しい[[合成]]を追加することを[[非推奨]]としており、
従って「Q-caron」のような[[文字]]が後から追加されることは原則として無いようです。 [SRC[>>6 3]]

** Unicode 3.1 以前の非互換性

[22] [[Unicode]] 3.1.0 が「[[合成版]]」ということは、逆にそれまでの版と現在とでは互換性がない変更が行われていることを意味します。

[23] たとえば [[Unicode]] 2.1.9 において[[ハングル音節]]に関する[[互換性写像]]が削除され、
[[正規化]]の結果が変化しています。 [SRC[>>6 6]]

[43] [[Unicode]] 3.0.1 と 3.1 の間に発行された[[訂正 #2]] では、
誤って[[合成除外表]]から欠落していた1[[文字]]について、
[[合成除外表]]に追加され、非互換性が生じています。

** Unicode 3.1 から Unicode 4.1 までの非互換性

[39] [[UAX #15]] では、[[強い正規化安定性]]が保証されていない [[Unicode]] 4.1 
よりも前の版との互換性が必要な時の対処方法として、
- [40] [[Unicode]] 4.1 以前の動作に近づける [SRC[>>6 11.3]]
- [41] 動作が変わってしまった[[文字]]の利用を禁止する [SRC[>>6 11.4]]

... の2通りを挙げて説明しています。

;; [42] >>41 は利用頻度が少ない[[文字]]だから問題ないことが多かろうなどと説明されていますが、
ひどいもんですなw

[44] [[Unicode]] 3.1 と 4.1 の間には[[訂正 #3]]と[[訂正 #4]]が発行され、
6文字について[[正準分解]]が修正されています。

[45] [[Unicode]] 4.0.1 と 4.1 の間には[[訂正 #5]] が発行され、「[[妨害]]」
の定義が修正されて[[正規化]]の[[冪等性]] (>>27) が保たれるようになっています。
それ以前も[[冪等性]]は設計目標に入っていましたが、定義の誤りにより厳密には成立していませんでした。

* 分解と合成

[55] [[Unicode]] では、[[符号化文字列]][VAR[文字列]]に対して[[正準分解]]、[[正準合成]]、[[互換分解]]といった[[演算]]が定義されています。
4つの[[正規化形]]は、その組み合わせとして次のように定義されています [SRC[>>54]]。

[FIG(list)[
- [[NFC]]: [VAR[文字列]]の[[正準分解]]の[[正準合成]]
- [[NFKC]]: [VAR[文字列]]の[[互換分解]]の[[正準合成]]
- [[NFD]]: [VAR[文字列]]の[[正準分解]]
- [[NFKD]]: [VAR[文字列]]の[[互換分解]]
]FIG]

[67] 次のような[[手順群]]に整理できます [SRC[>>54]]。
[FIG(steps)[
= [64] [VAR[文字列]]に[[完全分解]]を適用します。 
[[NFC]]/[[NFD]] なら[[正準等価性]]を、[[NFKC]]/[[NFKD]] なら[[互換等価性]]を用います。
= [65] [[NFC]]/[[NFKC]] なら、
== [66] [VAR[文字列]]に[[正準合成アルゴリズム]]を適用します。
= [68] それ以外なら、
== [63] [VAR[文字列]]に[[正準再順序付けアルゴリズム]]を適用します。
]FIG]

* 大文字・小文字との関係

[52] >>51 は[[プログラミング言語]]の[[識別子]]について[[大文字・小文字不区別]]と[[正規化]]を両方採用する場合について考察しています。

[REFS[
- [51] [CITE@en-us[UAX #31: Unicode Identifier and Pattern Syntax]] ([TIME[2013-09-30 19:53:19 +09:00]] 版) <http://www.unicode.org/reports/tr31/#normalization_and_case>
]REFS]

* 正規化が好ましくない挙動を示すケース

[124] 
[[Unicode正規化]]は破壊的な演算です。適用は極力避けるべきです。

[125] 
特に、
中長期的に保存する一次データに
[[Unicode正規化]]を適用すると、
元データは二度と回復できなくなってしまいますから、
これは絶対に避けるべきです。

-*-*-


[77] 
[[NFKC]],
[[NFKD]]
は破壊的です。
データの意味を致命的に変化させてしまうことが多いです。
特別に望ましい理由があって避けられない場合を除き、
使うべきではありません。

[80] 
[[NFC]]
が好ましいとされており、
[[NFD]]
はそれと逆方向の変換であるため、
特に理由がなければ
[[NFD]]
は使うべきではありません。

[96] 
[[NFC]] はデータを破壊することがあります。
影響が完全に理解されている場合を除き使うべきではありません。

-*-*-

[94] 
[[日本]]の[[常用漢字]]の[[旧字体]]のかなり多くが[[CJK互換漢字]]で表されています。
[[正規化]]すると[[旧字体]]から[[新字体]]への[[文字化け]]が起こります。

-*-*-

[79] 
[[CJK統合漢字]]との[[字形]]差を[[CJK互換漢字]]で表したものが、
[[正規化]]で破壊されるケースがあります。
(ありますというか、[[符号点]]の個数でいえばそのほうが多い。)

[87] 
その対策で導入された
[[CJK互換漢字]]に対応した [[SVS]] は、
[[CJK互換漢字]]と同じものを表しますが、
[[正規化]]で同一視される関係にはありません。
大元の [[CJK互換漢字]]はただの [[CJK統合漢字]]と同一視されてしまうという、
ねじれた関係にあります。
[SEE[ [[SVS]] ]]

つまり[[正規化]]はデータの破壊には役に立ちますが、
検索の役には立ちません。


-*-*-

[95] 
[[NFC]], [[NFKC]], [[NFKD]] を[[ハングル]]に適用すると望ましからざる結果になることがあります。
[SEE[ [[KS X 1026-1]] ]]

[97] [[NFKC]], [[NFKD]] は[[ハングル]]以外でも文字の意味を考慮しないで似た文字に変化させてしまうものなので、
[[ハングル]]で適用前後で文意が変わってしまうとしても特別に問題ということでもなさそうです。
(文意が変わってしまうケースは[[ハングル]]関係なく [[NFKC]], [[NFKD]] を使うべきではないので。)

[98] 
[[NFC]] は[[古ハングル]]が混じったデータに適用すると[[ハングル音節]]の構造を壊してしまうことがあります。
[SEE[ [[KS X 1026-1]] ]]

-*-*-

[78] 
[[combining enclosing mark]]
を使った合成済文字と[[結合文字列]]とで挙動が異なり、
[[正規化]]の対象から除外されているケースがあります。
[SEE[ [[combining enclosing mark]] ]]

[86] 
[[正準等価]]な[[正規化]]により発生する[[結合文字]]の順序の入れ替えが好ましからざる変化をもたらすことがあります。
[SEE[ [CODE(charname)@en[CGJ]] ]]


[81] 
単独の[[ダイアクリティカルマーク]]の多くは[[互換分解]]で
[CODE[U+0020]] + [[結合文字]]の[[ダイアクリティカルマーク]]に分解されてしまいます。
[CODE[U+0020]]
になることによって都合が悪いケースもあります。
[SEE[ [[結合文字]], [[発音区別符付き仮名]] ]]

[85] 
[[合字]]に[[結合文字]]が付いていた場合、
[[互換分解]]によって[[結合文字]]の[[適用]]先が変化してしまいます。
[SRC[>>164]]


-*-*-

[82] 
[[ラテン文字]]や[[キリル文字]]の[[基底文字]]に重ねる形や一部を変形される形の[[ダイアクリティカルマーク]]
([[overlaid diacritics]])
の扱いは一貫していません。
合成済文字と[[基底文字]] + [[結合文字]]の2種類の表現方法があっても、
大まかにいって、
[[数式]]と[[越南]]用のものは[[正規化]]され、
それ以外の[[ラテン文字]]系のものは[[正規化]]されないようです。
[SRC[>>164, >>88]]

;; [89] 
上下に付け加える[[ダイアクリティカルマーク]]と違って[[字形]]の変化が単純ではないためのようです。
全然[[字形]]が違うのに[[結合文字]]や[[合字]]で処理される[[インド系文字]]とはずいぶん扱いが違います。



[84] 
[[合字]]は[[互換分解]]で分解されるとしても、
[[正準分解]]だけでは分解されません。
例えば
[CODE[U+FB01]] は 「fi」 に[[互換分解]]される
([[正準分解]]されない) [[合字]]です。

[121] 
[[互換分解]]されそうなのにされないケース (事例ごとにされたりされなかったり一貫しないケース)
は珍しくありません。
[SEE[ [[互換分解]] ]]


[83] 
つまり、
[[正規化]]に期待される効果、
例えば一致とか検索とか、
似た文字によるセキュリティー問題の回避のような類には、
[[Unicode]]
で定められている[[正規化形]]では必ずしも十分ではありません。


-*-*-

[115] 
[[正規化]]による[[結合文字]]の順序入れ替えや[[合成済文字]]と[[結合列]]の置換は意味的に等価ということになっていますが、
操作前後の[[レンダリング][文字のレンダリング]]は実装によるところが大きく、
必ずしも同じように表示されるとは限りません。
[SRC[>>114]]

[116] 
規格上はどうだ、意味的にはこう定義されている、といったところで現実はそうなっていません。

[120] 
関連: 
[[正準再順序付け]],
[[発音区別符付き仮名]]


[114] [CITE@ja[PDF 千夜一夜: PDFと文字 (41) – Unicode標準形式NFCの問題点(続き)]], [TIME[2007-11-02T02:02:26.000Z]], [TIME[2023-04-11T14:30:55.242Z]] <https://blog.antenna.co.jp/PDFTool/archives/2006/02/pdf_41.html>


-*-*-

[91] 
何も考えずに [[NFC]] や [[NFKC]] を使えばええやん、
と気づかずにデータを破壊する人々

[92] [CITE@en[Normalization in HTML and CSS]], [TIME[2016-02-06T06:31:42.000Z]], [TIME[2021-08-25T12:02:05.211Z]] <https://www.w3.org/International/questions/qa-html-css-normalization>

[90] [CITE@en[Unicode normalization could change the structure of a URL · Issue #626 · whatwg/url · GitHub]], [TIME[2021-08-25T12:00:06.000Z]] <https://github.com/whatwg/url/issues/626>

[93] 
破壊的変換したら構造が破壊されるの、当たり前じゃんw


- [99] [CITE@ja[[[GlyphWiki]]-ノート:登録できるグリフについて - GlyphWiki]], [TIME[2022-11-24T14:34:26.000Z]] <https://glyphwiki.org/wiki/GlyphWiki-talk:%e7%99%bb%e9%8c%b2%e3%81%a7%e3%81%8d%e3%82%8b%e3%82%b0%e3%83%aa%e3%83%95%e3%81%ab%e3%81%a4%e3%81%84%e3%81%a6>
-- [100] [CITE@ja[グループ:twe_サンドボックス2 - [[GlyphWiki]]]], [TIME[2022-11-24T14:34:55.000Z]] <https://glyphwiki.org/wiki/Group:twe_%e3%82%b5%e3%83%b3%e3%83%89%e3%83%9c%e3%83%83%e3%82%af%e3%82%b92@78>

[101] >>99 
[[字形]]の区別のために [[CJK互換漢字]]を使っている事例、
[[NFC]] だと[[ハングル音節]] + [[ハングル字母]]の2文字になるのを[[ハングル字母]]3文字で表している事例。
これらで非 [[NFC]] が意図的に使われている。

[118] 
[[Twitter]] の [[NFC]] 強制による被害事案: [SEE[ [[異体字]] ]]

[122] [CITE@ja[XユーザーのYusuke S.さん: 「「原稿は必ずコピペ」にも落とし穴があるのでお気をつけください。Macの場合、CJK互換漢字の一部が正規化され、アドビのアプリにペーストしたら字形が変わることがあります。回避策は @monokano さん謹製のアプリを利用するのが最善。 正規化について:https://t.co/opIYxtxwGW https://t.co/7g70Owzxw0」 / X]], [TIME[午後4:59 · 2025年7月24日][2025-07-24T07:59:45.000Z]], [TIME[2025-07-25T07:11:33.000Z]] <https://x.com/Uske_S/status/1948292003944698059>

[5] [CITE@ja[macOS 26 Tahoeで、SynologyなどのNASにネットワーク共有されたボリュームへTime Machineバックアップができない不具合はUnicodeの正規化形式(NFD/NFC)問題が原因で、macOSのSMBサーバーでも発生するので注意を。 | AAPL Ch.]], [[applech2]], [TIME[2025-09-25T08:28:50.000Z]] <https://applech2.com/archives/20250922-macos-26-tahoe-nas-time-machine-issue.html>

[50] >>5 同じシステム上で [[NFC]] にするところと [[NFD]] にするところが混在していることに起因する問題とのこと。

[140] 
[[Apple]] の [[NFD]] 強制による被害: [SEE[ [[HFS+のNFD]], [[濁点問題]] ]]

* 文脈

[61] [[Web]] では、一部で [[NFC]] が使われます。 [[XML]] で[[完全正規化]]も使われます。
[[JavaScript]] の [CODE(DOMm)@en[normalize]] [[メソッド]]は、 [[NFC]]、[[NFD]]、
[[NFKC]]、[[NFKD]] に対応しています。

[119] [[PRECIS]] の[[正規化規則]]は4つの[[正規化形]]のいずれかを要求しています。

[62] それ以外の用法については、各[[正規化形]]の項を参照。

** いつ Unicode 正規化を使うべきか

[138] 
[[正規化]]という字面はいかにもやるべきことのように思わされますが、
実際に [[Unicode正規化]]を使うべき場面は限られています。

- [126] [[Unicode正規化]]を使うことが[MUST[要求]]されている[[プロトコル]]や[[データ形式]]では、
当該 [[Unicode正規化]]を使う以外に選択肢がありません。
-- [127] [[Unicode正規化]]によるデータ破壊が懸念されるケースでは、
当該[[プロトコル]]の利用を断念するしかありません。
- [128] [[文字列の比較]]では、 [[Unicode正規化]]を手順に組み込むことで、
同じ意味の[[文字列]]や似た[[文字]]を同一視することができます。
-- [129] しかし、 [[Unicode正規化]]だけで[[異体字]]の同一視などが実現できると思ってはいけません。
見た目が同じなのに [[Unicode正規化]]で同一にならなかったり、
見た目が違うのに [[Unicode正規化]]で同一になったり、
といった事情は[[文字]]ごとの歴史的経緯で決まっていて、ほとんど統一的な基準がありません。
-- [130] 「親切」な比較は、[[文字体系]]や[[言語]]や適用分野ごとの個別の基準により、
[[大文字・小文字不区別]]だとか、[[平仮名]]と[[片仮名]]の同一視だとか、
[[異体字シソーラス]]のような仕組みが別途必要です。
[[Unicode正規化]]がそのまま過不足なく使えることはまずありません。
- [131] [[文字のレンダリング]]では、
[[shaping]] の過程で
[[Unicode正規化]]やそれに関係する処理を行うことがあります。
-- [132] これは表示したい[[文字列]]の全体に[[Unicode正規化]]を適用するという意味では'''ありません'''。
[[レンダリング]]や[[フォント]]からの[[グリフ]]データの取り出しなどの処理の際に[[文字]]や[[文字体系]]や[[フォント]]形式などの要件に応じて部分文字列に適用することもある、
ということです。
- [133] [[Unicode]] 以外の[[文字コードへの変換][文字コードの変換]]や[[翻字]]等の[[変換]]の処理では、
より多くの入力を当該[[文字コード]]等で記述できるように、
あるいは変換処理の実装上の都合などのため、
[[Unicode正規化]]を使うことがあります。
-- [134] この場合そもそも [[Unicode]] 以外の[[文字コード]]は [[Unicode]]
と異なる符号化モデルを採用しているので、多かれ少なかれ[[文字列]]の意味に影響するような変化が加わってしまうことは避けがたく、
[[文字コードの変換]]の処理の設計者が慎重に検討して [[Unicode正規化]]によって発生する破壊的変化が十分に許容可能だと判断されるなら、
[[Unicode正規化]]による破壊のデメリットよりも変換成功のメリットが上回るということです。
-- [139] この用途でも [[Unicode正規化]]では過不足がある場合もありますから、
変換や変換対象の性質を考慮してケースバイケースで望むのが好ましいでしょう。
- [135] 
[[入力]] (例: [[鍵盤入力]]、[[IME]]) は、
[[NFC]] と [[NFD]] で異なる表現となる場合には [[NFC]] を生成するべきだとよくいわれます。
しかし、これは [[NFC]] を適用するべきという意味ではありません。
-- [136] [[NFC]] を適用したらそうなるという文字列を生成することが好ましいと言っているだけで、
生成文字列に [[NFC]] を適用しろとは言っていません。
-- [137] [[NFC]] にならない文字列を入力したい理由があるとき 
(例: [[旧字体]]を使いたいという意思があるとき)
もあるので、 [[NFC]] を適用するのは不適切です。


** プロトコルの採用正規化法の衝突問題

[102] 
プロトコルAとプロトコルBを組み合わせるとき、プロトコルAとプロトコルBで採用する
[[Unicode正規化形]]が違うと困ったことになります。

[103] 
指定が [[NFC]] と [[NFKC]] ならより厳しい [[NFKC]] にしておけばいいので問題ないです。
しかし指定が [[NFC]] と [[NFD]] なら、同時に従うことができません。
たまたま[[正規化]]によって変化しない[[文字]]だけで構成されるなら両方同時に適用された状態にもなりますが、
そんなシステムは実用に耐えません。

[104] 
こうした不都合が起こらないよう、
[[プロトコル]] ([[文書形式]]、[[データ構造]]等含め) は送信 ([[生成]])
において
[[Unicode正規化]]を強制するべきではありません。

[105] 
これが現実にあまり問題視されないのは、

- [106] [[NFC]] が他の3つよりも人気ある
- [107] 4つの[[Unicode正規化]]のいずれも実はそれほど使われていない

という理由と推測されます。

[108] あまり良く知らずに[[プロトコル]]の仕様書でおすすめされているからという理由で真面目に実装してしまうと、
罠にはまることになります。

* 実装

[REFS[
- [48] [CITE[SADAHIRO Tomoyuki / Unicode-Normalize - search.cpan.org]] ([TIME[2011-04-10 18:07:12 +09:00]] 版) <http://search.cpan.org/dist/Unicode-Normalize/>
]REFS]

[57] [[NFC]]、[[NFD]]、[[NFKC]]、[[NFKD]]、[[FCC]]、[[FCD]] を実装しています。
対応する [[Unicodeの版]]は、[[Perl]] の版に依存します。

[60] [[XS]] 版と [[PP]] 版があります。

[REFS[
- [59] [CITE[Charlint - A Character Normalization Tool]] ([TIME[2009-12-03 17:38:05 +09:00]]) <https://www.w3.org/International/charlint/>
]REFS]

* 関連

[21] >>12 や >>18 のようにありますが、[[合成除外表]]の規定によれば新たな[[正準分解]]が追加されるとすると、
その展開先の[[文字]]に既存の[[文字]]が含まれているなら[[合成除外表]]に追加しなければならないこととなっており、
場合によっては未定義の[[符号位置]]が含まれていても新しい版で結果が変わらないことが保証される場合もあるようです。

* 歴史

[109] [CITE@en[Unicode Normalization thread should slow down; summary needed]], [[L. David Baron]], [TIME[2009-02-07 07:58:32 +09:00]], [TIME[2023-01-23T02:13:34.000Z]], [TIME[2023-04-11T14:22:05.727Z]] <https://lists.w3.org/Archives/Public/www-style/2009Feb/0231.html>

[110] [[i18n]] の専門家を称する人々は各種 [[Web標準]]で 
[[Unicode正規化]]を要求するべきと主張していました ([[平成時代]]中期頃)。
しかし結局有効で有益で統一的な実装戦略を提出できませんでした。

[111] そのためいくつかの (当たり障りのない) 仕様に「できれば」程度の弱いおすすめとして潜り込ませることができたくらいで
(またはまったく世の中に影響のない仕様の要件として提示できたくらいで)、
ほとんどの事業者はまったくスルーしました。

[112] 
そのおかげで有害無益な[[正規化]]で性能が激落ちするとか、
[[文字化け]]が多発するとか、
といった困った事案が [[Web標準]]が原因で発生することは避けられました。

;;
[113] [[Web標準]]以外の要因では起きてしまっていますが、まあ不幸中の幸いといったところでしょうか。

* メモ

[1] [CITE[XProc: An XML Pipeline Language]]
([TIME[2010-05-11 22:38:07 +09:00]] 版)
<http://www.w3.org/TR/2010/REC-xproc-20100511/#p.serialization>

[2] [CITE@EN[XQuery 1.0 and XPath 2.0 Functions and Operators (Second Edition)]]
( ([TIME[2010-12-17 00:06:54 +09:00]] 版))
<http://www.w3.org/TR/2010/REC-xpath-functions-20101214/#func-normalize-unicode>

[47] [CITE@en[draft-duerst-i18n-norm - Character Normalization in IETF Protocols]]
<http://tools.ietf.org/html/draft-duerst-i18n-norm>

[49] [CITE@en[Character Model for the World Wide Web 1.0: Normalization]]
( ([TIME[2012-04-27 20:15:23 +09:00]] 版))
<http://www.w3.org/TR/2012/WD-charmod-norm-20120501/>

[56] [CITE@EN[XPath and XQuery Functions and Operators 3.0]]
( ([TIME[2014-04-08 07:02:07 +09:00]] 版))
<http://www.w3.org/TR/xpath-functions-3/#func-normalize-unicode>

[69] [CITE@en[XSLT 2.0 and XQuery 1.0 Serialization (Second Edition)]]
( ([TIME[2010-12-17 00:08:20 +09:00]] 版))
<http://www.w3.org/TR/2010/REC-xslt-xquery-serialization-20101214/#unicode-normalization>

[70] [CITE@en[XSLT 2.0 and XQuery 1.0 Serialization (Second Edition)]]
( ([TIME[2010-12-17 00:08:20 +09:00]] 版))
<http://www.w3.org/TR/2010/REC-xslt-xquery-serialization-20101214/#XML_NORMALIZATION-FORM>

[71] [CITE@EN[XPath and XQuery Functions and Operators 3.1]] ([TIME[2017-03-21 16:02:06 +09:00]]) <https://www.w3.org/TR/2017/REC-xpath-functions-31-20170321/#func-normalize-unicode>

[72] [CITE@en[XSLT and XQuery Serialization 3.1]]
([TIME[2017-03-20 12:35:18 +09:00]])
<https://www.w3.org/TR/2017/REC-xslt-xquery-serialization-31-20170321/#XML_NORMALIZATION-FORM>

[73] [CITE@en-us[UTS #22: CharMapML]]
([TIME[2017-06-01 07:35:01 +09:00]])
<http://www.unicode.org/reports/tr22/tr22-8.html#att_normalization>

[74] [CITE@en[Regexp.ja · neologd/mecab-ipadic-neologd Wiki]]
([TIME[2019-08-04 09:52:04 +09:00]])
<https://github.com/neologd/mecab-ipadic-neologd/wiki/Regexp.ja>

[76] [CITE@en-us[UAX #44: Unicode Character Database]]
([TIME[2020-03-06T22:23:11.000Z]], [TIME[2020-10-21T08:57:57.428Z]])
<https://www.unicode.org/reports/tr44/#NormalizationTest_txt>

[117] [CITE@en[ENSIP-15: Normalization Standard - ENS Documentation]], [TIME[2023-08-10T02:58:14.000Z]] <https://docs.ens.domains/ens-improvement-proposals/ensip-15-normalization-standard>
