<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body><section><h1>概要</h1><p><anchor-end xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="2" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">[2]</anchor-end> <anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">結合文字</anchor>の順序に関する
<anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">nondistict order</anchor>
規則に立脚しています。</p><p><anchor-end xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="3" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">[3]</anchor-end> 
<anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">結合文字</anchor>が
<code>ccc</code>
に従い<anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">整列</anchor>されます。</p></section><section><h1>長さ制限</h1><p><anchor-end xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="8" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">[8]</anchor-end> 
仕様上は<anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">結合文字列</anchor>に長さ制限はありません。しかし、
<anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">結合文字</anchor>が1GB分続いた後の<anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">結合文字</anchor>を前に持ってくる、
なんてことができる実装方法が現実的とは思えません。</p><p><anchor-end xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="6" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">[6]</anchor-end> 
<cite xml:lang="en-us">UAX #15: Unicode Normalization Forms</cite>, <time>2024-08-14T19:11:21.000Z</time>, <time>2025-07-02T03:34:49.968Z</time> <anchor-external xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:resScheme="URI" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:resParameter="https://unicode.org/reports/tr15/#Stream_Safe_Text_Format">https://unicode.org/reports/tr15/#Stream_Safe_Text_Format</anchor-external></p><p><anchor-end xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="7" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">[7]</anchor-end> 
<anchor-internal xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="6" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">&gt;&gt;6</anchor-internal> は
<anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">Stream-Safe Text Format</anchor>,
<anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">Stream-Safe Text Process</anchor>
なる謎概念を導入してます。</p><p><anchor-end xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="9" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">[9]</anchor-end> 
<dfn>Stream-Safe Text Process</dfn>
は任意の入力から
<anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">Stream-Safe Text Format</anchor>
を生成する操作です。
そのために
<sw-cc xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">CGJ</sw-cc>
が挿入されます。</p><p><anchor-end xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="10" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">[10]</anchor-end> 
しかしながら、これは <anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">Unicode正規化</anchor>が安全にできるための<anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">前処理</anchor>で、
<anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">正規化</anchor>の手順そのものに組み込まれていないので、別途明示的に適用しなければなりませんが、
これが実装されているところは見たことがありません。
さすがにどこかに実装事例くらいはあるでしょうが。
その実装を使っているところはもっと見たことがありません。</p><comment-p xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:10:"><anchor-end xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="12" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">[12]</anchor-end> <anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">アプリケーション</anchor>の独自の処理ならこの方法を使いたいと開発者が考えれば使えますが、
<anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">プロトコル</anchor>に <anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">Unicode正規化</anchor>が組み込まれている場合は、仕様書にないなら勝手に適用するわけにいきません。</comment-p><p><anchor-end xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="11" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">[11]</anchor-end> 
現実問題として、実用目的のすべての <anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">Unicode正規化</anchor>の実装は、
任意の入力に対して安全に処理を完了させる必要があります。
<anchor-internal xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="8" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">&gt;&gt;8</anchor-internal> のような入力が与えられたときは、諦めて完全に <anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">Unicode正規化</anchor>されていない文字列を返すか、
<anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">例外</anchor>を<anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">投げる</anchor>などの方法で失敗を伝えるかといった選択を迫られることになります。</p><p><anchor-end xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="13" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">[13]</anchor-end> 
<anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">Web</anchor> ではこの種の実装の制限を<anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">プラットフォーム制限条項</anchor>として包括的に認めています。
他の<anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">プラットフォーム</anchor>でも同様の制限を設けることになるでしょう。</p><p><anchor-end xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="14" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">[14]</anchor-end> 
実際に <anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">Web</anchor> でどう実装されているかを確かめてみましょう。</p><blockquote><pre>escape ( [&quot;x&quot;, &quot;\u0315&quot;.repeat (2**28) , &quot;\u0300&quot;].join(&quot;&quot;).normalize (&quot;NFC&quot;).substring (0, 20) )</pre></blockquote><p><anchor-end xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="15" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">[15]</anchor-end> <anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">Chrome</anchor> では <anchor-internal xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="14" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">&gt;&gt;14</anchor-internal> でも仕様通り正しく reordering します。 2**29 にすると不正な長さと
<code>.repeat</code> が失敗します。
<time>2025-07-02T04:19:12.800Z</time></p><p><anchor-end xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="16" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">[16]</anchor-end> <anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">Firefox</anchor> では <anchor-internal xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="14" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">&gt;&gt;14</anchor-internal> でも仕様通り正しく reordering します。 2**29 でも成功します。
2**30 だと文字列のメモリー割当に失敗したとなり、
2**31 にすると <code>.repeat</code> が失敗します。
<time>2025-07-02T04:21:14.600Z</time></p><comment-p xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:10:"><anchor-end xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="17" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">[17]</anchor-end> <anchor-internal xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="15" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">&gt;&gt;15</anchor-internal> <anchor-internal xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="16" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">&gt;&gt;16</anchor-internal> どちらも <code xmlns="http://www.w3.org/1999/xhtml">.repeat</code> は時間がかかってから失敗するので、
固定の上限ではなく環境によって違う可能性があります。</comment-p></section><section><h1>破壊性</h1><p><anchor-end xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="4" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">[4]</anchor-end> 
この操作が破壊的である事例:
<anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">発音区別符付き仮名</anchor></p></section><section><h1>文脈</h1><p><anchor-end xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="1" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">[1]</anchor-end> <anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">正準再順序付けアルゴリズム</anchor>は<anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">正規化</anchor>の処理から呼び出されます。</p></section><section><h1>関連</h1><p><anchor-end xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:" a0:anchor="5" xmlns:a0="urn:x-suika-fam-cx:markup:suikawiki:0:9:">[5]</anchor-end> 関連: <anchor xmlns="urn:x-suika-fam-cx:markup:suikawiki:0:9:">Unicode正規化</anchor></p></section><section><h1>メモ</h1></section></body></html>