日本語

テキストおよび日常ツール · テキスト ツールキット

非表示文字: 非改行スペース、ゼロ幅結合子およびトリム

· 背景

テキストクリーンアップ ユニコード 公開

隠れたスペースとゼロ幅の Unicode 文字を明らかにする表示されたテキスト行
オリジナル ToolAcre ベクトル イラスト

何も見えない文字 (非改行スペース、ゼロ幅スペースと結合子、バイト オーダー マーク) がどこから来たのか、どれが空白としてカウントされるのか、およびそれらを見つけて削除する方法を調査します。

重複していない 2 つの同一の行 — 非表示の文字が重複除外と検索をどのように無効にするか

2 つの行はエディターでは同一に見えますが、等価性チェック、検索チェック、または重複排除チェックに失敗することがあります。 1 つは通常の U+0020 スペースを含むことができ、もう 1 つは非改行スペースである U+00A0 を含むことができます。幅がゼロの文字は、目に見える幅を占有せずに同じ問題を引き起こす可能性があり、発行者には、明らかに一致する 2 つのラベルが別個の文字列のまま残ることになります。

これは単なる表面的なものではありません。非表示のコード ポイントにより、分析ディメンションが分割されたり、正確な検索操作が無効になったり、重複行が保存されたり、コピーされた識別子が検証に失敗したりする可能性があります。目で見てコンテンツを書き換える前に、ソースのコピーを保管し、疑わしい文字列を体系的に比較してください。目に見えるレンダリングは外観に関する証拠であり、基礎となる Unicode シーケンスが一致することの証拠ではありません。

それらの出所 — Web ページ、ワードプロセッサ、絵文字シーケンス、PDF からのコピーアンドペースト

目に見えない文字は通常、通常の作業を通じて到着します。 Web ページは非改行スペースを使用して用語をまとめ、ワード プロセッサはレイアウト指向のスペースを保持し、PDF 抽出は位置決めされたグリフからテキストを再構築します。これらのシステム間でコピーすると、コピー先には見慣れた単語やギャップしか表示されない場合でも、書式設定文字が CMS フィールドに取り込まれる可能性があります。

その他の目に見えないマークは、書記体系または絵文字の意図的な部分です。幅ゼロの結合子は絵文字コンポーネントを 1 つの表示シンボルに結合できますが、結合子と非結合子は複数のスクリプトの整形に影響します。その起源が重要です。「表示できない」ということは「削除しても安全」という意味ではありません。クリーンアップは、前進幅がたまたまゼロになっているすべてのキャラクターではなく、診断されたアーティファクトをターゲットにする必要があります。

ホワイトスペース ファミリ — 通常の改行のない狭い表意的なスペース、および JavaScript のトリムがホワイトスペースとみなすもの

Unicode には日常的なスペース以上のものが含まれています。 U+00A0 は非改行スペース、U+202F は狭い非改行スペース、U+3000 は表意文字スペースです。 JavaScript の空白処理にはこれらの文字が含まれるため、`trim()`、`trimStart()`、および `trimEnd()` は、これらの文字が文字列の関連する端にある場合にそれらを削除できます。

Text Toolkit の行トリミングでは、各行でこれらの JavaScript メソッドが呼び出されます。内部の間隔は正規化されないため、2 つの単語の間には改行されないスペースが残ります。 「スペースを含まない文字」統計は、ASCII スペースよりも広い JavaScript `s` に一致する文字を削除します。この数値は、すべての目に見えないコード ポイントが除外されたという約束としてではなく、定義された測定値として使用してください。

ゼロ幅ファミリー — ゼロ幅のスペース、結合子と非結合子、ワード結合子およびバイト オーダー マーク。これらはまったく空白ではありません。

ゼロ幅ファミリは異なるルールに従います。 U+200B ゼロ幅スペース、U+200C ゼロ幅非ジョイナー、U+200D ゼロ幅ジョイナー、および U+2060 ワード ジョイナーは、JavaScript ホワイトスペースではなくフォーマット文字です。したがって、通常の `trim()` ではそれらは削除されません。これらのマークのいずれかを含む行は、単に画面にインクが表示されないという理由だけで空白ではありません。

U+FEFF には 2 つの関連する歴史があります。エンコードされたデータの先頭ではバイト オーダー マークを通知でき、テキストではゼロ幅のノーブレーク スペースとして機能します。 ECMAScript には、U+200B から U+200D とは異なり、トリム空白セットに U+FEFF が含まれています。したがって、ゼロ幅ファミリー全体を一種の空白として扱うことは、実際の JavaScript の動作と矛盾します。

それらを検出する — 文字カウンターを使用して、表示されているものと一致しないカウントを見つけます。一部のジョイナーは隣接するものに取り付けられ、隠れたままであることを思い出します。

驚くべき数があれば、非表示のコンテンツを警告できますが、すべてのケースを特定できるわけではありません。 ToolAcre は、利用可能な場合、`Intl.Segmenter` を持つ書記素クラスターをカウントします。絵文字シーケンスに参加する結合子は、複数のコード ポイントが 1 つの書記素を形成するのに役立つ場合があるため、結合子を追加または削除すると、コード ポイント カウンタが示すような単純な 1 文字の増加を引き起こすことなく、レンダリングが変更される可能性があります。

いくつかの手がかりを組み合わせて使用​​します: 完全一致の失敗、予期しない「スペースなし」の結果、Unicode 対応エディターで検査されたコピーされたテキスト、または特定のコード ポイントの正規表現検索。セグメンターが使用できない場合、フォールバック カウンターはコード ポイントを使用するため、結果はブラウザーの機能によっても異なる場合があります。数えると調査の範囲が狭くなります。これは隠し文字スキャナーや Unicode 名ビューアではありません。

隠れた文字の検出: カウントは完全な一覧ではなく手がかりを提供します

確認されたコピー アンド ペースト アーティファクトの場合は、複製を操作し、正規表現モードで検索と置換を開きます。 `[​]` を検索し、何も置換しないと、テキスト全体から幅ゼロのスペースと埋め込まれた U+FEFF 文字が削除されます。このツールは、JavaScript のグローバル フラグを使用してパターンをコンパイルし、置換数を報告し、パターンが無効な場合はテキストを変更しないままにします。

そのパターンを `[​-‍]` に自動的に拡張しないでください。この範囲では、U+200C と U+200D も削除されます。これにより、スクリプトの形状が変更され、結合された絵文字が個別のシンボルに分割される可能性があります。これらのコード ポイントは、検査によって不要であることが判明した場合にのみ追加します。置換後、重複排除を実行し、公開する前に出力を保存されたオリジナルと比較します。

効果的な例: 重複を排除する前に、確認された不要なゼロ幅文字のみを削除します

このクリーンアップは、双方向制御文字、同形文字、または混乱を招くテキストに関連するすべてのセキュリティ問題に対処するものではありません。方向マークは視覚的な順序を変える可能性がありますが、ホモグリフ攻撃では互いに似ている異なる目に見える文字が使用されます。どちらの問題もスペースを削除することで解決されるわけではなく、無差別な非表示文字正規表現により、実際のリスクを見逃しながら、正規の多言語コンテンツに損害を与える可能性があります。

このツールキットは、Unicode や複数行モードなどの正規表現フラグを公開したり、今後の一致を強調表示したり、置換を個別に実行したりすることもありません。すべて置換は全文にわたって操作されるため、報告された数と元に戻すアクションは重要な安全対策となります。ソース コード、合法的なコピー、または見慣れないスクリプトについては、一括編集を行う前に専用の Unicode ツールを使用して各文字を検査してください。

要点 — 目に見えないからといって無害というわけではありません。 Text Toolkit のカウンタと正規表現の検索と置換は、ブラウザを離れることなくそれらを公開および削除します。

目に見えないということは、空である、交換可能である、有害であるという意味ではありません。非改行スペースは、レイアウト セマンティクスを持つ空白です。ゼロ幅結合子は整形セマンティクスを伝えることができます。 U+FEFF は、JavaScript トリミングの下で​​は再び異なる動作をします。正確なクリーンアップは、コード ポイントに名前を付け、コード ポイントが存在する理由を理解し、宛先にその機能がまだ必要かどうかを判断することから始まります。

Text Toolkit を制御されたブラウザ側のワークベンチとして使用します。カウントによって不一致が明らかになり、正規表現の検索と置換によって正確に定義されたセットが削除され、重複除外によって隠れた差異がなくなったことを確認できます。オリジナルを保持し、デフォルトでジョイナーの削除を回避し、レンダリングされた結果を確認します。範囲が狭くレビュー可能な修正は、目に見えない Unicode をすべて残骸として扱うよりも安全です。