C#の標準入力の使い方|Console.ReadLineで文字列・数値・複数行を読み取る方法

はじめに

C#のコンソールアプリケーションでは、キーボードや外部プログラムから渡されたデータを「標準入力」として受け取れます。標準入力の基本となるのが、Console.ReadLineメソッドです。

Console.ReadLineを使うと、文字列を1行単位で読み取れます。ただし、入力された値は基本的に文字列として扱われるため、整数や小数として利用する場合は型変換が必要です。また、スペースで区切られた複数の値や複数行のデータを読み取る場合は、Splitfor文、while文などを組み合わせます。

この記事では、C#の標準入力について、文字列・数値・複数値・複数行を読み取る方法をサンプルコード付きで解説します。競技プログラミングでよく使う入力方法や、Console.ReadLineを使う際の注意点も確認していきましょう。

1. C#の標準入力とは

1-1. 標準入力の基本的な意味

標準入力とは、プログラムが外部からデータを受け取るために用意されている基本的な入力経路です。

コンソールアプリケーションを直接実行している場合、通常はキーボードから入力した内容が標準入力になります。たとえば、次のように名前を入力するプログラムでは、利用者がキーボードから入力した文字列をプログラム内で使用できます。

C#
Console.Write("名前を入力してください: ");
string? name = Console.ReadLine();

Console.WriteLine($"こんにちは、{name}さん");

実行例は次のとおりです。

名前を入力してください: Taro
こんにちは、Taroさん

標準入力はキーボードだけに限定されません。ファイルの内容をリダイレクトしたり、別のプログラムからデータを渡したりすることもできます。

dotnet run < input.txt

この場合、input.txtの内容が標準入力としてプログラムに渡されます。

1-2. Console.ReadLineで入力を受け取る仕組み

C#で標準入力を1行単位で読み取るときは、Console.ReadLineを使用します。

C#
string? input = Console.ReadLine();

Console.ReadLineは、標準入力から改行までの文字を読み取ります。利用者がキーボードから入力する場合は、Enterキーが押されるまで入力待ちになります。

入力された改行文字そのものは、戻り値に含まれません。たとえば、次の内容を入力したとします。

Hello

変数inputに格納されるのは、改行を除いた"Hello"です。

また、標準入力の終端に到達した場合、Console.ReadLinenullを返します。そのため、Nullable参照型が有効な環境では、戻り値をstring?として受け取るのが厳密な書き方です。

C#
string? input = Console.ReadLine();

if (input is not null)
{
Console.WriteLine(input);
}

入力が必ず存在することが保証されている競技プログラミングなどでは、null許容演算子を使って次のように書くこともあります。

C#
string input = Console.ReadLine()!;

ただし、実際にnullが返る可能性のあるプログラムでは、適切なnullチェックが必要です。

1-3. 標準入力が使われる主な場面

C#の標準入力は、主に次のような場面で使われます。

  • コンソールアプリケーションで利用者から値を受け取る

  • AtCoderなどの競技プログラミングで問題の入力を受け取る

  • バッチ処理でファイルの内容をリダイレクトする

  • 別のプログラムからパイプで渡されたデータを処理する

  • C#の学習用プログラムで入力と出力を練習する

たとえば、2つの整数を入力して合計を表示する処理では、標準入力から値を受け取った後、整数に変換して計算します。

C#
Console.Write("1つ目の整数: ");
int a = int.Parse(Console.ReadLine()!);

Console.Write("2つ目の整数: ");
int b = int.Parse(Console.ReadLine()!);

Console.WriteLine($"合計: {a + b}");

標準入力の扱いを理解すると、対話型のコンソールアプリケーションや競技プログラミングのコードを書きやすくなります。

2. C#で標準入力から文字列を読み取る方法

2-1. Console.ReadLineの基本構文

Console.ReadLineの基本構文は次のとおりです。

C#
string? 変数名 = Console.ReadLine();

実際のコードでは、次のように使用します。

C#
string? input = Console.ReadLine();

このコードを実行すると、プログラムは入力待ちになります。利用者が文字を入力してEnterキーを押すと、その内容がinputに代入されます。

入力を促すメッセージを表示する場合は、Console.Writeと組み合わせます。

C#
Console.Write("メッセージを入力してください: ");
string? message = Console.ReadLine();

Console.Writeは出力後に自動で改行しないため、案内文の右側に続けて入力できます。

一方、Console.WriteLineは出力後に改行します。

C#
Console.WriteLine("メッセージを入力してください");
string? message = Console.ReadLine();

2-2. 入力された文字列を変数に代入する方法

入力された文字列を変数に代入する基本例は次のとおりです。

C#
Console.Write("好きな食べ物を入力してください: ");
string? food = Console.ReadLine();

Console.WriteLine($"入力された食べ物は「{food}」です。");

Console.ReadLineの結果は、空白を含めて1行分がそのまま文字列として格納されます。

たとえば、次のように入力したとします。

カレー ライス

変数foodには、"カレー ライス"が格納されます。半角スペースが含まれていても、それだけで文字列が分割されることはありません。

入力値の前後にある余分な空白を削除したい場合は、Trimを使用します。

C#
string input = Console.ReadLine()?.Trim() ?? string.Empty;

このコードでは、次の処理を同時に行っています。

  • Console.ReadLineで1行読み取る

  • Trimで前後の空白を削除する

  • nullの場合は空文字に置き換える

2-3. 入力値をそのまま出力して確認する方法

受け取った入力値を確認するには、Console.WriteLineでそのまま出力します。

C#
string? input = Console.ReadLine();
Console.WriteLine(input);

入力内容が分かりやすいように、説明文を付けることもできます。

C#
Console.Write("文字列を入力してください: ");
string? input = Console.ReadLine();

Console.WriteLine($"入力値: {input}");

nullと空文字を区別して確認したい場合は、条件分岐を使います。

C#
string? input = Console.ReadLine();

if (input is null)
{
Console.WriteLine("標準入力が終了しました。");
}
else if (input.Length == 0)
{
Console.WriteLine("空文字が入力されました。");
}
else
{
Console.WriteLine($"入力値: {input}");
}

Enterキーだけを押した場合、通常はnullではなく空文字""が返ります。nullは、標準入力の終端に到達した場合に返されます。

3. C#で標準入力から数値を読み取る方法

3-1. int.Parseで整数を読み取る方法

Console.ReadLineの戻り値は文字列です。そのため、整数として計算に使用するには、int.Parseint型に変換します。

C#
int number = int.Parse(Console.ReadLine()!);

入力された整数を2倍する例は次のとおりです。

C#
Console.Write("整数を入力してください: ");
int number = int.Parse(Console.ReadLine()!);

Console.WriteLine($"2倍した値: {number * 2}");

実行例は次のようになります。

整数を入力してください: 10
2倍した値: 20

入力が必ず整数であることが保証されている場合は、int.Parseを簡潔に使用できます。ただし、整数以外の文字列が入力されると例外が発生します。

3-2. double.Parseで小数を読み取る方法

小数を読み取る場合は、double.Parseを使用します。

C#
double number = double.Parse(Console.ReadLine()!);

円の半径を入力し、面積を計算する例は次のとおりです。

C#
Console.Write("円の半径を入力してください: ");
double radius = double.Parse(Console.ReadLine()!);

double area = Math.PI * radius * radius;

Console.WriteLine($"円の面積: {area}");

小数点記号の解釈は、実行環境のカルチャ設定の影響を受けます。入力形式を.に固定したい場合は、CultureInfo.InvariantCultureを指定できます。

C#
using System.Globalization;

string input = Console.ReadLine()!;
double number = double.Parse(input, CultureInfo.InvariantCulture);

Console.WriteLine(number);

競技プログラミングでは、小数点にピリオドを使うことが一般的なので、環境差を避けたい場合はInvariantCultureの利用を検討します。

3-3. TryParseで安全に数値変換する方法

利用者が自由に入力するプログラムでは、不正な文字列が入力される可能性があります。そのような場合は、ParseよりもTryParseを使うと安全です。

C#
string? input = Console.ReadLine();

if (int.TryParse(input, out int number))
{
Console.WriteLine($"整数に変換できました: {number}");
}
else
{
Console.WriteLine("整数を入力してください。");
}

int.TryParseは、変換に成功するとtrueを返し、変換後の値をout引数に格納します。変換に失敗した場合はfalseを返すため、通常は例外が発生しません。

正しい整数が入力されるまで繰り返す処理は、次のように書けます。

C#
int number;

while (true)
{
Console.Write("整数を入力してください: ");
string? input = Console.ReadLine();

if (int.TryParse(input, out number))
{
break;
}

Console.WriteLine("入力形式が正しくありません。");
}

Console.WriteLine($"入力された整数: {number}");

小数の場合は、double.TryParseを使用します。

C#
string? input = Console.ReadLine();

if (double.TryParse(input, out double number))
{
Console.WriteLine($"小数に変換できました: {number}");
}
else
{
Console.WriteLine("数値に変換できませんでした。");
}

3-4. 数値変換でエラーになる原因

int.Parsedouble.Parseでエラーになる主な原因は、次のとおりです。

入力が空文字の場合、FormatExceptionが発生します。

C#
int number = int.Parse("");

数字以外の文字が含まれている場合も、FormatExceptionが発生します。

C#
int number = int.Parse("10円");

int型で表現できる範囲を超えている場合は、OverflowExceptionが発生します。

C#
int number = int.Parse("99999999999999999999");

Console.ReadLinenullを返し、それをint.Parseに渡した場合は、ArgumentNullExceptionが発生する可能性があります。

入力形式が保証されていない場合は、次のようにTryParseを使うのが基本です。

C#
string? input = Console.ReadLine();

if (!int.TryParse(input, out int number))
{
Console.WriteLine("有効な整数ではありません。");
return;
}

Console.WriteLine(number);

大きな整数を扱う場合は、long.Parselong.TryParseを使用します。

C#
long number = long.Parse(Console.ReadLine()!);

4. C#で複数の値を1行から読み取る方法

4-1. Splitで半角スペース区切りの入力を分割する方法

1行に複数の値が半角スペース区切りで入力される場合は、Splitを使用します。

入力例が次の形式だとします。

apple orange banana

この1行を分割するコードは次のとおりです。

C#
string[] values = Console.ReadLine()!.Split(' ');

分割後の配列には、次の値が格納されます。

values[0] = "apple"
values[1] = "orange"
values[2] = "banana"

それぞれの値を出力する例は次のとおりです。

C#
string[] values = Console.ReadLine()!.Split(' ');

foreach (string value in values)
{
Console.WriteLine(value);
}

余分な空白が入力される可能性がある場合は、StringSplitOptions.RemoveEmptyEntriesを指定します。

C#
string[] values = Console.ReadLine()!
.Split(' ', StringSplitOptions.RemoveEmptyEntries);

これにより、スペースが連続していても空の要素が作られにくくなります。

4-2. 複数の文字列を読み取る方法

名前と都道府県を1行から読み取る例を考えます。

入力例は次のとおりです。

Taro Tokyo

コードは次のようになります。

C#
string[] input = Console.ReadLine()!.Split(' ');

string name = input[0];
string prefecture = input[1];

Console.WriteLine($"名前: {name}");
Console.WriteLine($"都道府県: {prefecture}");

分割代入を使うと、2つの値を簡潔に受け取れます。

C#
string[] input = Console.ReadLine()!.Split(' ');
(string name, string prefecture) = (input[0], input[1]);

Console.WriteLine($"{name} {prefecture}");

ただし、入力された要素数が不足していると、配列の範囲外を参照してIndexOutOfRangeExceptionが発生します。自由入力を扱う場合は、要素数を確認しましょう。

C#
string[] input = (Console.ReadLine() ?? string.Empty)
.Split(' ', StringSplitOptions.RemoveEmptyEntries);

if (input.Length < 2)
{
Console.WriteLine("2つの値を入力してください。");
return;
}

string name = input[0];
string prefecture = input[1];

4-3. 複数の整数を読み取る方法

1行に入力された複数の整数を読み取るには、Splitで分割した後、それぞれをint型に変換します。

入力例は次のとおりです。

10 20 30

基本的なコードは次のようになります。

C#
string[] input = Console.ReadLine()!.Split(' ');

int a = int.Parse(input[0]);
int b = int.Parse(input[1]);
int c = int.Parse(input[2]);

Console.WriteLine(a + b + c);

配列として保持する場合は、ループを使って変換できます。

C#
string[] input = Console.ReadLine()!.Split(' ');
int[] numbers = new int[input.Length];

for (int i = 0; i < input.Length; i++)
{
numbers[i] = int.Parse(input[i]);
}

Console.WriteLine(string.Join(", ", numbers));

入力形式が保証されていない場合は、各要素に対してint.TryParseを使用します。

C#
string[] input = (Console.ReadLine() ?? string.Empty)
.Split(' ', StringSplitOptions.RemoveEmptyEntries);

int[] numbers = new int[input.Length];

for (int i = 0; i < input.Length; i++)
{
if (!int.TryParse(input[i], out numbers[i]))
{
Console.WriteLine($"「{input[i]}」は整数ではありません。");
return;
}
}

Console.WriteLine($"合計: {numbers.Sum()}");

4-4. SelectとLINQを使って簡潔に書く方法

LINQのSelectを使うと、スペース区切りの整数を配列に変換する処理を1行で書けます。

C#
int[] numbers = Console.ReadLine()!
.Split(' ')
.Select(int.Parse)
.ToArray();

Select(int.Parse)は、分割された各文字列に対してint.Parseを実行します。最後にToArrayを呼び出し、int[]へ変換しています。

余分な空白を無視する場合は、次のように書きます。

C#
int[] numbers = Console.ReadLine()!
.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Select(int.Parse)
.ToArray();

List<int>として受け取りたい場合は、ToListを使用します。

C#
List<int> numbers = Console.ReadLine()!
.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Select(int.Parse)
.ToList();

小数の配列に変換する場合は、double.Parseを指定します。

C#
double[] numbers = Console.ReadLine()!
.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Select(double.Parse)
.ToArray();

LINQを使用する場合、古い形式のC#プロジェクトでは次の名前空間が必要です。

C#
using System.Linq;

.NET 6以降のテンプレートでは、Implicit Usingsによって明示的な記述が不要な場合もあります。

5. C#で複数行の標準入力を読み取る方法

5-1. 複数行の文字列を読み取る方法

複数行の文字列を読み取る場合は、行ごとにConsole.ReadLineを呼び出します。

3行の文字列を読み取る例は次のとおりです。

C#
string first = Console.ReadLine()!;
string second = Console.ReadLine()!;
string third = Console.ReadLine()!;

Console.WriteLine(first);
Console.WriteLine(second);
Console.WriteLine(third);

入力例は次のようになります。

Apple
Orange
Banana

行数が決まっている場合は、for文を使うと簡潔です。

C#
string[] lines = new string[3];

for (int i = 0; i < lines.Length; i++)
{
lines[i] = Console.ReadLine()!;
}

5-2. 複数行の数値を読み取る方法

1行に1つずつ整数が入力される場合は、各行をint.Parseで変換します。

C#
int a = int.Parse(Console.ReadLine()!);
int b = int.Parse(Console.ReadLine()!);
int c = int.Parse(Console.ReadLine()!);

Console.WriteLine(a + b + c);

入力例は次のとおりです。

10
20
30

行数が多い場合は、配列とループを使います。

C#
int[] numbers = new int[3];

for (int i = 0; i < numbers.Length; i++)
{
numbers[i] = int.Parse(Console.ReadLine()!);
}

Console.WriteLine(numbers.Sum());

各行に複数の整数が含まれる場合は、Splitと組み合わせます。

C#
int[] firstLine = Console.ReadLine()!
.Split(' ')
.Select(int.Parse)
.ToArray();

int[] secondLine = Console.ReadLine()!
.Split(' ')
.Select(int.Parse)
.ToArray();

5-3. for文で指定回数分の入力を受け取る方法

最初の行に入力件数Nが与えられ、その後にN行のデータが続く形式はよく使われます。

入力例は次のとおりです。

3
Apple
Orange
Banana

読み取りコードは次のようになります。

C#
int n = int.Parse(Console.ReadLine()!);
string[] values = new string[n];

for (int i = 0; i < n; i++)
{
values[i] = Console.ReadLine()!;
}

foreach (string value in values)
{
Console.WriteLine(value);
}

各行が整数の場合は、次のように書けます。

C#
int n = int.Parse(Console.ReadLine()!);
int[] numbers = new int[n];

for (int i = 0; i < n; i++)
{
numbers[i] = int.Parse(Console.ReadLine()!);
}

Console.WriteLine($"合計: {numbers.Sum()}");

for文を使う方法は、読み取る行数が事前に分かっている場合に適しています。

5-4. while文で入力が続く限り読み取る方法

入力行数が決まっていない場合は、Console.ReadLinenullを返すまでwhile文で読み取れます。

C#
string? line;

while ((line = Console.ReadLine()) is not null)
{
Console.WriteLine($"読み取った行: {line}");
}

より短く書く場合は、次のようにします。

C#
while (Console.ReadLine() is string line)
{
Console.WriteLine(line);
}

この方法は、ファイルからリダイレクトされたすべての行を処理するときなどに便利です。

dotnet run < input.txt

特定の文字列が入力されるまで読み取る方法もあります。

C#
while (true)
{
string? line = Console.ReadLine();

if (line is null || line == "end")
{
break;
}

Console.WriteLine($"入力: {line}");
}

このコードでは、endが入力された場合、または標準入力が終了した場合にループを抜けます。

6. 配列やリストに標準入力を格納する方法

6-1. 1行の数値を配列に変換する方法

半角スペースで区切られた1行の整数を配列に変換する基本コードは次のとおりです。

C#
int[] numbers = Console.ReadLine()!
.Split(' ')
.Select(int.Parse)
.ToArray();

入力例は次のとおりです。

5 10 15 20

配列の内容を確認するには、string.Joinを使います。

C#
Console.WriteLine(string.Join(", ", numbers));

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

5, 10, 15, 20

整数以外にも、型変換処理を変更すれば同じ考え方で読み取れます。

C#
double[] values = Console.ReadLine()!
.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Select(double.Parse)
.ToArray();

文字列の配列でよければ、Splitの結果をそのまま使えます。

C#
string[] words = Console.ReadLine()!
.Split(' ', StringSplitOptions.RemoveEmptyEntries);

6-2. 複数行の入力を配列に格納する方法

最初に行数を読み取り、その件数分の入力を配列へ格納します。

C#
int n = int.Parse(Console.ReadLine()!);
string[] lines = new string[n];

for (int i = 0; i < n; i++)
{
lines[i] = Console.ReadLine()!;
}

整数を格納する場合は、配列の型をint[]に変更します。

C#
int n = int.Parse(Console.ReadLine()!);
int[] numbers = new int[n];

for (int i = 0; i < n; i++)
{
numbers[i] = int.Parse(Console.ReadLine()!);
}

読み取った値の最大値を表示する例は次のとおりです。

C#
int n = int.Parse(Console.ReadLine()!);
int[] numbers = new int[n];

for (int i = 0; i < n; i++)
{
numbers[i] = int.Parse(Console.ReadLine()!);
}

Console.WriteLine(numbers.Max());

6-3. Listに入力値を追加する方法

入力件数が事前に決まっていない場合や、必要に応じて要素を追加したい場合は、List<T>が便利です。

C#
List<string> lines = new();

string? line;

while ((line = Console.ReadLine()) is not null)
{
lines.Add(line);
}

整数をリストに追加する場合は、次のように書けます。

C#
List<int> numbers = new();

while (Console.ReadLine() is string line)
{
if (int.TryParse(line, out int number))
{
numbers.Add(number);
}
}

最初に入力件数が与えられる場合でも、リストを使用できます。

C#
int n = int.Parse(Console.ReadLine()!);
List<int> numbers = new(n);

for (int i = 0; i < n; i++)
{
numbers.Add(int.Parse(Console.ReadLine()!));
}

new(n)は、リストの初期容量をnに指定しています。要素数を制限するものではありませんが、追加予定の件数が分かっている場合は、内部配列の再確保を減らせます。

6-4. 2次元配列として読み取る方法

N行M列の整数を2次元配列として読み取る場合は、二重ループを使います。

入力例は次のとおりです。

2 3
1 2 3
4 5 6

最初の行に行数Nと列数Mが入力され、その後にデータが続く形式です。

C#
int[] size = Console.ReadLine()!
.Split(' ')
.Select(int.Parse)
.ToArray();

int n = size[0];
int m = size[1];

int[,] values = new int[n, m];

for (int i = 0; i < n; i++)
{
int[] row = Console.ReadLine()!
.Split(' ')
.Select(int.Parse)
.ToArray();

for (int j = 0; j < m; j++)
{
values[i, j] = row[j];
}
}

読み取った2次元配列を出力するコードは次のとおりです。

C#
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
Console.Write($"{values[i, j]} ");
}

Console.WriteLine();
}

ジャグ配列として読み取ることもできます。

C#
int[][] values = new int[n][];

for (int i = 0; i < n; i++)
{
values[i] = Console.ReadLine()!
.Split(' ')
.Select(int.Parse)
.ToArray();
}

各行の要素数が同じとは限らない場合は、2次元配列よりジャグ配列が適しています。

7. 競技プログラミングでよく使う標準入力の書き方

7-1. AtCoderでよく使う入力パターン

AtCoderなどの競技プログラミングでは、入力形式が問題文で厳密に指定されています。そのため、Console.ReadLineSplitSelectを組み合わせた書き方がよく使われます。

整数を1つ読み取る場合は次のとおりです。

C#
int n = int.Parse(Console.ReadLine()!);

文字列を1つ読み取る場合は次のとおりです。

C#
string s = Console.ReadLine()!;

2つの整数を読み取る場合は次のとおりです。

C#
int[] input = Console.ReadLine()!
.Split(' ')
.Select(int.Parse)
.ToArray();

int a = input[0];
int b = input[1];

分割代入を使う場合は、次のようにも書けます。

C#
int[] input = Console.ReadLine()!
.Split()
.Select(int.Parse)
.ToArray();

(int a, int b) = (input[0], input[1]);

競技プログラミングでは入力形式が保証されているため、簡潔さを優先してint.Parse!を使うことが一般的です。

7-2. N個の整数を読み取るコード例

最初の行に整数N、次の行にN個の整数が入力される形式を考えます。

5
10 20 30 40 50

コードは次のとおりです。

C#
int n = int.Parse(Console.ReadLine()!);

int[] numbers = Console.ReadLine()!
.Split(' ')
.Select(int.Parse)
.ToArray();

Console.WriteLine(numbers.Sum());

入力形式が正しければ、配列numbersにはN個の整数が格納されます。

厳密に要素数を確認する場合は、次のように書けます。

C#
int n = int.Parse(Console.ReadLine()!);

int[] numbers = Console.ReadLine()!
.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Select(int.Parse)
.ToArray();

if (numbers.Length != n)
{
throw new InvalidOperationException("入力された整数の個数がNと一致しません。");
}

N個の整数が1行ずつ入力される形式では、for文を使います。

C#
int n = int.Parse(Console.ReadLine()!);
int[] numbers = new int[n];

for (int i = 0; i < n; i++)
{
numbers[i] = int.Parse(Console.ReadLine()!);
}

7-3. N行M列の入力を読み取るコード例

N行M列の整数をジャグ配列として読み取る例は次のとおりです。

C#
int[] size = Console.ReadLine()!
.Split()
.Select(int.Parse)
.ToArray();

int n = size[0];
int m = size[1];

int[][] grid = new int[n][];

for (int i = 0; i < n; i++)
{
grid[i] = Console.ReadLine()!
.Split()
.Select(int.Parse)
.ToArray();
}

入力例は次のとおりです。

3 4
1 2 3 4
5 6 7 8
9 10 11 12

特定の要素にアクセスする場合は、grid[行][列]と記述します。

C#
Console.WriteLine(grid[0][0]); // 1
Console.WriteLine(grid[2][3]); // 12

文字のグリッドを読み取る場合は、各行を文字配列に変換します。

C#
int[] size = Console.ReadLine()!
.Split()
.Select(int.Parse)
.ToArray();

int h = size[0];
int w = size[1];

char[][] grid = new char[h][];

for (int i = 0; i < h; i++)
{
grid[i] = Console.ReadLine()!.ToCharArray();
}

入力例は次のとおりです。

3 4
....
.#..
..#.

7-4. 高速に標準入力を処理したい場合の考え方

通常の問題では、Console.ReadLineSplitで十分なことが多いです。しかし、入力データが非常に多い場合は、文字列の分割や配列生成の回数が処理速度に影響することがあります。

特に次の処理は、入力が大規模になると負荷が増えます。

C#
Console.ReadLine()!
.Split()
.Select(int.Parse)
.ToArray();

この書き方は簡潔ですが、行ごとに文字列配列や整数配列が生成されます。

大量の整数を高速に読み取りたい場合は、標準入力を文字単位またはバッファ単位で処理するスキャナークラスを用意する方法があります。

C#
using System;
using System.IO;

sealed class FastScanner
{
private readonly Stream _stream = Console.OpenStandardInput();
private readonly byte[] _buffer = new byte[1 << 16];
private int _length;
private int _position;

private int ReadByte()
{
if (_position >= _length)
{
_length = _stream.Read(_buffer, 0, _buffer.Length);
_position = 0;

if (_length == 0)
{
return -1;
}
}

return _buffer[_position++];
}

public int NextInt()
{
int c;

do
{
c = ReadByte();

if (c == -1)
{
throw new EndOfStreamException();
}
}
while (c <= ' ');

int sign = 1;

if (c == '-')
{
sign = -1;
c = ReadByte();
}

int value = 0;

while (c >= '0' && c <= '9')
{
value = value * 10 + (c - '0');
c = ReadByte();
}

return value * sign;
}
}

使用例は次のとおりです。

C#
var scanner = new FastScanner();

int n = scanner.NextInt();
long sum = 0;

for (int i = 0; i < n; i++)
{
sum += scanner.NextInt();
}

Console.WriteLine(sum);

ただし、最初から高速入力を使う必要はありません。まずは読みやすいConsole.ReadLineで実装し、入力規模や実行時間制限に応じて高速化を検討するのがよいでしょう。

8. Console.ReadLineを使うときの注意点

8-1. nullが返るケース

Console.ReadLineは、標準入力の終端に到達するとnullを返します。

C#
string? input = Console.ReadLine();

if (input is null)
{
Console.WriteLine("入力が終了しました。");
}

ファイルを標準入力へリダイレクトしている場合は、ファイルの末尾に到達するとnullになります。また、環境によってはEOF操作によって標準入力を終了できます。

nullを空文字へ置き換える場合は、null合体演算子を使います。

C#
string input = Console.ReadLine() ?? string.Empty;

ただし、この方法では「標準入力が終了した場合」と「空行が入力された場合」を区別できなくなります。区別が必要な処理では、先にnullかどうかを確認してください。

C#
string? input = Console.ReadLine();

if (input is null)
{
return;
}

Console.WriteLine($"文字数: {input.Length}");

8-2. 空文字が入力された場合の扱い

利用者が何も入力せずEnterキーだけを押すと、通常は空文字""が返ります。

C#
string? input = Console.ReadLine();

if (input == string.Empty)
{
Console.WriteLine("何も入力されていません。");
}

string.IsNullOrEmptyを使うと、nullと空文字をまとめて判定できます。

C#
if (string.IsNullOrEmpty(input))
{
Console.WriteLine("入力がありません。");
}

空白だけの入力も無効として扱いたい場合は、string.IsNullOrWhiteSpaceが便利です。

C#
if (string.IsNullOrWhiteSpace(input))
{
Console.WriteLine("有効な文字を入力してください。");
}

string.IsNullOrWhiteSpaceは、次のような入力をまとめて判定できます。

  • null

  • 空文字

  • 半角スペースだけの文字列

  • 全角スペースだけの文字列

  • タブや改行などの空白文字だけの文字列

8-3. 全角スペースや余分な空白への対応

Split(' ')は、指定した半角スペースだけを区切り文字として扱います。そのため、全角スペースが含まれている場合は、期待どおりに分割できないことがあります。

半角スペースと全角スペースの両方を区切り文字にするには、次のように指定します。

C#
char[] separators = { ' ', ' ' };

string[] values = Console.ReadLine()!
.Split(separators, StringSplitOptions.RemoveEmptyEntries);

前後の余分な空白だけを削除する場合は、Trimを使用します。

C#
string input = (Console.ReadLine() ?? string.Empty).Trim();

各要素の前後にある空白を削除する場合は、Selectと組み合わせます。

C#
string[] values = (Console.ReadLine() ?? string.Empty)
.Split(',')
.Select(value => value.Trim())
.ToArray();

入力例が次の形式でも、各値をきれいに取り出せます。

Apple, Orange, Banana

8-4. 入力形式が違うときの例外対策

入力形式が想定と異なる場合、Parseや配列へのアクセスで例外が発生する可能性があります。

たとえば、2つの整数を期待しているのに、1つしか入力されなかった場合を考えます。

C#
string[] input = Console.ReadLine()!.Split(' ');
int a = int.Parse(input[0]);
int b = int.Parse(input[1]);

このコードでは、input[1]が存在しないため、IndexOutOfRangeExceptionが発生します。

安全に処理するには、要素数と数値変換の両方を確認します。

C#
string[] input = (Console.ReadLine() ?? string.Empty)
.Split(' ', StringSplitOptions.RemoveEmptyEntries);

if (input.Length != 2)
{
Console.WriteLine("整数を2つ入力してください。");
return;
}

if (!int.TryParse(input[0], out int a) ||
!int.TryParse(input[1], out int b))
{
Console.WriteLine("入力された値に整数以外が含まれています。");
return;
}

Console.WriteLine($"合計: {a + b}");

例外処理を使うこともできます。

C#
try
{
int number = int.Parse(Console.ReadLine()!);
Console.WriteLine(number);
}
catch (FormatException)
{
Console.WriteLine("整数の形式ではありません。");
}
catch (OverflowException)
{
Console.WriteLine("整数の範囲を超えています。");
}
catch (ArgumentNullException)
{
Console.WriteLine("入力がありません。");
}

ただし、入力の妥当性確認が目的であれば、通常はtry-catchよりTryParseのほうが分かりやすく効率的です。

9. C#の標準入力サンプルコード集

9-1. 文字列を1つ読み取るサンプル

文字列を1つ読み取り、そのまま表示するサンプルです。

C#
using System;

class Program
{
static void Main()
{
Console.Write("名前を入力してください: ");
string? name = Console.ReadLine();

if (string.IsNullOrWhiteSpace(name))
{
Console.WriteLine("名前が入力されていません。");
return;
}

Console.WriteLine($"こんにちは、{name}さん。");
}
}

入力例は次のとおりです。

Taro

出力例は次のとおりです。

こんにちは、Taroさん。

9-2. 整数を1つ読み取るサンプル

整数を1つ安全に読み取り、2乗した値を表示します。

C#
using System;

class Program
{
static void Main()
{
Console.Write("整数を入力してください: ");
string? input = Console.ReadLine();

if (!int.TryParse(input, out int number))
{
Console.WriteLine("有効な整数ではありません。");
return;
}

Console.WriteLine($"2乗した値: {number * number}");
}
}

入力形式が保証されている場合は、次のように簡潔に書けます。

C#
int number = int.Parse(Console.ReadLine()!);
Console.WriteLine(number * number);

9-3. スペース区切りの複数値を読み取るサンプル

1行に入力された2つの整数を読み取り、合計を表示します。

C#
using System;
using System.Linq;

class Program
{
static void Main()
{
int[] numbers = Console.ReadLine()!
.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Select(int.Parse)
.ToArray();

int a = numbers[0];
int b = numbers[1];

Console.WriteLine(a + b);
}
}

入力例は次のとおりです。

10 20

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

30

要素数や入力形式を確認する安全な例は次のとおりです。

C#
string[] input = (Console.ReadLine() ?? string.Empty)
.Split(' ', StringSplitOptions.RemoveEmptyEntries);

if (input.Length != 2 ||
!int.TryParse(input[0], out int a) ||
!int.TryParse(input[1], out int b))
{
Console.WriteLine("整数を2つ入力してください。");
return;
}

Console.WriteLine(a + b);

9-4. 複数行の入力を読み取るサンプル

最初に行数を読み取り、その後の文字列を配列に格納します。

C#
using System;

class Program
{
static void Main()
{
int n = int.Parse(Console.ReadLine()!);
string[] lines = new string[n];

for (int i = 0; i < n; i++)
{
lines[i] = Console.ReadLine()!;
}

for (int i = 0; i < n; i++)
{
Console.WriteLine($"{i + 1}: {lines[i]}");
}
}
}

入力例は次のとおりです。

3
Apple
Orange
Banana

出力例は次のとおりです。

1: Apple
2: Orange
3: Banana

9-5. 配列・リストに変換するサンプル

1行の整数を配列に変換するサンプルです。

C#
int[] numbers = Console.ReadLine()!
.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Select(int.Parse)
.ToArray();

Console.WriteLine($"最大値: {numbers.Max()}");
Console.WriteLine($"最小値: {numbers.Min()}");
Console.WriteLine($"合計値: {numbers.Sum()}");

1行の整数をリストに変換するサンプルです。

C#
List<int> numbers = Console.ReadLine()!
.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Select(int.Parse)
.ToList();

numbers.Add(100);

Console.WriteLine(string.Join(" ", numbers));

複数行の整数をリストに追加するサンプルです。

C#
int n = int.Parse(Console.ReadLine()!);
List<int> numbers = new(n);

for (int i = 0; i < n; i++)
{
numbers.Add(int.Parse(Console.ReadLine()!));
}

Console.WriteLine($"平均値: {numbers.Average()}");

10. C#の標準入力に関するよくある質問

10-1. Console.ReadLineとConsole.Readの違い

Console.ReadLineは、標準入力から1行分の文字列を読み取ります。

C#
string? line = Console.ReadLine();

たとえば、ABCと入力してEnterキーを押すと、戻り値は"ABC"になります。

一方、Console.Readは、標準入力から次の1文字を読み取り、その文字を表す整数値を返します。

C#
int value = Console.Read();

入力がAの場合、戻り値は文字Aの数値表現です。文字として使用するには、char型へ変換します。

C#
int value = Console.Read();

if (value != -1)
{
char character = (char)value;
Console.WriteLine(character);
}

標準入力の終端に到達した場合、Console.Read-1を返します。

1行単位でデータを処理したい場合はConsole.ReadLine、1文字ずつ処理したい場合はConsole.Readが適しています。

10-2. ReadLineで数値を直接受け取れない理由

Console.ReadLineは、入力された1行を文字列として読み取るメソッドです。そのため、戻り値の型はstring?であり、数値を入力しても自動的にintdoubleにはなりません。

C#
string? input = Console.ReadLine();

たとえば、利用者が123と入力しても、受け取る値は整数の123ではなく文字列の"123"です。

整数として利用するには、明示的な変換が必要です。

C#
int number = int.Parse(Console.ReadLine()!);

安全に変換する場合は、int.TryParseを使用します。

C#
if (int.TryParse(Console.ReadLine(), out int number))
{
Console.WriteLine(number + 10);
}

文字列として読み取る仕組みになっていることで、数字・英字・記号などを含むさまざまな入力を同じメソッドで扱えます。

10-3. 入力待ちでプログラムが止まる理由

Console.ReadLineを実行すると、1行分の入力が完了するまで処理が待機します。

C#
Console.WriteLine("入力してください。");
string? input = Console.ReadLine();
Console.WriteLine("入力が完了しました。");

このコードでは、利用者が文字を入力してEnterキーを押すまで、最後のConsole.WriteLineには進みません。

プログラムが止まっているように見えても、実際には標準入力を待っているだけの場合があります。入力を促すメッセージを表示すると、状態が分かりやすくなります。

C#
Console.Write("整数を入力してください: ");
int number = int.Parse(Console.ReadLine()!);

オンラインジャッジでは、問題文で指定された入力データがすべて渡されます。必要以上の回数だけConsole.ReadLineを呼び出すと、入力が足りず、想定外のnullが返る原因になります。

10-4. 標準入力の終端を判定する方法

Console.ReadLineの戻り値がnullかどうかを確認すると、標準入力の終端を判定できます。

C#
string? line;

while ((line = Console.ReadLine()) is not null)
{
Console.WriteLine(line);
}

この書き方では、入力が続く間だけループが実行されます。

Console.In.ReadLineを使っても同じように判定できます。

C#
while (Console.In.ReadLine() is string line)
{
Console.WriteLine(line);
}

標準入力全体をまとめて読み取る場合は、Console.In.ReadToEndも利用できます。

C#
string input = Console.In.ReadToEnd();
Console.WriteLine(input);

ReadToEndは標準入力が終了するまで待機し、その内容を1つの文字列として返します。行単位の処理にはReadLine、入力全体を一括処理する場合にはReadToEndが適しています。

まとめ

C#で標準入力を扱う基本的な方法は、Console.ReadLineで1行分の文字列を読み取ることです。

文字列を読み取る場合は、次のように記述します。

C#
string? input = Console.ReadLine();

整数や小数として利用する場合は、int.Parsedouble.ParseTryParseなどで型変換します。

C#
int number = int.Parse(Console.ReadLine()!);

入力形式が保証されていない場合は、例外を避けるためにTryParseを使用するのが安全です。

C#
if (int.TryParse(Console.ReadLine(), out int number))
{
Console.WriteLine(number);
}

半角スペースで区切られた複数の整数は、SplitとLINQを組み合わせると簡潔に読み取れます。

C#
int[] numbers = Console.ReadLine()!
.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Select(int.Parse)
.ToArray();

複数行の入力は、行数が決まっている場合はfor文、標準入力が終了するまで読み取る場合はwhile文を使います。

C#
while (Console.ReadLine() is string line)
{
Console.WriteLine(line);
}

C#の標準入力では、Console.ReadLineが文字列を返すこと、標準入力の終端ではnullを返すこと、数値として使うには型変換が必要なことが重要です。基本的な入力パターンを身につければ、コンソールアプリケーションから競技プログラミングまで、さまざまな場面で応用できます。