C#のエスケープ完全ガイド|文字列・引用符・改行・正規表現の書き方を解説
はじめに
C#で文字列を扱っていると、"を文字列の中に入れたい、改行を含めたい、Windowsのファイルパスを書きたい、正規表現の\dを使いたい、といった場面がよくあります。
このとき重要になるのが「エスケープ」です。
C#のエスケープを正しく理解していないと、次のような問題が起こります。
文字列が途中で終わったように解釈される
\が消えたり、意図しない特殊文字になったりする正規表現が想定どおりに動かない
ファイルパスやJSON、CSV、SQLなどの文字列でエラーが発生する
この記事では、C#のエスケープについて、文字列、引用符、改行、バックスラッシュ、ファイルパス、文字列補間、正規表現、実務での使い方まで体系的に解説します。
1. C#のエスケープとは?検索ユーザーがまず知りたい基本
1-1. エスケープとは何か
エスケープとは、プログラム上で特別な意味を持つ文字を、別の意味として扱うための書き方です。
たとえば、C#では文字列をダブルクォーテーション"で囲みます。
C#string message = "Hello";
では、文字列の中にダブルクォーテーションそのものを含めたい場合はどうすればよいでしょうか。
C#string message = "彼は"こんにちは"と言った";
このコードはコンパイルエラーになります。C#が、途中の"を「文字列の終わり」と解釈してしまうためです。
このような場合は、\"のように書きます。
C#string message = "彼は\"こんにちは\"と言った";
Console.WriteLine(message);
出力結果は次のようになります。
彼は"こんにちは"と言った
このように、本来は特別な意味を持つ文字を、文字として扱えるようにする仕組みがエスケープです。
1-2. C#でエスケープが必要になる理由
C#では、文字列や文字リテラルの中で一部の文字が特別な意味を持ちます。
代表的なものは次のとおりです。
":文字列の開始・終了':文字リテラルの開始・終了\:エスケープシーケンスの開始改行:通常の文字列リテラルではそのまま書けない
{と}:文字列補間で式を埋め込む記号
これらをそのまま書くと、C#のコンパイラが「構文」として解釈してしまいます。
そのため、文字として扱いたい場合にはエスケープが必要です。
1-3. 文字列・引用符・改行・正規表現で使われる主な場面
C#のエスケープは、主に次の場面で使われます。
C#// 引用符
string quote = "彼は\"OK\"と言った";
// 改行
string lines = "1行目\n2行目";
// タブ
string tsv = "名前\t年齢\t住所";
// バックスラッシュ
string path = "C:\\Users\\User\\Documents";
// 正規表現
string pattern = "\\d+";
特に初心者がつまずきやすいのは、バックスラッシュ\です。
C#では\nや\tのように、\から始まる特別な文字列があるため、\そのものを表示したい場合は\\と書く必要があります。
1-4. バックスラッシュ「\」が特別な意味を持つ仕組み
C#の通常の文字列リテラルでは、\は「次の文字と組み合わせて特別な文字を表す」という意味を持ちます。
たとえば、\nは改行、\tはタブを表します。
C#Console.WriteLine("A\nB");
出力結果は次のとおりです。
A
B
つまり、C#は文字列の中で\nを見つけると、バックスラッシュとnの2文字ではなく、改行文字として扱います。
そのため、バックスラッシュ自体を文字として扱いたい場合は、次のように\\と書きます。
C#Console.WriteLine("C:\\Temp\\test.txt");
出力結果は次のようになります。
C:\Temp\test.txt
2. C#のエスケープシーケンス一覧
2-1. よく使うエスケープシーケンス早見表
C#でよく使うエスケープシーケンスは次のとおりです。
| エスケープシーケンス | 意味 | 使用例 |
|---|---|---|
\" | ダブルクォーテーション | "彼は\"OK\"と言った" |
\' | シングルクォーテーション | '\'' |
\\ | バックスラッシュ | "C:\\Temp" |
\n | 改行、ラインフィード | "A\nB" |
\r | キャリッジリターン | "A\rB" |
\r\n | Windows系の改行 | "A\r\nB" |
\t | 水平タブ | "A\tB" |
\0 | null文字 | "\0" |
\a | ベル | "\a" |
\b | バックスペース | "A\bB" |
\f | フォームフィード | "\f" |
\v | 垂直タブ | "\v" |
\uXXXX | Unicode文字 | "\u3042" |
\UXXXXXXXX | Unicode文字 | "\U0001F600" |
\x | 可変長の16進Unicode表記 | "\x3042" |
日常的によく使うのは、\"、\\、\n、\tです。
2-2. 改行を表す「\n」とキャリッジリターン「\r」
\nはラインフィードを表すエスケープシーケンスです。一般的に「改行」として使われます。
C#string text = "1行目\n2行目";
Console.WriteLine(text);
出力結果は次のとおりです。
1行目
2行目
一方、\rはキャリッジリターンを表します。
現在の多くの環境では、改行として\nまたは\r\nが使われます。Windowsでは伝統的に\r\n、LinuxやmacOSでは\nが使われることが多いです。
C#string windowsLine = "1行目\r\n2行目";
環境に応じた改行を使いたい場合は、Environment.NewLineを使う方法もあります。
C#string text = "1行目" + Environment.NewLine + "2行目";
2-3. タブを表す「\t」
\tは水平タブを表します。
C#string line = "名前\t年齢\t住所";
Console.WriteLine(line);
出力例は次のようになります。
名前 年齢 住所
タブ区切りのテキスト、ログ、簡単な表形式の出力などで使われます。
ただし、表示幅はエディタやコンソール環境によって異なるため、きれいに列をそろえたい場合は文字列の書式指定を使う方が適しています。
C#Console.WriteLine("{0,-10}{1,5}", "Alice", 20);
Console.WriteLine("{0,-10}{1,5}", "Bob", 35);
2-4. ダブルクォーテーションを表す「"」
文字列の中でダブルクォーテーションを表示したい場合は、\"を使います。
C#string text = "彼は\"C#を勉強中です\"と言った";
Console.WriteLine(text);
出力結果は次のようになります。
彼は"C#を勉強中です"と言った
C#では通常の文字列を"で囲むため、文字列内の"をそのまま書くと、文字列の終了と解釈されます。
そのため、文字としての"を表すにはエスケープが必要です。
2-5. シングルクォーテーションを表す「'」
C#では、1文字を表す文字リテラルを'で囲みます。
C#char c = 'A';
シングルクォーテーションそのものを文字として扱いたい場合は、'\''と書きます。
C#char quote = '\'';
Console.WriteLine(quote);
出力結果は次のとおりです。
'
なお、文字列リテラルの中ではシングルクォーテーションは通常そのまま書けます。
C#string text = "It's OK";
ただし、文字リテラルでは'が区切り記号になるため、エスケープが必要です。
2-6. バックスラッシュを表す「\」
バックスラッシュ\そのものを文字列に含めるには、\\と書きます。
C#string path = "C:\\Temp\\sample.txt";
Console.WriteLine(path);
出力結果は次のようになります。
C:\Temp\sample.txt
C#では\がエスケープシーケンスの開始を表すため、\を1文字として扱いたい場合は、もう1つ\を重ねる必要があります。
2-7. null文字・ベル・バックスペースなどの制御文字
C#には、改行やタブ以外にも制御文字を表すエスケープシーケンスがあります。
C#string nullChar = "\0";
string bell = "\a";
string backspace = "ABC\bD";
主な制御文字は次のとおりです。
| エスケープシーケンス | 意味 |
|---|---|
\0 | null文字 |
\a | ベル |
\b | バックスペース |
\f | フォームフィード |
\v | 垂直タブ |
通常の業務アプリケーションでは、これらを直接使う機会は多くありません。
ただし、バイナリデータ、通信プロトコル、古い端末制御、特殊なテキスト処理では登場することがあります。
2-8. Unicode文字を表す「\u」「\U」「\x」
C#ではUnicode文字をエスケープで表現できます。
\uは4桁の16進数でUnicode文字を表します。
C#string text = "\u3042";
Console.WriteLine(text);
出力結果は次のとおりです。
あ
\Uは8桁の16進数でUnicode文字を表します。絵文字など、4桁では表しきれないコードポイントに使います。
C#string emoji = "\U0001F600";
Console.WriteLine(emoji);
出力結果は次のようになります。
😀
\xも16進数でUnicode文字を表しますが、桁数が可変で解釈されるため、後ろに続く文字によって意図しない結果になることがあります。
C#string text = "\x3042";
Console.WriteLine(text);
Unicodeを明確に書きたい場合は、\uXXXXまたは\UXXXXXXXXを使う方が安全です。
3. C#の文字列リテラルとエスケープの書き方
3-1. 通常の文字列リテラルでのエスケープ
通常の文字列リテラルは、ダブルクォーテーション"で囲む一般的な文字列です。
C#string text = "Hello, C#";
通常の文字列リテラルでは、エスケープシーケンスが有効です。
C#string message = "1行目\n2行目";
string quote = "彼は\"OK\"と言った";
string path = "C:\\Temp\\file.txt";
短い文字列や、\n、\tなどを使いたい場合に向いています。
一方で、ファイルパスや正規表現のようにバックスラッシュが多い文字列では、\\が増えて読みにくくなりがちです。
3-2. 逐語的文字列リテラル「@」でエスケープを減らす方法
逐語的文字列リテラルは、文字列の前に@を付ける書き方です。
C#string path = @"C:\Temp\file.txt";
逐語的文字列リテラルでは、バックスラッシュを特別扱いしません。そのため、Windowsのファイルパスや正規表現を読みやすく書けます。
通常文字列では次のように書く必要があります。
C#string path = "C:\\Temp\\file.txt";
逐語的文字列なら、次のように自然に書けます。
C#string path = @"C:\Temp\file.txt";
ただし、逐語的文字列でもダブルクォーテーション"は特別です。文字列内に"を含めたい場合は、""と2つ続けて書きます。
C#string text = @"彼は""OK""と言った";
Console.WriteLine(text);
出力結果は次のとおりです。
彼は"OK"と言った
3-3. 生文字列リテラル「"""」で複数行や記号を扱う方法
C# 11以降では、生文字列リテラルを使えます。生文字列リテラルは、3つ以上のダブルクォーテーションで囲む文字列です。
C#string json = """
{
"name": "Alice",
"language": "C#"
}
""";
生文字列リテラルでは、通常のエスケープをほとんど意識せずに、複数行の文字列や引用符をそのまま書けます。
JSON、XML、HTML、SQL、複数行テンプレートなどを書くときに便利です。
C#string html = """
<div class="message">
<p>Hello, C#</p>
</div>
""";
文字列の中に"""を含めたい場合は、開始と終了のクォーテーション数を4つ以上に増やします。
C#string text = """"
これは """ を含む文字列です。
"""";
3-4. 通常文字列・逐語的文字列・生文字列の違い
C#には複数の文字列リテラルがあり、それぞれエスケープの扱いが異なります。
| 種類 | 書き方 | 特徴 | 向いている用途 |
|---|---|---|---|
| 通常文字列 | "..." | \nや\tなどのエスケープが使える | 短い文字列、改行やタブを明示したい場合 |
| 逐語的文字列 | @"..." | バックスラッシュをそのまま書ける | Windowsパス、正規表現 |
| 生文字列 | """...""" | 複数行や引用符を自然に書ける | JSON、HTML、SQL、複数行テキスト |
たとえば、同じファイルパスでも書き方は次のように異なります。
C#string path1 = "C:\\Temp\\file.txt";
string path2 = @"C:\Temp\file.txt";
string path3 = """
C:\Temp\file.txt
""";
短いパスなら逐語的文字列、複数行の構造化テキストなら生文字列が読みやすくなります。
3-5. どの文字列リテラルを使うべきかの判断基準
基本的には、読みやすさを基準に選びます。
通常の文字列リテラルが向いているのは、次のような場合です。
C#string message = "Hello\nWorld";
改行やタブをエスケープで明示したい場合は、通常の文字列が便利です。
逐語的文字列が向いているのは、バックスラッシュが多い場合です。
C#string path = @"C:\Users\User\Documents";
string pattern = @"^\d{3}-\d{4}$";
生文字列リテラルが向いているのは、複数行で引用符も含む文字列です。
C#string json = """
{
"id": 1,
"name": "Alice"
}
""";
迷った場合は、次のように考えるとよいでしょう。
\nや\tを使いたいなら通常文字列Windowsパスや正規表現なら逐語的文字列
JSON、HTML、SQL、複数行テンプレートなら生文字列
4. 引用符・ダブルクォーテーション・シングルクォーテーションのエスケープ
4-1. 文字列内でダブルクォーテーションを表示する方法
通常の文字列リテラル内でダブルクォーテーションを表示するには、\"を使います。
C#string text = "商品名は\"C#入門\"です。";
Console.WriteLine(text);
出力結果は次のとおりです。
商品名は"C#入門"です。
ダブルクォーテーションは文字列の区切りとして使われるため、文字列の中にそのまま書くことはできません。
誤った例は次のとおりです。
C#string text = "商品名は"C#入門"です。";
このコードは、途中の"で文字列が終わったと解釈されるため、コンパイルエラーになります。
4-2. 文字リテラル内でシングルクォーテーションを表示する方法
文字リテラルでシングルクォーテーションを表すには、'\''と書きます。
C#char c = '\'';
Console.WriteLine(c);
出力結果は次のようになります。
'
文字リテラルはシングルクォーテーションで囲むため、中にシングルクォーテーションをそのまま書くと構文が壊れます。
誤った例は次のとおりです。
C#char c = ''';
一方、文字列リテラルの中ではシングルクォーテーションは特別な意味を持たないため、そのまま書けます。
C#string text = "It's a pen.";
4-3. 逐語的文字列でダブルクォーテーションを書く方法
逐語的文字列リテラルでは、バックスラッシュによる\"は使いません。
C#string text = @"彼は\"OK\"と言った";
この場合、\はそのまま文字として扱われるため、期待する結果になりません。
逐語的文字列でダブルクォーテーションを含めるには、""と2つ続けて書きます。
C#string text = @"彼は""OK""と言った";
Console.WriteLine(text);
出力結果は次のとおりです。
彼は"OK"と言った
逐語的文字列では、バックスラッシュはそのまま、ダブルクォーテーションは2つ重ねる、と覚えると分かりやすいです。
4-4. 生文字列リテラルで引用符をそのまま書く方法
生文字列リテラルでは、ダブルクォーテーションをそのまま書ける場面が多くなります。
C#string text = """
彼は"OK"と言った
""";
この場合、文字列の中の"はエスケープ不要です。
JSONのようにダブルクォーテーションが多い文字列でも、読みやすく書けます。
C#string json = """
{
"name": "Alice",
"message": "Hello"
}
""";
ただし、文字列の中に区切りと同じ数の連続したダブルクォーテーションを含めたい場合は、外側のクォーテーション数を増やします。
C#string text = """"
文字列の中に """ を含めます。
"""";
4-5. 引用符のエスケープでよくあるコンパイルエラー
引用符のエスケープで多いエラーは、文字列が途中で終わってしまうケースです。
C#string text = "彼は"OK"と言った";
正しくは次のように書きます。
C#string text = "彼は\"OK\"と言った";
逐語的文字列で\"を書いてしまうミスもよくあります。
C#string text = @"彼は\"OK\"と言った";
この場合、出力にはバックスラッシュが含まれます。
彼は\"OK\"と言った
逐語的文字列では次のように書きます。
C#string text = @"彼は""OK""と言った";
文字列リテラルの種類によって、引用符の書き方が変わる点に注意しましょう。
5. 改行・タブ・空白をエスケープで表現する方法
5-1. 「\n」で改行する基本
C#で文字列内に改行を入れる基本的な方法は、\nを使うことです。
C#string text = "1行目\n2行目\n3行目";
Console.WriteLine(text);
出力結果は次のとおりです。
1行目
2行目
3行目
\nは短く書けるため、コード内で改行位置を明示したい場合に便利です。
5-2. Windows環境で使われる「\r\n」との違い
\nはラインフィード、\r\nはキャリッジリターンとラインフィードの組み合わせです。
Windowsのテキストファイルでは、改行コードとして\r\nが使われることがあります。
C#string text = "1行目\r\n2行目";
一方、LinuxやmacOSでは\nが一般的です。
近年の多くのアプリケーションではどちらも扱えますが、古いツールや特定のファイル仕様では改行コードの違いが問題になることがあります。
5-3. Environment.NewLineとの使い分け
実行環境に合わせた改行文字を使いたい場合は、Environment.NewLineを使います。
C#string text = "1行目" + Environment.NewLine + "2行目";
Console.WriteLine(text);
Environment.NewLineは、実行環境に応じた改行文字列を返します。
使い分けの目安は次のとおりです。
| 書き方 | 向いている場面 |
|---|---|
\n | プログラム内で改行を簡潔に表したい |
\r\n | Windows形式の改行が明示的に必要 |
Environment.NewLine | 実行環境に合わせた改行を使いたい |
| 生文字列リテラル | 複数行の文章やテンプレートを書きたい |
たとえば、ログや画面表示ではEnvironment.NewLine、通信仕様やファイル仕様で改行コードが決まっている場合は\r\nや\nを明示するのがよいでしょう。
5-4. 「\t」でタブを入れる方法
タブを入れるには\tを使います。
C#string text = "ID\tName\tAge";
Console.WriteLine(text);
出力例は次のとおりです。
ID Name Age
タブ区切りテキストを作る場合にも使えます。
C#string line = $"1\tAlice\t20";
ただし、CSVやTSVなどのデータ出力では、単純に\tや,で連結するだけでは不十分な場合があります。
値の中にタブ、改行、引用符が含まれる可能性がある場合は、形式に応じたエスケープ処理が必要です。
5-5. 複数行文字列を書くときの注意点
通常の文字列リテラルでは、文字列の中にそのまま改行を書くことはできません。
C#string text = "1行目
2行目";
このコードはコンパイルエラーになります。
複数行文字列を書くには、\nを使う方法があります。
C#string text = "1行目\n2行目";
逐語的文字列を使う方法もあります。
C#string text = @"1行目
2行目";
生文字列リテラルを使うと、より自然に複数行を書けます。
C#string text = """
1行目
2行目
""";
ただし、逐語的文字列や生文字列では、実際に書いた改行やインデントが文字列に含まれる点に注意が必要です。
6. バックスラッシュとファイルパスのエスケープ
6-1. Windowsパスで「\」が必要になる理由
Windowsのファイルパスでは、フォルダーの区切りにバックスラッシュ\を使います。
C:\Users\User\Documents\sample.txt
しかし、C#の通常文字列では\がエスケープシーケンスの開始として扱われます。
そのため、Windowsパスをそのまま通常文字列に書くと問題が起こることがあります。
C#string path = "C:\Users\User\Documents\sample.txt";
このコードでは、\Uなどがエスケープシーケンスとして解釈されようとするため、エラーになる可能性があります。
6-2. 通常文字列でファイルパスを書く例
通常文字列でWindowsパスを書く場合は、バックスラッシュを\\にします。
C#string path = "C:\\Users\\User\\Documents\\sample.txt";
Console.WriteLine(path);
出力結果は次のとおりです。
C:\Users\User\Documents\sample.txt
\を1つ表示したい場合は、コード上では\\と2つ書く、というのが基本です。
6-3. 逐語的文字列「@」でファイルパスを書く例
Windowsパスを書くときは、逐語的文字列リテラルを使うと読みやすくなります。
C#string path = @"C:\Users\User\Documents\sample.txt";
Console.WriteLine(path);
出力結果は同じです。
C:\Users\User\Documents\sample.txt
逐語的文字列では、バックスラッシュをエスケープする必要がありません。
ファイルパス、フォルダーパス、正規表現など、\が多い文字列では@を使うとコードがすっきりします。
6-4. パス結合ではPath.Combineを使うべき理由
ファイルパスを文字列連結で作ると、区切り文字の重複や不足が起こりやすくなります。
C#string folder = @"C:\Temp";
string file = "sample.txt";
string path = folder + "\\" + file;
このような場合は、Path.Combineを使うのが基本です。
C#using System.IO;
string folder = @"C:\Temp";
string file = "sample.txt";
string path = Path.Combine(folder, file);
Console.WriteLine(path);
Path.Combineを使うと、環境に応じた区切り文字を考慮してパスを結合できます。
また、Path.JoinやPath.GetFullPathなどのAPIを組み合わせることで、手動でエスケープや区切り文字を調整するより安全に扱えます。
6-5. URL・URIではエスケープの考え方が異なる点
URLやURIでは、Windowsパスのように\ではなく、通常はスラッシュ/を使います。
https://example.com/articles/csharp-escape
URLで日本語や空白、記号を扱う場合は、C#の文字列エスケープではなく、URLエンコードを考える必要があります。
C#string keyword = "C# エスケープ";
string encoded = Uri.EscapeDataString(keyword);
Console.WriteLine(encoded);
出力例は次のようになります。
C%23%20%E3%82%A8%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%97
C#のエスケープとURLエンコードは別物です。
C#のエスケープ:ソースコード上で文字列を正しく表すための仕組み
URLエンコード:URLとして安全に送信するための変換
用途に応じて使い分ける必要があります。
7. 文字列補間とエスケープの使い方
7-1. 文字列補間「$」の基本
文字列補間は、文字列の中に変数や式を埋め込む書き方です。
C#string name = "Alice";
int age = 20;
string message = $"{name}さんは{age}歳です。";
Console.WriteLine(message);
出力結果は次のとおりです。
Aliceさんは20歳です。
文字列の前に$を付け、{}の中に式を書きます。
C#string result = $"合計は{100 + 200}円です。";
文字列補間でも、通常の文字列リテラルと同じように\nや\"などのエスケープを使えます。
7-2. 補間文字列内で改行や引用符を使う方法
補間文字列内でも、改行は\nで表せます。
C#string name = "Alice";
string message = $"名前: {name}\n状態: 有効";
Console.WriteLine(message);
出力結果は次のとおりです。
名前: Alice
状態: 有効
ダブルクォーテーションを含める場合は、通常の文字列と同じく\"を使います。
C#string word = "OK";
string message = $"彼は\"{word}\"と言った";
Console.WriteLine(message);
出力結果は次のようになります。
彼は"OK"と言った
7-3. 中かっこ「{」「}」を表示する方法
文字列補間では、{}は式の埋め込みに使われます。
そのため、中かっこ自体を文字として表示したい場合は、{{と}}のように2つ重ねます。
C#int value = 100;
string text = $"値は{{{value}}}です。";
Console.WriteLine(text);
出力結果は次のとおりです。
値は{100}です。
単に中かっこだけを表示したい場合は次のように書きます。
C#string text = $"{{ }}";
Console.WriteLine(text);
出力結果は次のとおりです。
{ }
JSONのように中かっこが多い文字列を補間で作る場合は、通常の補間文字列だと読みにくくなることがあります。
そのような場合は、生文字列リテラルとの組み合わせが便利です。
7-4. 「$@」と「@$」の書き方
文字列補間と逐語的文字列は組み合わせて使えます。
C#string user = "User";
string path = $@"C:\Users\{user}\Documents";
Console.WriteLine(path);
出力結果は次のとおりです。
C:\Users\User\Documents
$@と@$はどちらも使用できます。
C#string path1 = $@"C:\Users\{user}\Documents";
string path2 = @$"C:\Users\{user}\Documents";
どちらも同じ意味です。
ただし、プロジェクトのコーディング規約に合わせて、どちらかに統一すると読みやすくなります。
7-5. 生文字列リテラルと文字列補間を組み合わせる方法
生文字列リテラルと文字列補間を組み合わせると、JSONやHTMLのテンプレートを読みやすく書けます。
C#string name = "Alice";
int age = 20;
string json = $$"""
{
"name": "{{name}}",
"age": {{age}}
}
""";
Console.WriteLine(json);
出力結果は次のとおりです。
JSON{
"name": "Alice",
"age": 20
}
$を2つ付けると、補間式は{{...}}で書きます。
これにより、JSONで使う通常の{や}をそのまま書きやすくなります。
たとえば、$"""..."""では{name}が補間になりますが、$$"""..."""では{{name}}が補間になります。
JSONやテンプレート内で中かっこが多い場合は、$の数を調整するとエスケープを減らせます。
8. C#の正規表現で必要なエスケープ
8-1. 正規表現におけるエスケープとは
正規表現では、.、*、+、?、(、)、[、]、\などの文字が特別な意味を持ちます。
たとえば、.は任意の1文字を表します。
regexa.c
この正規表現は、abcやa-cなどにマッチします。
ドット.そのものにマッチさせたい場合は、正規表現上で\.と書く必要があります。
regexa\.c
このように、正規表現で特別な意味を持つ文字を通常の文字として扱うためにもエスケープが必要です。
8-2. C#文字列のエスケープと正規表現のエスケープの違い
C#で正規表現を書くときに混乱しやすいのは、「C#文字列としてのエスケープ」と「正規表現としてのエスケープ」が重なることです。
たとえば、正規表現で数字を表す\dを使いたいとします。
正規表現としては次の意味です。
regex\d+
しかし、C#の通常文字列では\がエスケープに使われるため、次のように書くと問題になります。
C#string pattern = "\d+";
\dはC#の有効なエスケープシーケンスではないため、コンパイルエラーになります。
通常文字列では、バックスラッシュをエスケープして次のように書きます。
C#string pattern = "\\d+";
逐語的文字列なら、次のように書けます。
C#string pattern = @"\d+";
C#の正規表現では、逐語的文字列を使うと読みやすくなることが多いです。
8-3. 通常文字列で正規表現を書く場合の注意点
通常文字列で正規表現を書く場合は、\を\\と書く必要があります。
たとえば、郵便番号のような形式を表す正規表現は次のようになります。
C#using System.Text.RegularExpressions;
string pattern = "^\\d{3}-\\d{4}$";
bool isMatch = Regex.IsMatch("123-4567", pattern);
Console.WriteLine(isMatch);
正規表現として見れば、実際に渡されるパターンは次の意味になります。
regex^\d{3}-\d{4}$
通常文字列では、正規表現の\dを書くために\\dと書く必要があります。
バックスラッシュが多くなると読みにくいため、正規表現では逐語的文字列を使うのがおすすめです。
8-4. 逐語的文字列で正規表現を読みやすく書く方法
逐語的文字列を使うと、正規表現をそのままに近い形で書けます。
C#using System.Text.RegularExpressions;
string pattern = @"^\d{3}-\d{4}$";
bool isMatch = Regex.IsMatch("123-4567", pattern);
Console.WriteLine(isMatch);
通常文字列と比べると、\の数が少なくなり、正規表現としての見た目に近くなります。
C#// 通常文字列
string pattern1 = "^\\d{3}-\\d{4}$";
// 逐語的文字列
string pattern2 = @"^\d{3}-\d{4}$";
正規表現はただでさえ記号が多いため、C#では@"..."で書くと保守しやすくなります。
8-5. 「\d」「\s」「\w」などをC#で書く例
正規表現でよく使う文字クラスには、\d、\s、\wなどがあります。
| 正規表現 | 意味 | 通常文字列 | 逐語的文字列 |
|---|---|---|---|
\d | 数字 | "\\d" | @"\d" |
\s | 空白文字 | "\\s" | @"\s" |
\w | 単語構成文字 | "\\w" | @"\w" |
\b | 単語境界 | "\\b" | @"\b" |
使用例は次のとおりです。
C#using System.Text.RegularExpressions;
string input = "ID: 12345";
string pattern = @"\d+";
Match match = Regex.Match(input, pattern);
Console.WriteLine(match.Value);
出力結果は次のとおりです。
12345
通常文字列で同じことを書くと、次のようになります。
C#string pattern = "\\d+";
8-6. ドット・括弧・角括弧などのメタ文字をエスケープする方法
正規表現では、次のような文字がメタ文字として特別な意味を持ちます。
. ^ $ * + ? { } [ ] \ | ( )
これらを文字そのものとして扱いたい場合は、正規表現上で\を付けます。
たとえば、ドット.を文字として扱うには\.と書きます。
C#の逐語的文字列では次のようになります。
C#string pattern = @"example\.com";
通常文字列では次のようになります。
C#string pattern = "example\\.com";
括弧を文字として扱いたい場合は、次のように書きます。
C#string pattern = @"\(税込\)";
角括弧を文字として扱う例です。
C#string pattern = @"\[OK\]";
正規表現上のエスケープとC#文字列上のエスケープを混同しないことが大切です。
8-7. Regex.Escapeを使うべきケース
ユーザー入力や外部データを正規表現に埋め込む場合は、手動でエスケープするよりRegex.Escapeを使う方が安全です。
たとえば、検索したい文字列に.や+が含まれていると、それらは正規表現のメタ文字として扱われてしまいます。
C#using System.Text.RegularExpressions;
string keyword = "C# 3.0";
string pattern = Regex.Escape(keyword);
bool isMatch = Regex.IsMatch("C# 3.0を学ぶ", pattern);
Console.WriteLine(isMatch);
Regex.Escapeを使うと、正規表現上で特別な意味を持つ文字を、通常の文字として扱えるようにエスケープしてくれます。
ユーザーが入力した検索キーワードを正規表現として使う場合は、特別な理由がない限りRegex.Escapeを使いましょう。
8-8. 正規表現のエスケープでよくある失敗例
よくある失敗の1つは、通常文字列で\dをそのまま書いてしまうことです。
C#string pattern = "\d+";
正しくは次のどちらかです。
C#string pattern1 = "\\d+";
string pattern2 = @"\d+";
もう1つの失敗は、ドット.をエスケープし忘れることです。
C#string pattern = @"example.com";
この正規表現では、.が任意の1文字として扱われます。
ドメインのドットそのものにマッチさせたい場合は、次のように書きます。
C#string pattern = @"example\.com";
また、ユーザー入力をそのまま正規表現に組み込むのも危険です。
C#string keyword = userInput;
string pattern = keyword;
ユーザー入力に[や*などが含まれると、正規表現として意味を持ってしまいます。
C#string pattern = Regex.Escape(userInput);
このように、正規表現では「C#のエスケープ」と「Regexのエスケープ」の両方を意識する必要があります。
9. 実務でよく使うエスケープの具体例
9-1. JSON文字列でのエスケープ
JSONでは、文字列をダブルクォーテーションで囲みます。そのため、C#の通常文字列でJSONを直接書くと、\"が多くなります。
C#string json = "{\"name\":\"Alice\",\"age\":20}";
これは動作しますが、読みにくくなりがちです。
逐語的文字列を使うと、ダブルクォーテーションを""で表します。
C#string json = @"{""name"":""Alice"",""age"":20}";
C# 11以降なら、生文字列リテラルを使うとさらに読みやすくなります。
C#string json = """
{
"name": "Alice",
"age": 20
}
""";
ただし、実務ではJSON文字列を手動で組み立てるより、System.Text.Jsonなどのシリアライズ機能を使う方が安全です。
C#using System.Text.Json;
var user = new { Name = "Alice", Age = 20 };
string json = JsonSerializer.Serialize(user);
Console.WriteLine(json);
値の中に引用符、改行、バックスラッシュが含まれていても、ライブラリが適切に処理してくれます。
9-2. CSV出力での引用符の扱い
CSVでは、値にカンマ、改行、ダブルクォーテーションが含まれる場合、値全体をダブルクォーテーションで囲む必要があります。
また、値の中のダブルクォーテーションは""のように2つ重ねます。
csv"名前","メモ"
"Alice","彼女は""OK""と言った"
C#で簡単にCSV用のエスケープを行う例は次のとおりです。
C#static string EscapeCsv(string value)
{
if (value.Contains('"') || value.Contains(',') || value.Contains('\n') || value.Contains('\r'))
{
return "\"" + value.Replace("\"", "\"\"") + "\"";
}
return value;
}
string name = "Alice";
string memo = "彼女は\"OK\"と言った";
string line = EscapeCsv(name) + "," + EscapeCsv(memo);
Console.WriteLine(line);
出力結果は次のようになります。
csvAlice,"彼女は""OK""と言った"
CSVは仕様や利用先によって細かな違いがあるため、複雑なCSVを扱う場合は専用ライブラリを使うのが安全です。
9-3. SQL文字列で注意すべきエスケープとパラメータ化
SQLで文字列を扱う場合、シングルクォーテーションをエスケープするために''と2つ重ねることがあります。
SQLSELECT * FROM Users WHERE Name = 'O''Reilly';
しかし、C#でSQLを組み立てるときに、文字列連結や手動エスケープに頼るのは危険です。
悪い例は次のとおりです。
C#string sql = "SELECT * FROM Users WHERE Name = '" + userName + "'";
このようなコードはSQLインジェクションの原因になります。
実務では、エスケープよりもパラメータ化を優先します。
C#using var command = connection.CreateCommand();
command.CommandText = "SELECT * FROM Users WHERE Name = @name";
var parameter = command.CreateParameter();
parameter.ParameterName = "@name";
parameter.Value = userName;
command.Parameters.Add(parameter);
SQLでは、「どうエスケープするか」よりも「文字列連結でSQLを作らない」ことが重要です。
9-4. HTML・XMLでのエスケープ
HTMLやXMLでは、<、>、&、"などが特別な意味を持ちます。
たとえば、ユーザー入力をHTMLにそのまま出力すると、タグとして解釈される可能性があります。
HTML<script>alert('xss')</script>
HTMLでは、次のようにエスケープします。
| 文字 | HTMLエスケープ |
|---|---|
< | < |
> | > |
& | & |
" | " |
C#では、HTML出力時に専用のエンコード機能を使います。
C#using System.Net;
string input = "<b>Hello</b>";
string encoded = WebUtility.HtmlEncode(input);
Console.WriteLine(encoded);
出力結果は次のとおりです。
HTML<b>Hello</b>
XMLでも同様に、文字列の用途に応じたエスケープが必要です。
C#の文字列エスケープとHTML・XMLのエスケープは別のものなので、混同しないようにしましょう。
9-5. ログ出力で改行やタブを扱う方法
ログ出力では、改行やタブをそのまま出すか、見える形に変換するかを検討する必要があります。
たとえば、ユーザー入力に改行が含まれていると、ログが複数行に分かれて読みづらくなることがあります。
C#string input = "Hello\nWorld";
Console.WriteLine(input);
ログでは、改行を\nという文字列として見せたい場合があります。
C#string safeLog = input
.Replace("\\", "\\\\")
.Replace("\r", "\\r")
.Replace("\n", "\\n")
.Replace("\t", "\\t");
Console.WriteLine(safeLog);
出力結果は次のようになります。
Hello\nWorld
構造化ログを使っている場合は、文字列を手動で加工するより、ログライブラリの機能に任せる方が安全です。
9-6. コンソール出力で特殊文字を表示する方法
コンソール出力では、エスケープシーケンスを使って改行、タブ、引用符などを表示できます。
C#Console.WriteLine("名前\t年齢");
Console.WriteLine("Alice\t20");
Console.WriteLine("Bob\t35");
ダブルクォーテーションを表示する例です。
C#Console.WriteLine("彼は\"OK\"と言った");
バックスラッシュを表示する例です。
C#Console.WriteLine("C:\\Temp\\sample.txt");
Unicode文字を表示する例です。
C#Console.WriteLine("\u3042");
Console.WriteLine("\U0001F600");
ただし、絵文字や一部のUnicode文字は、コンソールのフォントや文字エンコーディングによって表示できない場合があります。
10. C#エスケープのよくあるエラーと対処法
10-1. 認識できないエスケープシーケンスが出る原因
C#でよくあるエラーの1つが、認識できないエスケープシーケンスです。
たとえば、次のコードはエラーになります。
C#string path = "C:\Users\User\Documents";
\Uや\Dなどがエスケープシーケンスとして解釈されようとするためです。
正しくは、バックスラッシュをエスケープします。
C#string path = "C:\\Users\\User\\Documents";
または、逐語的文字列を使います。
C#string path = @"C:\Users\User\Documents";
正規表現でも同じ問題が起こります。
C#string pattern = "\d+";
正しくは次のどちらかです。
C#string pattern1 = "\\d+";
string pattern2 = @"\d+";
10-2. 文字列が途中で終わる原因
文字列内にダブルクォーテーションをそのまま書くと、文字列が途中で終わったと解釈されます。
C#string text = "彼は"OK"と言った";
正しくは次のように書きます。
C#string text = "彼は\"OK\"と言った";
逐語的文字列では次のように書きます。
C#string text = @"彼は""OK""と言った";
生文字列リテラルを使う方法もあります。
C#string text = """
彼は"OK"と言った
""";
引用符の扱いは、文字列リテラルの種類によって異なるため注意しましょう。
10-3. バックスラッシュが1つ足りないケース
バックスラッシュが1つ足りないと、意図しないエスケープとして解釈されるか、コンパイルエラーになります。
誤った例です。
C#string path = "C:\Temp\new";
この場合、\Tは無効なエスケープとして問題になる可能性があります。また、\nが含まれていると改行として解釈されてしまいます。
正しくは次のように書きます。
C#string path = "C:\\Temp\\new";
または、逐語的文字列を使います。
C#string path = @"C:\Temp\new";
C#の通常文字列では、表示したい\の数に対して、コード上では2倍の\が必要だと考えると分かりやすいです。
10-4. 正規表現が想定どおりに動かないケース
正規表現では、ドットや括弧などのメタ文字をエスケープし忘れると、想定外の文字列にマッチすることがあります。
たとえば、次の正規表現はexample.comだけでなく、example-comやexampleXcomにもマッチする可能性があります。
C#string pattern = @"example.com";
ドットを文字として扱いたい場合は、次のように書きます。
C#string pattern = @"example\.com";
また、通常文字列で正規表現を書く場合は、C#側のエスケープも必要です。
C#string pattern = "example\\.com";
正規表現が想定どおりに動かない場合は、次の2点を確認しましょう。
正規表現上のメタ文字をエスケープしているか
C#文字列上のバックスラッシュを正しく書いているか
10-5. 文字化けや改行コードの違いによる問題
エスケープ自体は正しくても、文字エンコーディングや改行コードの違いによって問題が起こることがあります。
たとえば、ファイル出力で文字化けする場合は、文字列のエスケープではなく、ファイルのエンコーディングが原因かもしれません。
C#File.WriteAllText("sample.txt", "こんにちは");
必要に応じて、エンコーディングを指定します。
C#using System.Text;
File.WriteAllText("sample.txt", "こんにちは", Encoding.UTF8);
また、改行コードの違いで外部ツールが正しく読み込めない場合があります。
C#string text = "1行目\n2行目";
Windows形式の改行が必要な仕様であれば、\r\nを使います。
C#string text = "1行目\r\n2行目";
エスケープの問題に見えても、実際には文字コード、改行コード、読み込み側の仕様が原因であることもあります。
10-6. エラーを防ぐためのチェックポイント
C#のエスケープでエラーを防ぐには、次の点を確認しましょう。
文字列内の
"は\"または""で表しているかバックスラッシュを通常文字列で書く場合は
\\になっているかWindowsパスには逐語的文字列やPath APIを使っているか
正規表現ではC#文字列のエスケープとRegexのエスケープを区別しているか
JSON、CSV、HTML、SQLなどは用途別のエスケープを使っているか
外部入力を手動で連結していないか
改行コードや文字エンコーディングの仕様を確認しているか
特に実務では、手動でエスケープするより、専用APIやライブラリを使う方が安全です。
11. C#エスケープのベストプラクティス
11-1. 読みやすさを重視して文字列リテラルを選ぶ
C#では、通常文字列、逐語的文字列、生文字列を使い分けられます。
重要なのは、エスケープの少なさと読みやすさです。
C#// 読みにくい
string path1 = "C:\\Users\\User\\Documents\\sample.txt";
// 読みやすい
string path2 = @"C:\Users\User\Documents\sample.txt";
JSONも同様です。
C#// 読みにくい
string json1 = "{\"name\":\"Alice\",\"age\":20}";
// 読みやすい
string json2 = """
{
"name": "Alice",
"age": 20
}
""";
エスケープが多くなってきたら、文字列リテラルの種類を見直しましょう。
11-2. ファイルパスは逐語的文字列やPath APIを使う
Windowsのファイルパスは、通常文字列で書くと\\が多くなります。
C#string path = "C:\\Temp\\sample.txt";
固定のパスであれば、逐語的文字列を使うと読みやすくなります。
C#string path = @"C:\Temp\sample.txt";
ただし、パスを組み立てる場合は、文字列連結よりもPath.Combineを使いましょう。
C#string folder = @"C:\Temp";
string fileName = "sample.txt";
string path = Path.Combine(folder, fileName);
パス区切り文字を手動で書く機会を減らすことで、エスケープミスも減らせます。
11-3. 正規表現は逐語的文字列で書く
C#で正規表現を書く場合は、逐語的文字列を使うのがおすすめです。
C#string pattern = @"^\d{3}-\d{4}$";
通常文字列では、次のようにバックスラッシュが増えます。
C#string pattern = "^\\d{3}-\\d{4}$";
逐語的文字列を使うことで、正規表現としての見た目に近くなり、ミスを減らせます。
ただし、逐語的文字列でも正規表現上のメタ文字はエスケープが必要です。
C#string pattern = @"example\.com";
11-4. 外部出力は用途別に適切なエスケープを使う
文字列を外部に出力する場合、用途によって必要なエスケープは異なります。
| 出力先 | 必要な処理 |
|---|---|
| JSON | JSONシリアライズ |
| CSV | CSV仕様に沿った引用符処理 |
| SQL | パラメータ化 |
| HTML | HTMLエンコード |
| URL | URLエンコード |
| XML | XMLエスケープ |
| ログ | 改行や制御文字の扱いを検討 |
C#の\"や\\は、あくまでC#のソースコード上で文字列を表すためのエスケープです。
HTMLやSQL、JSONなどの安全性を保証するものではありません。
用途に応じたエスケープやエンコードを使うことが重要です。
11-5. 手動エスケープより専用APIを優先する
実務では、手動で文字列をエスケープするより、専用APIを使う方が安全です。
JSONならJsonSerializerを使います。
C#string json = JsonSerializer.Serialize(obj);
正規表現にユーザー入力を埋め込むならRegex.Escapeを使います。
C#string pattern = Regex.Escape(userInput);
HTMLならHTMLエンコードを使います。
C#string encoded = WebUtility.HtmlEncode(input);
URLならURLエンコードを使います。
C#string encoded = Uri.EscapeDataString(input);
SQLならエスケープではなくパラメータ化を使います。
C#command.CommandText = "SELECT * FROM Users WHERE Name = @name";
手動エスケープは漏れが起こりやすいため、信頼できるAPIやライブラリを優先しましょう。
12. C#のエスケープに関するFAQ
12-1. C#で「\」を文字として表示するには?
通常文字列では、\\と書きます。
C#Console.WriteLine("\\");
出力結果は次のとおりです。
\
ファイルパスのようにバックスラッシュが多い場合は、逐語的文字列を使うと読みやすくなります。
C#string path = @"C:\Temp\sample.txt";
Console.WriteLine(path);
12-2. C#でダブルクォーテーションを文字列に含めるには?
通常文字列では、\"を使います。
C#string text = "彼は\"OK\"と言った";
逐語的文字列では、""と2つ続けます。
C#string text = @"彼は""OK""と言った";
生文字列リテラルでは、そのまま書けます。
C#string text = """
彼は"OK"と言った
""";
12-3. C#で改行を入れるには「\n」とEnvironment.NewLineのどちらを使う?
用途によって使い分けます。
プログラム内で簡単に改行したいだけなら\nで十分です。
C#string text = "1行目\n2行目";
実行環境に応じた改行を使いたい場合は、Environment.NewLineを使います。
C#string text = "1行目" + Environment.NewLine + "2行目";
ファイル仕様や通信仕様で改行コードが決まっている場合は、その仕様に合わせて\nや\r\nを明示します。
12-4. C#の正規表現で「\d」と「\d」は何が違う?
正規表現としての\dは、数字を表します。
ただし、C#の通常文字列で\dを書くには、バックスラッシュをエスケープして"\\d"と書く必要があります。
C#string pattern = "\\d";
一方、逐語的文字列では、次のように書けます。
C#string pattern = @"\d";
つまり、C#コード上では"\\d"と@"\d"が同じ正規表現パターンを表します。
12-5. 逐語的文字列ではエスケープが不要になる?
逐語的文字列では、バックスラッシュのエスケープは不要になります。
C#string path = @"C:\Temp\sample.txt";
ただし、すべてのエスケープが不要になるわけではありません。
逐語的文字列内でダブルクォーテーションを表すには、""と書く必要があります。
C#string text = @"彼は""OK""と言った";
また、正規表現では、正規表現として必要なエスケープは残ります。
C#string pattern = @"example\.com";
逐語的文字列は、C#文字列としてのバックスラッシュ処理を減らすための仕組みであり、正規表現やHTMLなど別のルールまで無効にするものではありません。
12-6. 生文字列リテラルはいつ使うべき?
生文字列リテラルは、複数行の文字列や、引用符・バックスラッシュ・中かっこが多い文字列を書くときに便利です。
代表的な用途は次のとおりです。
JSON
HTML
XML
SQL
複数行メッセージ
テンプレート文字列
テスト用の入力データ
たとえば、JSONは生文字列リテラルで読みやすく書けます。
C#string json = """
{
"name": "Alice",
"message": "Hello, C#"
}
""";
文字列補間と組み合わせる場合は、$の数と中かっこの数に注意します。
C#string name = "Alice";
string json = $$"""
{
"name": "{{name}}"
}
""";
生文字列リテラルは、エスケープを減らして見た目どおりに文字列を書きたいときに有効です。
まとめ
C#のエスケープは、文字列、引用符、改行、バックスラッシュ、正規表現、ファイルパスなどを正しく扱うために欠かせない知識です。
通常の文字列リテラルでは、\n、\t、\"、\\などのエスケープシーケンスを使います。
C#string text = "彼は\"OK\"と言った\n次の行です。";
バックスラッシュが多いWindowsパスや正規表現では、逐語的文字列リテラル@を使うと読みやすくなります。
C#string path = @"C:\Temp\sample.txt";
string pattern = @"^\d{3}-\d{4}$";
JSONやHTML、SQLのような複数行で記号の多い文字列には、生文字列リテラルが便利です。
C#string json = """
{
"name": "Alice",
"language": "C#"
}
""";
一方で、JSON、CSV、SQL、HTML、URLなどの外部出力では、C#のエスケープだけでは不十分です。用途に応じて、シリアライズ、エンコード、パラメータ化、専用ライブラリを使う必要があります。
C#のエスケープで迷ったときは、次の基準で考えると分かりやすくなります。
短い文字列や改行・タブを使うなら通常文字列
Windowsパスや正規表現なら逐語的文字列
JSONやHTMLなど複数行の構造化テキストなら生文字列
外部出力やユーザー入力には専用APIを使う
エスケープを正しく理解しておくと、コンパイルエラーや文字列処理の不具合を減らし、読みやすく安全なC#コードを書けるようになります。

