【Java】エスケープシーケンス早見表

Java手帖

Javaのエスケープシーケンス一覧を早見表にまとめています。

一部は詳しい解説も行っています。辞書的にお使いください。

記事内のコードは OpenJDK 21 で動作確認済みです。

早見表はこちらからご覧になれます。

エスケープシーケンスとは

Javaのエスケープシーケンス(エスケープ文字)とは、制御文字や特別な記号、あるいは文字コード単位で指定したい文字を表記するための、\(バックスペース)から始まる特殊な記法のことです。Javaでは11種類が用意されています。

使用できるのは文字列リテラル内・文字リテラル内・テキストブロック内です(例外あり)。

\(バックスペース)は環境によっては ¥(円記号)として表示されますが、内部では同じものとして扱われています。

エスケープシーケンスは制御系・文字系・数値系の3種類に大別され、それぞれ以下のような特徴を持ちます。

制御系

改行(LF)や水平タブ(HT)など、通常のテキスト入力では表しにくい制御文字を記述するためのエスケープシーケンスです。

各エスケープシーケンスは対応する制御文字1つを表し、文字の位置や改行といった表示時の動作を制御します。

制御文字についてはこちらの記事が直観的にわかりやすいです。

文字系

プログラム内で使用される特別な意味を持った文字( "' など)を、通常の文字として扱うためのエスケープシーケンスです。これをエスケープ処理ともいいます。

例えば、" は「文字列リテラルの始点と終点」を表す特別な文字ですが、これをエスケープ処理して \" とすることで、リテラル中に " を通常の文字として含めることができます。

数値系

文字を文字コード(数値)で指定するためのエスケープシーケンスです。

私たちが普段見ている文字は、コンピュータ内部ではすべて数値(文字コード)として管理されています。

Javaの数値系エスケープシーケンスは Unicode という文字コードに基づいており、「あ」は U+3042(16進)であるため、\u3042 と記述することで「あ」を表せます。

早見表

リンクをクリックすると詳細な解説に飛びます。

リンクが存在しないエスケープシーケンスは、まだ詳細な解説がありません。
随時更新予定です。

エスケープシーケンス意味種類備考
\bBS バックスペース制御系全く使われない
\fFF 改ページ制御系全く使われない
\nLF 改行制御系出力時の不整合に注意
\rCR 復帰制御系ほぼ使われない
\tHT 水平タブ制御系固定幅ではない
\\\文字系
\''文字系
\""文字系
\s行末スペースの保持文字系※1Java 15 以降
\XXX8進定数(XXXは 0~377 の8進数)数値系実質的にLatin-1文字コード
\uXXXX16進定数(XXXXは4桁の16進数)数値系※2Unicode文字コード

※1 文字系の中では特殊な性質を持ち、主にテキストブロックで使用する。また、制御系の側面もある。
※2 文字(列)リテラル外でも使用でき、字句・構文解析前に文字へ変換される。

よく利用されるのは \n, \t, 文字系( \\, \', \" ) のエスケープシーケンスです。初学者はまずここを押さえましょう。

それ以外は必須ではありませんが、知っておくとJavaや文字コードに対する知識が深まります。

制御系

\b – バックスペース

\bバックスペースBS: U+0008)を挿入するエスケープシーケンスです。

動作には2通りあり、どちらになるかは環境によって異なります。

多くの環境では前者となります。

1文字消去する

文字を1文字だけ消去し、カーソルもそれに従って1文字分戻ります。キーボードの BackSpace キーと同じです。

コード
public class Main {
    public static void main(String[] args) {
        System.out.print("ABCDE\b");
    }
}
実行結果
ABCD

E が消去されているのが確認できます。


\b の後ろに文字が続く場合は、以下のようになります。

コード
public class Main {
    public static void main(String[] args) {
        System.out.print("ABC\bDE");
    }
}
実行結果
ABDE

C が消去され、B に続けて文字が入力されているのが確認できます。

カーソルを1文字分だけ戻す

文字の消去は行わず、カーソルを1文字分だけ戻します。

コード
public class Main {
    public static void main(String[] args) {
        System.out.print("ABCDE\b");
    }
}
実行結果
ABCDE

実行結果に変化はありませんが、内部的にはカーソルが戻った状態になっています。続けて文字を表示すると以下のようになります。

コード
public class Main {
    public static void main(String[] args) {
        System.out.print("ABCDE\b");
        System.out.print("Hello"); // 続けて文字を表示
    }
}
実行結果
ABCDHello

カーソルは D と E の間に移動した状態です。続けて文字を表示すると EHello上書きされ、表示されません。


ここでは2通りの動作を紹介しましたが、環境によっては \b を解釈できず、⌧(置換記号)として表示されることもあります。

\b は環境依存度がきわめて高く、Javaの「どのような環境でも同じように動く」という基本方針と相容れないため、使われる機会はほとんどありません。教材や記事で紹介されることはあっても、実務で使うことはまずないでしょう。

E は消滅したのか

1つ目・2つ目の例ともに、E は「消去」または「上書き」によって完全に消滅したように見えます。

しかし、\b はあくまで表示とカーソルの動きを制御するだけで、実際のデータから E が消去されたわけではありません。バイナリレベルでは依然 A B C D E \b のデータが並んでいます。

ただし、キーボードの BackSpace キーは編集中のデータを本当に消去するという点には注意が必要です。\b は「表示制御」ですが、BackSpace キーは「入力制御」なため、このような違いが発生します。

\b はなぜ存在するのか

\b(BS)は文字を疑似的に消去するために誕生しました。

初期のテレタイプ端末(TTY)では、一度入力した文字は即座に画面に反映され、文字を消去するという操作自体が存在しませんでした。

そこで、カーソルを1文字分戻したのちスペースを入力することで文字を上書きし、疑似的に消去したように見せる方法が採られました。この「1文字分戻す」操作に必要だったのが \b です。

今日では入力した文字を編集して消去することは容易いため、\b はほとんど使われなくなりました。

\f – 改ページ

\f改ページFF・フォームフィード: U+000C)を挿入するエスケープシーケンスです。

このエスケープシーケンスは現代ではほとんど機能せず、⌧(置換記号)等に置き換えられます。

コード
public class Main {
    public static void main(String[] args) {
        System.out.print("1ページ目\f2ページ目");
    }
}
実行結果(環境により異なる)
1ページ目2ページ目

そもそも機能しないため、現代のJavaプログラミングでは完全に不要です。実務で使うことはありませんし、覚える必要もありません。

\f の本来の動作

\f(FF)は本来、プリンタのためのエスケープシーケンスです。

初期のプリンタは、コンピュータから直接印刷する文字列を受け取り、それに基づいて印刷するという仕様でした。\f を受け取ると、そこで改ページ(ページを送って次のページの先頭から印字を開始する)を行います。

現代では印刷はページ記述言語によって制御され、直接文字列を送ることはほとんどありません。

\f歴史的な名残りとして存在するに過ぎないと言えるでしょう。

\n – 改行

\n改行LF・ラインフィード: U+000A)を挿入するエスケープシーケンスです。

数あるエスケープシーケンスの中で最も使用頻度が高く、見かける場面も非常に多いです。

基本的な動作は以下のようになります。

コード
public class Main {
    public static void main(String[] args) {
        System.out.print("1行目\n");
        System.out.print("2行目");
    }
}
実行結果
1行目
2行目

「1行目」の後に改行され、「2行目」が次の行に表示されているのが確認できます。


文字列の途中で \n を用いた場合は以下のようになります。

コード
public class Main {
    public static void main(String[] args) {
        System.out.print("私は\n今日\n学校に\n行きました");
    }
}
実行結果
私は
今日
学校に
行きました

複数回連続で \n を用いた場合は以下のようになります。

コード
public class Main {
    public static void main(String[] args) {
        System.out.print("1行目\n\n\n");
        System.out.print("4行目");
    }
}
実行結果
1行目


4行目

文字(列)リテラルに組み込める特徴を活かし、以下のような使い方もできます。

コード
public class Main {
    public static void main(String[] args) {
        for (int i = 1; i < 10; i++) {
            for (int j = 1; j < 10; j++) {
                System.out.print((i * j) + (j == 9 ? "\n" : "\t"));
            }
        }
    }
}
実行結果
1	2	3	4	5	6	7	8	9
2	4	6	8	10	12	14	16	18
3	6	9	12	15	18	21	24	27
4	8	12	16	20	24	28	32	36
5	10	15	20	25	30	35	40	45
6	12	18	24	30	36	42	48	54
7	14	21	28	35	42	49	56	63
8	16	24	32	40	48	56	64	72
9	18	27	36	45	54	63	72	81

三項演算子を使用し、j == 9 の場合のみ改行するようになっています。if - else 文および System.out.println() でも同じことはできますが、こちらはより簡潔です。

このように、\n は非常に柔軟な改行を行うことができます。


使いどころ

  • 簡易的な改行
  • 簡易的なコンソール(ログ)出力
  • 簡易的なファイル出力

※ なぜ「簡易的」なのかは次項以降で解説しています。


System.lineSeparator()%n

\n に似たものとして、System.lineSeparator()printf(), String.format() で利用可能な %n があります。

どちらも「改行する」という点では同じですが、その互換性に差があります。

詳しい説明は省きますが、System.lineSeparator()%n のほうが互換性は高いです。しかし、現代ではこの差を意識すべき場面は少なくなっています。

\nSystem.lineSeparator() よりも記述量が少なく、 %n よりもさまざまな場面で利用可能なことから、ほとんどの場合 \n を使うので特に問題ありません。

ただし、一部のケースでは互換性の差による不都合が生じます。詳しくは【発展】OS改行コードとの不整合に注意(Windows)をご覧ください。

【発展】\n(LF)の本来の動作と改行の関係

ここまで、\n(LF)は改行を挿入するためのエスケープシーケンス(制御文字)だと説明してきました。

しかし、これは便宜的なものに過ぎず、正確には誤りです。

本来、\n は1行送る(カーソルを1行下にずらす)という意味です。そのため、正確には以下のように動作すべきです。

コード
public class Main {
    public static void main(String[] args) {
        System.out.print("1行目\n");
        System.out.print("2行目");
    }
}
実行結果(仮想)
1行目
   2行目

\n のみではカーソルが行頭に戻らず、改行が不完全になってしまいます。

完全な改行を行うためには、「行送り(LF)」に加え、「復帰(CR)」を行う必要があります。復帰とは、カーソルを行頭に戻す操作のことです。両者が揃って初めて、改行が成立します。

コード
public class Main {
    public static void main(String[] args) {
        System.out.print("1行目\r\n");
        System.out.print("2行目");
    }
}
実行結果
1行目
2行目

両者をまとめて CRLF と表します。エスケープシーケンスで言えば \r\n で、改行の必要十分条件です。

改行に必要な制御文字を改行コードと呼びます。

\n(LF)のみで改行されるのは、現代の実行環境が \n を自動的に改行とみなすように設計されているためです。これにより、\n だけでも問題は起きにくくなっています(詳しくは以下のコラムを参照)。

ただし、 \n が「簡易的な改行」であることに変わりはなく、場合によっては問題が発生します。詳しくは次項をご覧ください。

CRLF は本当に必要十分か

「CRLFは改行の必要十分条件である」と述べましたが、この表現に違和感を抱いた方もいるかもしれません。LFのみで改行できる場面も多いためです( Linux / macOS や多くのコンソール)。

しかし、これらの環境では「LFを受け取った際、自動でCR的処理も行っていると解釈することができます。

LFのみで改行できるのは、CR的処理を環境が自動で補ってくれるためと考えられるのです。

実装上は単なる「LFの解釈の違い」なのですが、このように理解すれば、CRLFが改行に必要十分なのも筋が通ります。

まとめると、以下のようになります。

どのような環境でも、LFは行送り以上を意味しない
LFのみで改行できる場合、環境が自動でCR的処理を補っている

【発展】OSの改行コードとの不整合に注意(Windows)

改行コードはOSによって異なります。

  • Windows: CRLF
  • Linux / macOS: LF

Javaの \n はLFを表します。LinuxやmacOSではまったく問題ありませんが、WindowsではOSの改行コードと合いません。

System.out.print() 等で、一時的にコンソールに表示するだけなら特に問題ないのですが、顕在化するのはファイルに保存する場合です。

\n(LF)が自動的に \r\n(CRLF)に変換されることはないため、誤った改行コードのままファイルに保存されてしまいます。

この状態でファイル操作を行うと、予期せぬ動作を引き起こす可能性があります。

そのため、明示的に \r\n を記述するか、より互換性の高い System.lineSeparator() または %n を使うようにしましょう。

System.lineSeparator() は、OSの改行コード(WindowsならCRLF、Linux / macOSならLF)を出力するメソッドです。
詳しくは以下の記事をご覧ください。

%n は内部的に System.lineSeparator() を用いているため、両者は本質的には同じです。
※ これ以外にもOSの改行コードを出力する方法はありますが、記事の本題とずれるため、ここでは解説しません。

なぜエディタとコンソールでは問題が起こらない(ように見える)のか

WindowsではCRLFが改行コードですが、エディタとコンソールではLFのみでも問題なく改行されることが大半です。

これは、ツールが自動的にLFをCRLFとして解釈しているためです。自動でCR的処理も行うことで、CRLFとしての改行を実現しています。

ただし、これはあくまでツールによる”表示上の気配り”であって、実際のデータがCRLFに書き換えられるわけではありません。この点には十分注意しましょう。

改行コードの歴史的経緯

改行コードの起源は、タイプライターにあります。

タイプライターとは、キーボードによく似た文字盤を打鍵して、用紙に直接文字を打ち込むための道具です。まさに現代のキーボードの「祖先」といえる存在です。

タイプライター(引用:Wikipedia

タイプライターでは、改行は一つの動作ではありませんでした。

  • CR(キャリッジリターン):文字を打つ位置(キャリッジ)を行頭に戻す
  • LF(ラインフィード):用紙を1行分送り出す

この2つを組み合わせて初めて、改行が実現できたのです。

この仕組みはのちにテレタイプ端末(TTY)に受け継がれ、さらにコンピュータへと引き継がれていきました。

コンピュータでは、これをどう再現するかがOSごとに分かれました。Windowsではタイプライターを踏襲してCRLFに、Linux / macOSでは利便性を重視してLFのみになりました。

歴史的経緯が、現代の開発現場にまで影響を与えているのです。

\t – 水平タブ

\t水平タブHT: U+0009)を挿入するエスケープシーケンスです。

次のタブストップまでカーソルを移動させます。

タブストップとは

タブストップとは、HT(\t)が入力された際にカーソルが移動する、行内の決まった位置(区切り)のことです。実際に見ることはできませんが、テキスト内に必ず存在しています。

また、タブストップ間の幅のことをタブ幅といいます。タブ幅は環境によって異なりますが、またはが主流です。

※ タブ幅はASCII文字(英数字)で計算されます。例えば、4なら英数字4文字分です。他の言語(日本語など)の幅ではない点に注意しましょう。

特に断りがない限り、本記事では タブ幅 = 4 として解説しています。必要に応じて読み替えてください。

\t は固定長のスペース(キーボードのスペースキーで入力できる空白)を挿入するエスケープシーケンスだと誤解されがちです。

しかし、実際には次のタブストップまでの距離によって表示される空白幅は変化します。また、表示される空白も、スペースの並びではなく、\t(HT)という一文字として識別されます。この点に注意しましょう。


基本的な動作は以下のようになります。

コード
public class Main {
    public static void main(String[] args) {
        System.out.println("Name\tPrice\tAmount");
    }
}
実行結果
Name	Price	Amount

空白が固定幅ではないことが確認できます。


「次のタブストップまで移動」という特徴を活かし、複数行にわたる文字列表示を位置揃え(整形)することもできます。

コード
public class Main {
    public static void main(String[] args) {
        System.out.println("Name\tPrice\tAmount");
        System.out.println("Apple\t2000\t50");
    }
}
実行結果
Name	Price	Amount
Apple	2000	50

各要素の左端が位置揃えされ、表のような見た目となります。


ただし、要素幅の差が大きすぎたり、英数字以外が含まれている場合、正しく位置揃えできないこともあります。

コード
public class Main {
    public static void main(String[] args) {
        System.out.println("Name\tPrice\tAmount");
        System.out.println("Blueberry\t6500\t100");
        System.out.println("バナナ\t10000\t1000");
    }
}
実行結果
Name	Price	Amount
Blueberry	6500	100
バナナ	10000	1000

この場合、\t を増やす・手動でスペースを挿入するなどの対応が必要になります。


ここまで見てきたように、\t は複雑な処理を行わずとも、文字列を位置揃えして表示することが可能です。

その手軽さゆえ、特にログ・デバッグ目的で役立ちます。

しかし、本格的な位置揃えには不十分です。そのような場合は \t ではなく、書式指定文字列をサポートする printf()String.format() を使いましょう。


使いどころ

  • 簡易的な位置揃え(表形式の表示など)
  • 区切り文字として使用(TSVファイルなど)

Tab キー入力の自動変換に注意

Tabキーは水平タブ(HT)を入力するためのキーです(\t と同じ)。

したがって、エディタ内でTab入力を行うと、本来はそのまま水平タブが入力されます。

しかし、IDE(統合開発環境)や一部の高性能なエディタでは、Tab入力が自動的にスペース4つに変換されることがあります。

Javaプログラミングでは、Tabキーをインデント挿入のためのキーとして使うことが多いです。インデント自体はスペースでも水平タブでも問題ないのですが、タブ幅は環境ごとに異なるため、水平タブを使うと表示が崩れる可能性があります。

そのため、「インデントは水平タブではなくスペース4つにすべき」という公式ガイドラインが定められています。Tabキーの機能性を損ねず、ガイドラインにも適合するよう、エディタはあえてTab入力を自動変換しているのです。
※ Java以外の多くの言語でも同様の仕様となっています。

\t(HT)キーボードの Tab キーの関係

多くのキーボードのTabキーには、 という記号が印字されています。

キーボードのTabキー(引用:FreeImages.com / OmirOnia)

この記号は、まさに「次のタブストップ( | )までカーソルを移動させる(⇆)ことを表しています。

\t の動作は複雑に見えますが、Tabキーに印字されている記号と何ら変わらないのです。

コメント

PAGE TOP
タイトルとURLをコピーしました