C#の string は、UTF-16の文字(char の値)の並びです。参照型ですが、重要な点では値のように振る舞います。不変であり、== はオブジェクトの同一性ではなくテキストを比較します。string は.NETの型 System.String を表すC#のキーワードで、2つは互換です。
出力:
Porto
5
0
*****
hi
Porto has 5 letters
文字列は不変
文字列をその場で変更するメソッドはありません。ToUpper、Replace、Trim をはじめすべてのメソッドは新しい文字列を返し、元の文字列には触れません。戻り値を使い忘れるのは、非常によくある文字列のバグです。
出力:
[ maya ]
[MAYA]
tea
tea and cake
不変なので、文字列はスレッド間で安全に共有でき、辞書のキーにも使えます。代償として、ループの中で文字列を少しずつ組み立てると、ステップごとに新しい文字列が作られます。その場合はStringBuilderを使います。
長さとインデックス
Length はプロパティです(かっこは付けません)。インデクサー s[i] は、0から数えた位置 i の char を返し、読み取り専用です。
出力:
7
A
1
IndexOutOfRangeException
XB-2931
C# 8以降では、末尾からのインデックスも使えます。code[^1] は最後の文字で、code[code.Length - 1] と同じです。複数の文字をまとめて取り出すには、Substringを参照してください。
Length が数えるのはUTF-16のコード単位で、読む人が文字と見なすものではありません。ほとんどの言語のほとんどの文字は1単位ですが、絵文字や一部のまれな文字体系は2単位(サロゲートペア)を使うので、"👍".Length は2です。
文字列の比較
== と != は、大文字と小文字を区別して文字を比較します。それ以外の比較では、比較方法を示す StringComparison の値を渡します。
出力:
False
False
True
True
apple first
True
False
False
True
どの比較を使うか:
Ordinalは文字の数値コードを比較します。高速で予測でき、どのマシンでも同じです。識別子、ファイル名、キー、プロトコルの値など、人に見せないものすべてに使います。OrdinalIgnoreCaseは同じ比較で、大文字と小文字を無視します。ファイルの拡張子やHTTPヘッダーのような、大文字と小文字を区別しない確認に適しています。CurrentCulture(とCurrentCultureIgnoreCase)はユーザーの言語の規則に従うので、その言語の辞書と同じように単語を並べます。ユーザーに見せるリストの並べ替えに使います。InvariantCultureは、ユーザーの言語設定に依存しない、カルチャを考慮した規則を使います。それでもグローバリゼーションのライブラリには依存します。現代の.NETはICUを、.NET FrameworkはWindowsのNLSを使い、両者は一部の文字列の順序が異なることがあります。
StringComparison なしの string.Compare(a, b) と a.CompareTo(b) は現在のカルチャを使うので、結果がマシンによって変わります。a.ToLower() == b.ToLower() による比較は避けます。新しい文字列を2つ割り当て、一部のカルチャでは間違った答えになります(トルコ語の点付きと点なしのiが典型的な例です)。
a がnullのときに a.Equals(b) を呼ぶと NullReferenceException が投げられますが、a == b と静的な string.Equals(a, b) はnullを安全に扱います。
エスケープ文字
通常の文字列リテラルの中では、バックスラッシュがエスケープシーケンスを始めます。
| エスケープ | 意味 |
|---|---|
\n | 改行(ラインフィード) |
\r | 復帰(キャリッジリターン) |
\t | タブ |
\\ | バックスラッシュ |
\" | 二重引用符 |
\' | 単一引用符(char のリテラルでのみ必要) |
\0 | null文字 |
\uXXXX | 4桁の16進数のコードによるUTF-16の文字。例:\u00e9 |
\U0001F44D | 8桁の16進数のコードによる文字。U+FFFFを超えると2つの char 値になる |
\xH から \xHHHH | 1から4桁の16進数による文字(長さがあいまいなので避ける) |
\a、\b、\f、\v | 警告音、バックスペース、改ページ、垂直タブ |
\e | エスケープ文字、U+001B(C# 13) |
出力:
Name: Ana
City: Porto
She said "hi"
C:\temp\report.txt
cafe = cafe
' is a quote char
"\d" のような認識されないシーケンスはコンパイルエラー(CS1009、認識できないエスケープシーケンス)になります。Windowsのパスや正規表現を通常の文字列で書くと、こうなります。
逐語的文字列と複数行の文字列
リテラルの前に @ を付けると逐語的になります。バックスラッシュはそのままの文字になり、文字列は複数行にまたがれます。残るエスケープは、二重引用符1つを生成する "" だけです。
出力:
C:\Users\ana\Documents\notes.txt
\d{3}-\d{4}
He said "ready" and left.
Rua das Flores 12
4050-262 Porto
Portugal
first line
second line
逐語的な複数行の文字列には、続きの行のインデントも含め、引用符の間のすべてが含まれます。だから通常は、上のように左端にそろえて書きます。含まれる改行はソースファイルのものなので、Windowsの改行コードで保存されたファイルでは \r\n になります。
C# 11では、両方の問題を解決する生文字列リテラルが追加されました。3つ以上の二重引用符で始まって終わり、エスケープはまったく不要で、閉じ引用符のインデントの分だけインデントを取り除きます。
// C# 11 and later
string json = """
{
"name": "Ana",
"path": "C:\temp"
}
""";
// The 4 spaces before the closing """ are removed from every line.
内容自体に """ が含まれる場合は、代わりに4つの引用符で始めて終えます。生文字列リテラルは補間とも組み合わせられます($"""...""")。文字列補間を参照してください。
null、空、空白
文字列の変数は、null(文字列がまったくない)、空(""、長さ0)、または空白だけを含む状態になりえます。2つの静的なヘルパーは、NullReferenceException の危険なしにこれらのケースを確認します。
出力:
null empty: True blank: True
"" empty: True blank: True
" " empty: False blank: True
"Ana" empty: False blank: False
True
ユーザーの入力を検証するなら、ほぼ常に string.IsNullOrWhiteSpace が求めているものです。string.Empty と "" は同じ値で、どちらを書くかはスタイルの問題です。
文字のループ
文字列は列挙可能なので、foreach で各 char を訪れます。char 型には文字を分類する静的メソッドがあります。
出力:
letters=6 digits=4 upper=1 symbols=1
!6202tesnuS
文字列の連結
+ は連結し、反対側がどんな型でも使えます(ToString() を呼びます)。多くの値を組み合わせるなら、補間か string.Join を優先します。
出力:
Ana Silva, 31
Ana Silva, 31
AnaSilva
tea | coffee | juice
Total: 23
Total: 5
最後の2行は優先順位の落とし穴を示しています。+ は左から右に評価されるので、左辺が文字列になった時点で、それ以降の + はすべて連結になります。連結の中の算術演算はかっこで囲みます。
よくある質問
C#で文字列の長さを取得するには?
Length プロパティを使います:"hello".Length は5です。メソッドではなくプロパティなので、かっこは付けません。Length はUTF-16のコード単位を数えるので、絵文字など基本多言語面の外にある文字は2と数えられます。null の文字列に対して呼ぶと NullReferenceException が投げられます。
C#で文字列を比較するには?
a == b はテキストを比較し、大文字と小文字を区別します。大文字と小文字を区別しない等価性には string.Equals(a, b, StringComparison.OrdinalIgnoreCase) を使います。文字列を並べ替えたり順序を決めたりするには、string.Compare(a, b, StringComparison.Ordinal) かカルチャを考慮した比較を使い、これは負の数、ゼロ、正の数のいずれかを返します。
C#で複数行の文字列を書くには?
リテラルの前に @ を付けて逐語的にします。複数行にまたがることができ、バックスラッシュはそのままの文字になり、二重引用符は "" と書きます。C# 11以降では、""" で区切る生文字列リテラルも複数行にまたがり、共通のインデントを取り除き、エスケープがまったく不要です。\n や Environment.NewLine で行をつなぐこともできます。
C#の逐語的文字列とは何ですか?
@"C:\Users\ana" のように、前に @ を付けた文字列リテラルです。エスケープシーケンスが処理されないので、バックスラッシュは単なるバックスラッシュであり、Windowsのパスや正規表現に自然に使えます。中で使えるエスケープは、二重引用符を表す "" だけです。
C#のstringとStringの違いは何ですか?
違いはありません。int が System.Int32 の別名であるのと同じく、string は.NETの型 System.String を表すC#のキーワードの別名です。慣例では、宣言には string を、静的な呼び出しには string.IsNullOrEmpty(...) を使いますが、どちらもまったく同じものにコンパイルされます。
C#ではどんなエスケープ文字が使えますか?
\n 改行、\r 復帰、\t タブ、\\ バックスラッシュ、\" 二重引用符、\' 単一引用符、\0 null文字、\uXXXX 16進数のコードによるUTF-16の文字、\U0001F600 8桁のコードによる文字(サロゲートペアになります)、\a 警告音、\b バックスペース、\f 改ページ、\v 垂直タブ、そして \e(C# 13)エスケープです。\d のような未知のシーケンスはコンパイルエラー(CS1009)になるので、正規表現は通常逐語的文字列で書きます。