C#の改行コードを完全理解|\r\n・\nの違いと文字列置換・環境別の扱い方

はじめに

C#で文字列やテキストファイルを扱っていると、「改行コード」が原因で思った通りに表示されない、置換できない、ファイルの内容が崩れるといった問題に出会うことがあります。

特に、Windowsでよく使われる\r\n、LinuxやmacOSで使われることが多い\n、古い環境で見かける\rの違いを理解していないと、文字列処理やファイル入出力で予期しない不具合が起こります。

C#では、文字列に直接\n\r\nを書く方法のほか、Environment.NewLineConsole.WriteLineStringBuilder.AppendLineなど、改行を扱うための方法が複数用意されています。

この記事では、C#の改行コードについて、基本的な意味から、\r\n\n\rの違い、文字列への改行の入れ方、Environment.NewLineの使い方、改行コードの置換・削除方法まで詳しく解説します。

1. C#の改行コードとは?まず押さえる基本

1-1. 改行コードとは何か

改行コードとは、テキストの中で「ここで行を変える」という意味を持つ特殊な文字のことです。

画面上では目に見えませんが、文字列やテキストファイルの内部には、改行を表すためのコードが含まれています。

たとえば、次のような文字列があるとします。

C#
string text = "1行目\n2行目";

この文字列を表示すると、\nの位置で行が分かれます。

1行目
2行目

つまり、改行コードは普通の文字と同じように文字列の一部として扱われますが、表示上は「改行」として解釈される特殊な文字です。

1-2. C#で使う主な改行表現

C#でよく使われる改行表現には、主に次のようなものがあります。

C#
"\n"
"\r\n"
"\r"
Environment.NewLine

それぞれの意味は次の通りです。

\n      LF。主にLinux・macOSで使われる改行コード
\r\n CRLF。主にWindowsで使われる改行コード
\r CR。古いMac OSなどで使われていた改行コード
Environment.NewLine 実行環境に応じた改行文字列

C#のソースコード内で改行を表したい場合は、単純に\nを書くこともできますし、Windows形式に合わせて\r\nを書くこともできます。

また、実行環境に合わせた改行コードを使いたい場合は、Environment.NewLineを使います。

1-3. \r・\n・\r\nの意味

\r\nは、それぞれ異なる意味を持つ制御文字です。

\rはキャリッジリターン、\nはラインフィードを表します。

\r  Carriage Return。カーソルを行の先頭に戻す
\n Line Feed。カーソルを次の行に送る
\r\n Carriage Return + Line Feed。行頭に戻して次の行へ進む

現在の一般的な開発では、Windowsでは\r\n、LinuxやmacOSでは\nがよく使われます。

C#の文字列処理では、これらはすべて文字として扱われるため、検索や置換の対象にできます。

C#
string windowsText = "1行目\r\n2行目";
string unixText = "1行目\n2行目";
string oldMacText = "1行目\r2行目";

見た目はどれも複数行に表示されることがありますが、内部的な改行コードは異なります。

1-4. 改行コードとエスケープシーケンスの関係

C#で使う\n\rは、エスケープシーケンスと呼ばれる表記です。

エスケープシーケンスとは、通常の文字として直接書きにくい文字を、バックスラッシュを使って表現する仕組みです。

たとえば、次のようなものがあります。

C#
"\n"  // 改行
"\r" // キャリッジリターン
"\t" // タブ
"\"" // ダブルクォーテーション
"\\" // バックスラッシュ

C#では、通常の文字列リテラル内で\nと書くと、バックスラッシュとnの2文字ではなく、改行を表す1つの制御文字として解釈されます。

C#
string text = "Hello\nWorld";
Console.WriteLine(text);

出力結果は次のようになります。

Hello
World

一方で、バックスラッシュそのものを文字として扱いたい場合は、\\のように書きます。

2. \r\n・\n・\rの違いを正しく理解する

2-1. \r\nはWindowsで使われる改行コード

\r\nは、CRLFと呼ばれる改行コードです。

Windowsのテキストファイルでは、一般的にこの\r\nが改行として使われます。

C#
string text = "1行目\r\n2行目\r\n3行目";
Console.WriteLine(text);

出力結果は次の通りです。

1行目
2行目
3行目

Windows環境でメモ帳などを使って作成したテキストファイルでは、各行の末尾に\r\nが入っていることが多いです。

そのため、Windows向けのテキストファイルをC#で生成する場合は、\r\nEnvironment.NewLineがよく使われます。

ただし、.NETをLinuxやmacOS上で実行している場合、Environment.NewLine\nになります。Windows形式の改行が必要な場合は、環境依存のEnvironment.NewLineではなく、明示的に\r\nを指定する必要があります。

2-2. \nはLinux・macOSで使われる改行コード

\nは、LFと呼ばれる改行コードです。

Linuxや現在のmacOSでは、一般的に\nが改行コードとして使われます。

C#
string text = "1行目\n2行目\n3行目";
Console.WriteLine(text);

出力結果は次の通りです。

1行目
2行目
3行目

Webアプリケーション、API、ログ、CSV、JSONなどでは、環境や仕様によって\nが使われることも多くあります。

また、C#の文字列内で単に改行を表現したいだけであれば、\nでも問題なく表示されるケースが多いです。

ただし、Windows形式のテキストファイルとして出力したい場合や、外部システムが\r\nを要求している場合は、\nだけでは不十分なことがあります。

2-3. \rが使われるケース

\rは、CRと呼ばれる改行コードです。

古いMac OSでは、改行コードとして\rが使われていました。

現在の一般的な環境では、単独の\rを改行コードとして使う場面は少なくなっています。

ただし、まったく使われないわけではありません。

たとえば、コンソール上で同じ行を上書き表示したい場合に、\rを使うことがあります。

C#
for (int i = 0; i <= 100; i++)
{
Console.Write($"\r進捗: {i}%");
Thread.Sleep(10);
}

この例では、\rによってカーソルを行頭に戻し、同じ行に進捗を上書き表示しています。

ファイルの改行コードとしてはあまり使いませんが、制御文字としての役割を理解しておくと、コンソール表示などで役立つことがあります。

2-4. 改行コードの違いで起きる不具合

改行コードの違いを意識していないと、C#の文字列処理でさまざまな不具合が発生します。

よくあるのは、Replaceで改行を置換できないケースです。

C#
string text = "1行目\r\n2行目";

string result = text.Replace("\n", "");

このコードでは\nだけを削除しているため、文字列内に\rが残る可能性があります。

結果として、見えない制御文字が残り、表示や比較で問題になることがあります。

また、次のような問題も起こります。

文字列比較で一致しない
CSVやTSVの行分割がうまくいかない
ログファイルの表示が崩れる
Gitの差分で不要な変更が大量に出る
外部APIに送信するデータ形式が合わない

たとえば、Windowsで作られたテキストをLinux環境で処理する場合、改行コードが\r\nのままだと、行末に\rが残ってしまうことがあります。

C#
string[] lines = text.Split('\n');

foreach (string line in lines)
{
Console.WriteLine($"[{line}]");
}

元の文字列が"A\r\nB\r\nC"の場合、Split('\n')で分割すると、各行の末尾に\rが残る場合があります。

このような不具合を避けるには、改行コードを正規化してから処理するのが有効です。

3. C#で文字列に改行を入れる方法

3-1. 文字列リテラルに\nや\r\nを書く方法

C#で文字列に改行を入れる最も基本的な方法は、文字列リテラルに\n\r\nを書くことです。

C#
string text = "1行目\n2行目";
Console.WriteLine(text);

出力結果は次の通りです。

1行目
2行目

Windows形式の改行コードを明示したい場合は、\r\nを使います。

C#
string text = "1行目\r\n2行目";
Console.WriteLine(text);

この方法はシンプルで分かりやすいですが、改行コードが固定されます。

つまり、\nと書けば常にLF、\r\nと書けば常にCRLFになります。

そのため、実行環境に合わせて改行コードを変えたい場合には、Environment.NewLineを使う方が適しています。

3-2. Environment.NewLineを使う方法

Environment.NewLineを使うと、実行環境に応じた改行文字列を取得できます。

C#
string text = "1行目" + Environment.NewLine + "2行目";
Console.WriteLine(text);

Windowsで実行した場合、Environment.NewLineは通常\r\nになります。

LinuxやmacOSで実行した場合は、通常\nになります。

文字列補間と組み合わせることもできます。

C#
string name = "山田";
string message = $"こんにちは、{name}さん{Environment.NewLine}今日もよろしくお願いします。";

Console.WriteLine(message);

出力結果は次のようになります。

こんにちは、山田さん
今日もよろしくお願いします。

OSに合わせた自然な改行コードを使いたい場合は、Environment.NewLineが便利です。

3-3. Console.WriteLineで改行する方法

コンソールに文字列を出力する場合は、Console.WriteLineを使うことで、出力後に自動的に改行されます。

C#
Console.WriteLine("1行目");
Console.WriteLine("2行目");
Console.WriteLine("3行目");

出力結果は次の通りです。

1行目
2行目
3行目

Console.Writeは改行しません。

C#
Console.Write("1行目");
Console.Write("2行目");

出力結果は次のようになります。

1行目2行目

一方、Console.WriteLineは文字列の末尾に改行を追加します。

C#
Console.WriteLine("1行目");
Console.WriteLine("2行目");

コンソールアプリでは、明示的に\nを書くよりも、行単位で出力したい場合はConsole.WriteLineを使う方が自然です。

3-4. StringBuilder.AppendLineで改行する方法

複数行の文字列を効率よく組み立てる場合は、StringBuilderAppendLineが便利です。

C#
using System.Text;

StringBuilder sb = new StringBuilder();

sb.AppendLine("1行目");
sb.AppendLine("2行目");
sb.AppendLine("3行目");

string text = sb.ToString();

Console.WriteLine(text);

AppendLineは、指定した文字列を追加したあとに改行を追加します。

大量の文字列を連結する場合、+演算子で何度も結合するより、StringBuilderを使った方が効率的です。

たとえば、ログやCSV、メール本文、レポート文書など、複数行のテキストを生成する場面でよく使われます。

C#
StringBuilder sb = new StringBuilder();

sb.AppendLine("名前,年齢,部署");
sb.AppendLine("山田,30,営業");
sb.AppendLine("佐藤,28,開発");

string csv = sb.ToString();

なお、AppendLineで追加される改行は、基本的に環境に応じた改行です。改行コードを厳密に固定したい場合は、Appendで明示的に\n\r\nを追加する方法もあります。

C#
sb.Append("1行目\r\n");
sb.Append("2行目\r\n");

3-5. 逐語的文字列リテラルと複数行文字列の扱い

C#では、逐語的文字列リテラルを使って、ソースコード上の改行をそのまま文字列に含めることができます。

逐語的文字列リテラルは、文字列の前に@を付けて書きます。

C#
string text = @"1行目
2行目
3行目";

Console.WriteLine(text);

この場合、ソースコード内の改行がそのまま文字列に含まれます。

ただし、実際に含まれる改行コードは、ソースファイルの改行コードやコンパイラの扱いに影響される場合があります。そのため、外部システム向けに厳密な改行コードが必要な場合は、\n\r\nEnvironment.NewLineなどを明示する方が安全です。

また、C# 11以降では、複数行の文字列を扱いやすい生文字列リテラルも使えます。

C#
string text = """
1行目
2行目
3行目
""";

Console.WriteLine(text);

複数行のテンプレートやJSON、SQLなどを書くときに便利です。

C#
string json = """
{
"name": "山田",
"age": 30
}
""";

ただし、これも改行コードを厳密に制御したい場合には注意が必要です。見た目上は複数行でも、内部の改行コードが処理対象の仕様と合っているか確認することが大切です。

4. Environment.NewLineの使い方と注意点

4-1. Environment.NewLineとは

Environment.NewLineは、現在の実行環境で使われる改行文字列を返すプロパティです。

C#
string newLine = Environment.NewLine;

文字列の連結に使うと、環境に合わせた改行を入れることができます。

C#
string text = "1行目" + Environment.NewLine + "2行目";

Environment.NewLineはメソッドではなくプロパティなので、後ろに()は付けません。

誤った書き方は次の通りです。

C#
// 誤り
string newLine = Environment.NewLine();

正しくは次のように書きます。

C#
// 正しい
string newLine = Environment.NewLine;

4-2. 実行環境によって返される改行コード

Environment.NewLineが返す値は、実行環境によって異なります。

一般的には、Windowsでは\r\n、LinuxやmacOSでは\nになります。

C#
Console.WriteLine(Environment.NewLine == "\r\n");
Console.WriteLine(Environment.NewLine == "\n");

Windowsで実行すると、1つ目がTrueになりやすく、LinuxやmacOSでは2つ目がTrueになりやすいです。

そのため、同じC#のコードでも、実行するOSによって生成される文字列の改行コードが変わることがあります。

これは便利な反面、外部システムやファイル形式で改行コードが決まっている場合には注意が必要です。

4-3. \r\nや\nを直接書く場合との違い

\r\n\nを直接書く場合、改行コードは常に固定されます。

C#
string text1 = "1行目\r\n2行目"; // 常にCRLF
string text2 = "1行目\n2行目"; // 常にLF

一方、Environment.NewLineは実行環境によって変わります。

C#
string text = "1行目" + Environment.NewLine + "2行目";

違いを整理すると、次のようになります。

\r\nを直接書く          常にWindows形式の改行
\nを直接書く 常にLF形式の改行
Environment.NewLine 実行環境に応じた改行

C#で改行コードを扱うときは、「環境に合わせたいのか」「特定の形式に固定したいのか」を考えることが重要です。

4-4. Environment.NewLineを使うべき場面

Environment.NewLineは、実行環境に合わせた自然な改行を使いたい場面に向いています。

たとえば、次のようなケースです。

コンソールアプリで複数行のメッセージを作る
OSに合わせたテキストファイルを生成する
ログやレポートをローカル環境向けに出力する
人が読むための文章を組み立てる

具体例は次の通りです。

C#
string message =
"処理を開始しました。" + Environment.NewLine +
"しばらくお待ちください。" + Environment.NewLine +
"処理が完了しました。";

Console.WriteLine(message);

また、StringBuilderと組み合わせる場合も自然です。

C#
StringBuilder sb = new StringBuilder();

sb.Append("名前: 山田");
sb.Append(Environment.NewLine);
sb.Append("部署: 開発部");

Console.WriteLine(sb.ToString());

実行環境ごとの標準的な改行コードを使いたい場合は、Environment.NewLineを選ぶとよいでしょう。

4-5. 固定の改行コードを使うべき場面

一方で、Environment.NewLineではなく、\r\n\nを明示的に使うべき場面もあります。

たとえば、外部仕様で改行コードが決まっている場合です。

HTTPヘッダーではCRLFが必要
特定のCSV仕様でCRLFが指定されている
APIがLFのみを想定している
Git管理上、LFに統一したい
Linuxサーバーで処理するファイルをLFに統一したい
Windows向けファイルとしてCRLFに統一したい

このような場合にEnvironment.NewLineを使うと、実行環境によって出力結果が変わってしまいます。

たとえば、Windowsで実行すると\r\n、Linuxで実行すると\nになるため、同じコードでも生成されるファイルの内容が変わる可能性があります。

外部システムとの連携では、環境に合わせるよりも、仕様に合わせることが重要です。

C#
// LFに固定したい場合
string text = "1行目\n2行目\n3行目";

// CRLFに固定したい場合
string textForWindows = "1行目\r\n2行目\r\n3行目";

特に、ファイル出力や通信データでは、求められる改行コードを確認してから実装しましょう。

5. C#で改行コードを置換・削除する方法

5-1. Replaceで\r\nを\nに置換する

Windows形式の改行コード\r\nを、LinuxやmacOSでよく使われる\nに変換したい場合は、Replaceを使います。

C#
string text = "1行目\r\n2行目\r\n3行目";

string normalized = text.Replace("\r\n", "\n");

Console.WriteLine(normalized);

この処理により、CRLFがLFに変換されます。

ただし、文字列内に\r\nだけでなく、単独の\rも混在している場合は、追加の対応が必要です。

複数の改行コードをすべて\nに統一したい場合は、次のように書けます。

C#
string text = "1行目\r\n2行目\r3行目\n4行目";

string normalized = text
.Replace("\r\n", "\n")
.Replace("\r", "\n");

Console.WriteLine(normalized);

ポイントは、先に\r\nを置換することです。

もし先に\rを置換すると、\r\nが意図しない形で処理されることがあります。

C#
// 推奨
text.Replace("\r\n", "\n").Replace("\r", "\n");

改行コードを統一してからSplit('\n')などで行単位に処理すると、不具合を減らせます。

5-2. \nを\r\nに置換する

LF形式の改行コード\nを、Windows形式の\r\nに変換したい場合もReplaceを使えます。

ただし、単純に次のように書くと注意が必要です。

C#
string converted = text.Replace("\n", "\r\n");

元の文字列にすでに\r\nが含まれている場合、この処理を行うと\r\r\nのように余計な\rが入ってしまう可能性があります。

安全にCRLFへ統一したい場合は、いったん改行コードを\nに正規化してから、\r\nへ変換する方法が分かりやすいです。

C#
string text = "1行目\r\n2行目\r3行目\n4行目";

string normalized = text
.Replace("\r\n", "\n")
.Replace("\r", "\n");

string crlfText = normalized.Replace("\n", "\r\n");

Console.WriteLine(crlfText);

このように、まずすべての改行コードをLFに統一し、その後でCRLFに変換すると、混在した改行コードにも対応しやすくなります。

ファイル出力でWindows形式にそろえたい場合にも、この方法が有効です。

C#
File.WriteAllText("output.txt", crlfText);

5-3. 改行コードをすべて削除する

文字列から改行コードをすべて削除したい場合も、Replaceを使います。

C#
string text = "1行目\r\n2行目\n3行目\r4行目";

string removed = text
.Replace("\r\n", "")
.Replace("\n", "")
.Replace("\r", "");

Console.WriteLine(removed);

出力結果は次のようになります。

1行目2行目3行目4行目

改行を削除する場合も、\r\n\n\rのすべてを考慮することが大切です。

特に、Windows形式の\r\nだけを削除するコードでは、LFやCRが残る可能性があります。

C#
// \r\nしか削除できない
string removed = text.Replace("\r\n", "");

複数の環境から受け取った文字列を処理する場合は、次のようにすべての改行パターンに対応する方が安全です。

C#
string removed = text
.Replace("\r\n", "")
.Replace("\n", "")
.Replace("\r", "");

改行を半角スペースに置き換えたい場合は、空文字ではなくスペースを指定します。

C#
string replaced = text
.Replace("\r\n", " ")
.Replace("\n", " ")
.Replace("\r", " ");

文章を1行にまとめたいときや、検索用の文字列を作るときに便利です。

まとめ

C#の改行コードを正しく扱うには、まず\r\n\n\rの違いを理解することが重要です。

Windowsでは主に\r\n、LinuxやmacOSでは主に\nが使われます。\rは現在の一般的なテキストファイルではあまり使われませんが、古い環境やコンソール制御などで登場することがあります。

C#で文字列に改行を入れる方法には、\n\r\nを直接書く方法、Environment.NewLineを使う方法、Console.WriteLineStringBuilder.AppendLineを使う方法があります。

実行環境に合わせた改行を使いたい場合は、Environment.NewLineが便利です。一方で、外部システムやファイル仕様で改行コードが決まっている場合は、\n\r\nを明示的に指定する必要があります。

また、改行コードを置換・削除する場合は、\r\nだけでなく、\n\rも考慮しましょう。特に複数の環境から受け取る文字列では、改行コードが混在している可能性があります。

C#で安定した文字列処理を行うためには、改行コードを意識し、必要に応じて正規化してから処理することが大切です。