文字と文字列

文字と文字列の違い

C#では、文字と文字列とは扱いが明確に異なります。
「文字」は一文字を意味し、「文字列」は「文字」が連続しているものを言います。


char c = 'a';
string s = "abcde";

char型は「文字」を扱うことができます。
string型は「文字列」を扱うことができます。

どちらも一見同じように見えますが、「文字」の場合はシングルクォーテーション(')で囲うという決まりがあります。
「文字列」の場合はダブルクォーテーション(")で囲うという決まりがあります。

これを逆にするとそれぞれ別の理由でエラーとなってしまいます。


//char型変数cは文字列を扱えない!
char c = "a";

//文字列はシングルクォーテーションでは囲えない!
string s = 'abcde';

「一文字は文字」と説明しましたが、たとえ「a」の一文字であっても、ダブルクォーテーションで囲うとそれは「文字列」とみなされます。
char型変数には「文字」しか代入できないため、「一文字の文字列」を代入することはできません。

「abcde」という文字列をシングルクォーテーションで囲うことはできません。
文字列をシングルクォーテーションで囲えば一文字とみなされる、というようなことはありません。

日本語の扱い

英語などの半角英数文字は、見た目通り「一文字なら文字扱い」が可能ですが、日本語の場合はやや特殊となっています。


char c1 = 'あ';
char c2 = '𩸽';

もしかすると2行目の文字は環境によってはうまく表示できないかもしれません。
魚へんに花と書いて「ホッケ」という字です。

1行目の「あ」は問題なくchar型変数に代入が可能です。
2行目の「ホッケ」はエラーとなります。

日本語の場合は、同じ見た目が一文字でも「一文字として扱われる文字」と「二文字として扱われる文字」が混在しています。
「ホッケ」は二文字として扱われる文字なので、char型では扱えません。

日本語を扱う場合は、一文字でも文字列(ダブルクォーテーションで囲う)として扱うのが無難です。
ただし、string型変数から一文字ずつ取り出して処理をするようなプログラムの場合はおかしな動作となる場合があります。
(ここでは詳しい説明は省きます)

string型からchar型を取り出す

string型の変数から特定の一文字(char型)を取り出すには配列の時に使用した添字演算子を使用します。


string str = "abcde";

//3文字目を取り出す
//c
char moji = str[2];

文字列の先頭を表す添え字は「0」である点に注意してください。

書き換えはできない

添字演算子を使用して文字列を書き換えることはできません。
C#では文字列は読み取り専用となっています。


string str = "abcde";

//エラー
str[0] = 'A';

文字、文字列の結合

文字や文字列は「+」記号を使用して結合することができます。


string s = "あいう" + "えお";
Console.WriteLine(s);
あいうえお

結合以外にも文字列処理はありますが、多少複雑になるので改めて説明します。

char型同士の文字の結合の場合

文字や文字列は+記号で結合が可能ですが、文字(char型)同士を+記号で結合する場合には注意が必要です。

char型は文字型ですが、実は内部的には数値として扱われています。
以下のコードは、アルファベットの「a」は内部的には「97」という数値として扱われていることを示します。


char c = 'a';
int number = c;
Console.WriteLine(number);
97

そして、char型データ同士を+記号で結ぶと、文字の結合ではなく数値の足し算となり、その結果はint型に変化します。
以下のコードは、3行目でエラーになります。


char c1 = 'a';
char c2 = 'b';
char c3 = c1 + c2;

3行目の「c1 + c2」の計算結果はint型になります。
int型をchar型の変数に代入しようとしているので、エラーになるというわけです。
(char型はint型よりも扱える値の幅が小さいため)

これは以下のコードでも同様で、int型のデータをstring型に代入しようとしているのでやはりエラーになります。


string s = 'a' + 'b';

char型同士を数値ではなく文字の結合にする方法はいくつかあります。
いままでの説明の範囲で可能なものには、最初や途中に空の文字列を挟む方法があります。


char c1 = 'a';
char c2 = 'b';
string s1 = "" + c1 + c2;
string s2 = c1 + "" + c2;

Console.WriteLine(s1);
Console.WriteLine(s2);
ab
ab

空の文字列

プログラミングでは「文字数がゼロの文字列」を使用することが多々あります。


string str1 = "";
string str2 = string.Empty;

空の文字列は「""」という風に、ダブルクォーテーションを連続して記述することで表現できます。

そのほか、「string.Empty」という特殊なキーワードを使用する方法もあります。
これはstring型にあらかじめ用意されている、空の文字列を示す値です。
意味は「""」と同じです。

「string.Empty」は見た目で意味やコードの意図が明確になります。
「""」は記述量が少ない、コードが短い、というメリットがあります。
どちらを使用しても構いませんが、両者を混在させるのではなくどちらかに統一したほうが良いでしょう。
(Visual Studioならコード補完があるのでタイピング速度は大して変わりません)

文字列の長さ

文字列の長さはLengthプロパティで取得できます。


string str = "abcde";
Console.WriteLine(str.Length);
5

null

string型の変数は、nullという特殊な値を代入することができます。
これは「空の文字列」とは別の状態です。


string str = null;

nullが格納されている状態のstring型変数は、見た目はstring型変数ですがstring型変数が持つあらゆる機能が使えない状態です。
文字列の代入や、中身がnullか否かのチェックは可能です。

例えば「Lengthプロパティ」で文字数を調べる、などの操作はできません。
文法的なエラーにはなりませんが、プログラムの実行時にエラーとなります。

nullについてはリテラルの項で改めて説明します。

nullチェック

値がnullかどうかは「nullと比較」するほか、string.IsNullOrEmptyという関数を使用することでもチェックできます。
これは値が「空文字(string.Empty)」か「null」の場合に真を返す関数です。
比較のための「if」という文についてはif文の項で改めて説明します。


static void Main(string[] args)
{
    string strEmpty = string.Empty;
    string strNull = null;

    if (strEmpty == string.Empty)
    {
        //○
    }
    if (strNull == string.Empty)
    {
        //×
    }

    if (strEmpty == null)
    {
        //×
    }
    if (strNull == null)
    {
        //○
    }

    if (string.IsNullOrEmpty(strEmpty))
    {
        //○
    }
    if (string.IsNullOrEmpty(strNull))
    {
        //○
    }
}

エスケープシーケンス

文字列中に「\」記号が登場すると、それに続く文字は特殊な意味を持ちます。
例えば、文字列中で改行をしたい場合は以下のようにします。


string s = "あいうえお\nかきくけこ";
Console.WriteLine(s);
あいうえお
かきくけこ

「\n」というのが改行を表します。
この「\n」自体は画面には表示されない特殊な文字です。
このような特殊文字をエスケープシーケンス(エスケープ文字)といいます。

\記号は環境によって「¥」(円記号)または「\」(バックスラッシュ)のどちらかで表示されます。
「¥n」と「\n」はどちらも意味は同じです。
(ここでは説明のためそれぞれの記号を全角で記述していますが、本来はどちらも半角文字です)

エスケープ文字は\記号と半角文字ひとつの組み合わせで表されますが、セットで一文字として扱われます。
つまり、シングルクォーテーションで囲み、char型変数に代入することも可能です。


char c = '\n';

よく使うエスケープ文字

以下によく使用されるエスケープ文字を示します。

\a
警告音
\b
バックスペース
\f
フォームフィード
\n
改行(ラインフィード)
\r
改行(キャリッジリターン)
\t
タブ文字
\v
垂直タブ文字
\u
Unicodeエスケープシーケンス
\U
Unicodeエスケープシーケンス(サロゲートペア)
\'
シングルクォーテーション
\"
ダブルクォーテーション
\0
Null
\\
\記号

例えば、ダブルクォーテーション自体を文字として表示したい場合は、ダブルクォーテーションの前に\記号を書きます。


string s = "ab\"c\"de";
Console.WriteLine(s);
ab"c"de

\記号を書かずにそのままダブルクォーテーションを書いてしまうと、その場所で文字列の終わりを意味することになってしまい、文法エラーになります。


string s = "ab"c"de";

文字列中にシングルクォーテーションをそのまま記述することは可能です。


string s = "ab'c'de";

同じように、ダブルクォーテーションを文字として表す場合にもエスケープシーケンスを使用する必要はありません。


char s = '"';

\記号を表示したい場合は「\\」という風に\記号を連続させます。


string s = "\\100";

全角の¥記号はそのまま記述できます。


string s = "¥100";

エスケープシーケンスの抑制(逐語的文字列)

文字列中に登場する「\」記号は特殊な意味を持ちますが、時にはこれが邪魔になる場合があります。
例えばWindowsのファイルパスは「C:\directory1\directory2\...」という形式で、\記号がディレクトリ(フォルダ)の区切りを意味します。
これをそのまま文字列にすると、\記号がエスケープシーケンスであると解釈されてしまい、思わぬエラーとなることがあります。

これを回避するには「\\」エスケープシーケンスを利用して、以下のように\記号の前にさらに\記号を書くのが通常の方法です。


string s = "C:\\directory1\\directory2\\";

これでも構いませんが、数が多くなると面倒ですし記述漏れをしてしまう場合もあります。
そのような場合は、文字列を示すダブルクォーテーションの前に@記号を書く方法もあります。


string s = @"C:\directory1\directory2\";

このように書くと、その文字列中の「\」記号は特殊な意味がなくなり、通常の文字として扱われます。
これを逐語的文字列といいます。

ダブルクォーテーションを含める場合

エスケープシーケンスが働かなくなるということは、文字列中にダブルクォーテーション記号を含めたい場合に手段がなくなるということです。
以下のようにしても、ふたつめのダブルクォーテーションが登場した時点で文字列の終わりを意味してしまい、文字列中にダブルクォーテーションを含めることができません。


string s = @"ab\"c\"de";

この場合は\記号ではなく、ダブルクォーテーションを連続させることで対応可能です。


string s = @"ab""c""de";
Console.WriteLine(s);
ab"c"de

文字列補間

文字列補間(補間文字列)は、文字列中に変数などの値を直接記述する記法です。
(C#6.0以降)

通常、ダブルクォーテーションで囲われた箇所は文字列として扱われ、そこに変数名などを書いてもただの文字列として扱われますが、文字列補間を用いると変数としての意味を持ちます。


int num = 123;
double real = 0.456;

string s1 = $"{num}, {real}";
string s2 = $"num={num}, real={real}";

Console.WriteLine(s1);
Console.WriteLine(s2);
123, 0.456
num=123, real=0.456

文字列補間は、文字列の先頭(ダブルクォーテーションの手前)に$記号を記述します。
この文字列中のブロック記号{}の間に記述された値(変数など)はその中身が前後の文字列と結合されて出力されます。

上記のサンプルコードでは文字の色が一緒になってしまっていますが、Visual Studio上では文字列と変換される値の色が分けられているのでわかりやすくなっています。
Visual Studio上の文字列補間の表示

文字列補間を使用すると、ブロック記号{}が文字として使用できなくなります。
ブロック記号を使用したい場合は「{{」「}}」と、同じ記号をふたつ続けて記述します。


int num = 123;

string s1 = $"{{を記述するには'{{{{'と書く";
string s2 = $"num={{{num}}}";

Console.WriteLine(s1);
Console.WriteLine(s2);
{を記述するには'{{'と書く
num={123}

逐語的文字列と文字列補間を併用する場合は「$@」の順で記述します。


int num = 123;

string s = $@"\{num}";

Console.WriteLine(s);
¥123

コード中の文字列の途中改行(ヒアドキュメント)

@記号はほかにも、コード中の文字列を途中で改行することも可能です。


string s = @"あいうえお
かきくけこ
さしすせそ";
Console.WriteLine(s);
あいうえお
かきくけこ
さしすせそ

このように書くと、改行などのコード中の表記と実際の文字列とを同じにすることができます。
これをヒアドキュメントといいます。