制御文字
画面に表示されないが、テキストの処理方法を指示する特殊な文字。改行 (LF)、タブ (HT)、キャリッジリターン (CR)、ヌル文字 (NUL) などが含まれる。
制御文字 (control character) は、文字として表示されるのではなく、テキストの処理や表示を制御するために使われる特殊な文字です。ASCII の最初の 32 文字 (U+0000〜U+001F) と DEL (U+007F) が制御文字に分類されます。Unicode ではさらに U+0080〜U+009F の範囲にも制御文字が定義されています。
日常的に使われる制御文字は限られています。LF (Line Feed、U+000A) は改行を表し、UNIX 系 OS の標準改行コードです。CR (Carriage Return、U+000D) はカーソルを行頭に戻す文字で、Windows では CR+LF の 2 文字で改行を表します。HT (Horizontal Tab、U+0009) はタブ文字で、テキストの桁揃えに使われます。NUL (U+0000) はヌル文字で、C 言語では文字列の終端を示します。
文字数カウントにおいて、制御文字の扱いは混乱の原因になります。テキストエディタで「改行」を入力すると、見た目には行が変わるだけですが、内部的には LF が 1 文字、または CR+LF が 2 文字ぶん挿入されています。Windows で作成したテキストファイルの文字数を数えると、改行 1 つにつき 2 文字がカウントされ、UNIX で作成した同じ内容のファイルより文字数が多くなります。同じ本文なのに数が合わない、という食い違いの多くはこれが原因です。数える前に改行コードをどちらかへ統一しておけば、環境をまたいでも同じ数になります。なお、入力欄に書いた文章をフォームで送信する場合、ブラウザは送信時に改行を CR+LF の対へ揃えます (wrap 属性の値にかかわらず、フォーム送信時のシリアライズ規則によるものです)。画面で数えた値とサーバー側で受け取ってから数えた値がずれることがあるのは、この変換が間に入るためです。
ウェブの文脈では、連続する空白文字 (スペース、タブ、改行) は 1 つのスペースにまとめて表示されます。これは HTML の文法上そう決まっているのではなく、CSS の white-space プロパティの既定値 (normal) による表示上の処理です。そのため、HTML ソースコード上の文字数と、ブラウザに表示されるテキストの文字数は一致しません。<pre> 要素や white-space: pre を指定した要素では、タブや改行がそのまま表示されます。数える対象が「ソースの文字」なのか「画面に見える文字」なのかで答えが変わるため、どちらを数えたいのかを先に決める必要があります。
セキュリティの観点では、制御文字はインジェクション攻撃の手段になり得ます。HTTP ヘッダに CR+LF を挿入して別のヘッダを偽造する「HTTP ヘッダインジェクション」や、ログファイルに改行を挿入して偽のログ行を作る「ログインジェクション」が知られています。前者については、2026 年時点の主要なサーバー実装はヘッダの値に CR や LF が含まれていると送信そのものを拒否します (Node.js では例外が発生します) が、ログのように自分で文字列を組み立てて書き出す出力には、同じ防壁が用意されているわけではありません。対策として制御文字を除去する場合、範囲の指定には注意が必要です。U+0000〜U+001F をまとめて削除すると、改行とタブも一緒に消えて本文が 1 行に潰れます。意味を持つ改行 (LF・CR) とタブは残し、それ以外を落とす、という粒度で分けるのが現実的な落としどころです。
Unicode には、制御文字に加えて「フォーマット文字」というカテゴリもあります。ゼロ幅スペース (U+200B)、ゼロ幅接合子 (U+200D)、双方向制御文字 (U+200E、U+200F) などがこれに該当します。これらは制御文字と同様に不可視ですが、Unicode の分類上は別のカテゴリに属します (制御文字は Cc、フォーマット文字は Cf)。この違いは実務にも表れます。JSON の文字列リテラルには生の制御文字を書けないため、タブや改行がそのまま混ざったデータは読み込みの時点で構文エラーになりますが、ゼロ幅スペースはフォーマット文字なので何の警告もなく通り抜けます。受け渡す形式そのものが弾いてくれる文字と、最後まで残ってしまう文字がある、ということです。
制御文字を扱うときの判断は、3 つに整理できます。まず、改行とタブは文章の構造を担う情報であって不要なゴミではないので、一律には削除しないこと。次に、NUL のように処理系を誤動作させ得る文字や、U+0080〜U+009F のようにテキストとして現れる理由のない文字は、保存する前の入力チェックで弾くこと。最後に、文字数を数える場面では、改行を 1 文字と数えるのか 2 文字と数えるのか、そもそも数に含めるのかを先に決めておくこと。この 3 つを決めておけば、環境やツールをまたいだときの食い違いは大半が防げます。