C#: 文字列
1. 宣言と初期化
string は System.String の別名であり、不変の参照型です。一度作成されると、文字列の内容を変更することはできません。
▶ サンプル
string name = "Hello";
string empty = "";
string nullStr = null;
string fromChar = new string('A', 5);
Console.WriteLine(name);
Console.WriteLine(fromChar);
Hello
AAAAA
2. 文字列の不変性
文字列オブジェクトが一度作成されると、その文字列は変更できなくなります。すべての「変更」操作は新しい文字列を返し、元の文字列は変更されません。
▶ サンプル
string a = "Hello";
string b = a;
a = a + " World";
Console.WriteLine(a);
Console.WriteLine(b);
Hello World
Hello
ヒント:b は依然として元の "Hello" を指していますが、a + " World" はまったく新しい文字列オブジェクトを生成します。
3. 文字列の連結
複数の文字列を結合するには、演算子 +、String.Concat()、または String.Join() を使用します。
▶ サンプル
string s1 = "Hello" + " " + "World";
string s2 = String.Concat("A", "B", "C");
string s3 = String.Join(", ", new string[] { "apple", "banana", "cherry" });
Console.WriteLine(s1);
Console.WriteLine(s2);
Console.WriteLine(s3);
Hello World
ABC
apple, banana, cherry
4. 文字列補間
文字列内に変数を埋め込むには、$"" 補間構文または String.Format() を使用してください。
▶ サンプル
string name = "Alice";
int age = 25;
string s1 = $"My name is {name}, age {age}.";
string s2 = String.Format("My name is {0}, age {1}.", name, age);
string s3 = $"2 + 3 = {2 + 3}";
Console.WriteLine(s1);
Console.WriteLine(s2);
Console.WriteLine(s3);
My name is Alice, age 25.
My name is Alice, age 25.
2 + 3 = 5
ヒント:補間中括弧 {} 内には、任意の C# 式を記述でき、{value:F2} などのフォーマット指定子を追加することもできます。
5. 文字列の比較
== 演算子は、文字列の値の等価比較(参照比較ではない)を行います。Equals()、Compare()、および CompareOrdinal() を使用すると、よりきめ細かな制御が可能です。
▶ サンプル
string a = "hello";
string b = "hello";
string c = "HELLO";
Console.WriteLine(a == b);
Console.WriteLine(a.Equals(b));
Console.WriteLine(String.Compare(a, c, StringComparison.OrdinalIgnoreCase) == 0);
Console.WriteLine(String.CompareOrdinal(a, c) > 0);
True
True
True
True
警告:文字列 == は参照ではなく値を比較します。これは、他のほとんどの参照型の挙動とは異なります。
6. よく使われるメソッド:length / substring / replace / split
これらは、日常的な文字列操作で最も頻繁に使用されるメソッドです。
▶ サンプル
string s = "Hello, World!";
Console.WriteLine(s.Length);
Console.WriteLine(s.Substring(7));
Console.WriteLine(s.Substring(0, 5));
Console.WriteLine(s.Replace("World", "C#"));
string parts = "a,b,c";
foreach (string p in parts.Split(','))
{
Console.WriteLine(p);
}
13
World!
Hello
Hello, C#!
a
b
c
7. 一般的なメソッド:Trim / Contains / Index
Trim() は先頭と末尾の空白を削除し、Contains() は部分文字列の有無を確認し、IndexOf() および LastIndexOf() は位置を検索します。
▶ サンプル
string s = " Hello World ";
Console.WriteLine($"[{s.Trim()}]");
Console.WriteLine(s.Contains("World"));
Console.WriteLine(s.IndexOf("World"));
Console.WriteLine(s.LastIndexOf("o"));
[Hello World]
True
8
7
8. 一般的なメソッド:Case / StartsWith / EndsWith / Pad / Remove / Insert
より実用的な文字列処理の方法。
▶ サンプル
string s = "Hello";
Console.WriteLine(s.ToUpper());
Console.WriteLine(s.ToLower());
Console.WriteLine(s.StartsWith("Hel"));
Console.WriteLine(s.EndsWith("llo"));
Console.WriteLine("5".PadLeft(3, '0'));
Console.WriteLine("5".PadRight(3, '0'));
string r = "Hello World".Remove(5);
Console.WriteLine(r);
string ins = "H World".Insert(1, "ello");
Console.WriteLine(ins);
HELLO
hello
True
True
005
500
Hello
Hello World
9. バーバティム文字列と生文字列
リテラル文字列 @"" はエスケープシーケンスを処理しないため、ファイルパスの指定に最適です。C# 11 では、エスケープ処理を必要としない複数行のコンテンツ向けに、生文字列リテラル """ が導入されました。
▶ サンプル
string path = @"C:\Users\Doc\file.txt";
string json = """
{
"name": "Alice",
"age": 25
}
""";
Console.WriteLine(path);
Console.WriteLine(json.Trim());
C:\Users\Doc\file.txt
{
"name": "Alice",
"age": 25
}
ヒント:逐語文字列では、二重引用符は "" と記述されます。生文字列リテラルは、少なくとも3つの引用符で始まり、3つの引用符で終わります。
10. StringBuilder の概要
ループ内で文字列を繰り返し連結する場合、string はその都度新しいオブジェクトを作成するため、パフォーマンスが低下します。一方、StringBuilder は内部バッファ上で処理を行い、最終的な文字列を一度だけ生成します。
▶ サンプル
using System.Text;
var sb = new StringBuilder();
for (int i = 0; i < 5; i++)
{
sb.Append(i);
sb.Append(" ");
}
Console.WriteLine(sb.ToString().Trim());
0 1 2 3 4
ヒント:ループ内で多数の文字列を連結する際は、StringBuilder を使用すると、メモリの割り当てを大幅に削減できます。
11. 文字エンコーディング
C#の文字列はUTF-16エンコーディングを使用します。charは2バイト(1つのUTF-16コード単位)を占めます。
▶ サンプル
char ch = 'A';
Console.WriteLine(ch);
Console.WriteLine((int)ch);
Console.WriteLine(sizeof(char));
A
65
2
❓ よくある質問
== は参照を比較するのか、それとも値を比較するのか?== 演算子は、内容による等価比較を行うようにオーバーロードされています。stringは不変であるため、連結を行うたびに新しいオブジェクトが生成されてしまいます。一方、StringBuilderはバッファを修正し、最後にのみ最終的な文字列を生成します。@"" と通常の文字列の違いは何ですか?\n、\t など)は処理されません。 バックスラッシュは文字通りそのまま保持されるため、ファイルパスや正規表現に最適です。ArgumentOutOfRangeException が発生します。呼び出す前に長さを確認してください。📖 まとめ
stringは不変の参照型であり、System.Stringの別名です。- 連結:
+、String.Concat()、String.Join() - 補間:
$""およびString.Format() - 比較:
==は値を比較します。Equals()およびCompare()では、さらに多くのオプションが利用できます - 一般的な方法:
Length,Substring,Replace,Split,Trim,Contains,IndexOf,ToUpper,ToLower,StartsWith,EndsWith,PadLeft,PadRight,Remove,Insert - 逐語文字列
@""ではエスケープが無効になります。生文字列リテラル"""では、複数行のコンテンツがサポートされます。 StringBuilderは、ループ内での繰り返し連結に最適であり、パフォーマンスを向上させます- 文字列はUTF-16エンコーディングを使用しており、
charは2バイトを占めます
📝 練習問題
- 文字列変数を宣言し、補間を使用して
"My name is XXX, and I am XX years old."を出力する - カンマ区切りの文字列
"a,b,c,d"を受け取り、Splitで分割し、各要素を別々の行に出力するプログラムを作成してください。 - 文字列
" Hello World "を切り取り、"World"を"C#"に置き換えて、その結果を出力してください StringBuilderを使用して、1 から 100 までの数字を 1 行に 1 つずつ連結し、最終的な文字列を出力してください- 文字列リテラルを使用して Windows ファイルパス
C:\Program Files\MyApp\config.jsonを定義し、それを出力する