6.4 string型②とchar型
6.4.1 string型と配列
string型は、実際には文字の配列であると捉えると、文字列に対する操作を行うことができる。
一度、アルファベットと数字・一部の記号だけ、いわゆる「1バイト文字」のみで考えよう。ひらがなやカタカナについては後で説明する。
DANGER
ひらがな・カタカナ・漢字などの文字を使うと、以下の説明が成り立たなくなってしまうことがある。
配列と同じようにして、長さを取得したり、1文字ずつ取得したりすることができる。
string s = "traP";
cout << s.size() << endl; // 配列と捉えて配列の要素数を取得する。
cout << s.length() << endl; // length()によって文字列の長さを取得する
for (int i=0; i<s.size(); i++) {
cout << s[i];
}6.4.2 バイト・ビット
ビット(bit)は、1ビットは0か1かの情報のみを持つ。
バイト(Byte)は、パソコンが一般的に処理するデータの単位。基本的に8bit=1Byte。 よくスマホの通信量とかの「キロバイト」等のバイトはこれを指している。
8bitなので、1バイトで扱える情報は0から255の256()種類である。
6.4.3 char型
文字1文字を扱う時は、char型を用いる。
しばしば、char型で表されるものを「文字」、string型で表されるものを「文字列」と呼び分けて区別する。文字列は文字の並びである。
string s = "Hello";
char c = s[1];
cout << c << endl; // Output: e1文字を扱う時は、''(シングルクォーテーション)で囲う。
string s = "traP";
s[3] = 'Q';
cout << s << endl; // Output: traQここで、s[3](文字列sの4文字目)は文字(≠文字列)であるから以下のように書くとエラーとなる。
string s = "traP";
s[3] = "Q";
cout << s << endl; // Output: traQ6.4.4 ASCII
各文字には、文字コード(ASCIIコード)と呼ばれる番号が定められていて、内部的にchar型には数値が格納されている。
char c = 'e';
int a = c;
cout << a << endl; // output: 101ASCIIコード表:https://e-words.jp/p/r-ascii.html
ここで、アルファベットは順番に並んでいるという事実は覚えておくと良い。
逆に、charに数値を代入によって文字を代入することもできる。
char c = 81;
cout << c << endl; // output: Q6.4.5 文字の比較
6.4.4によれば、1文字1文字は、実際は数値として扱われているのであった。よって、数値と同じように扱えるということは、以下のように比較できるということである。
cout << ('A' < 'B') << endl;ここで、アルファベットはASCIIコード上で順番に並んでいるということを思い返すと、 ('A' <= x && x <= 'Z')で「文字が大文字アルファベットかどうか」が判定できる。 更にこれとfor文をうまく使えば、(アルファベットの)辞書順でどちらが先かを実装することができるだろう。
TIP
実際には、文字列の辞書順で先かどうかは、<や>の不等号演算子で簡単に実装できる。
string s = "Hello";
string t = "Bello";
cout << (s < t) << endl;0string型同士で比較するときに、1文字目を比較→同じなら2文字目を比較→…という処理を行って比較されている。
6.4.6 マルチバイト文字
ところで、ASCIIコード表には日本語特有の文字(ひらがな・カタカナ・漢字)が存在しないことに気づくだろうか。
これは1バイトで扱える情報が256通りしかないから、日本語は1バイトだけでは扱うことができない。 それゆえ、日本語(ひらがなカタカナ等)はマルチバイト文字で表現されている(複数バイトで1文字を表す方式)。
ここで、char型は、正確には「1バイトの整数型」である。よって、char型ではひらがな等の字を扱うことができない。実際に試してみると、5文字なのに長さは15と表示されてしまうし、1文字目を出力してみようと思ってもうまく出力されない。例えば「こ」の場合は、3文字出力してようやく「こ」が表示されるのである。
string dame = "こんにちは";
cout << dame.length() << endl;
cout << dame[0] << endl;
cout << dame[0] << dame[1] << dame[2] << endl;15
�
こ多バイト文字を扱える型も存在するが、非常に扱いが面倒なのでここでは扱わない。 C++以外の言語でも大体は文字列を扱えるが、マルチバイト文字に対する扱いは言語によってまちまちだったりするので、よく調べること。
文字化け
ここで横道に逸れてしまうが、せっかくの機会なので「文字化け」についても触れておこう。
歴史的な経緯
ASCIIでは日本語文字を扱えないのは明らかだったので、1文字で2バイトを使う文字コード体系が考案された。2バイトであれば 文字を扱えるので、これだけあれば十分だという事である。 しかし、結果としては国内で文字コードが乱立し(Shift-JIS, EUC-JP 等…)、様々衝突するようになった上、国内にとどまらず各国で独自の文字コードが作成されてしまい、混乱を極めてしまったのである(ASCIIで表せないのは日本語だけではなく、アラビア文字・簡体字・ギリシャ文字など様々…)。
最終的には、世界の全文字を扱う文字コードとしてUnicode(≒ UTF-8)が策定され、今日ではこれが普及している。しかし完全に普及している訳でもなく、よって、今日見かける文字化けはもっぱら「UTF-8かUTF-8以外か」の文字コードを使って発生しているパターンである。
CJK問題
また、日本語の漢字が中国語のフォントで表示されている、という謎の現象に遭遇したこともあるかもしれない。これは、Unicodeを制定した際に日本語・中国語(簡体字・繁体字)・韓国語の漢字について、似ている漢字を全て一緒くたにしてしまった事が原因である。 → Your Code Displays Japanese Wrong
横道
(横道の横道はもう獣道では…?) 日本国内は2バイト文字コードの覇権を争うために揉めていたが、その間ヨーロッパでは自国専用の1バイト文字が乱立していて同じように揉めていたらしい。
TIP
int型は4バイトの整数型である。扱える情報はで、整数は負と正の値を取るから非負整数の部分に個を割り当てる。なのだが、実はこの値は既にテキストで一度出現している。さてどこだろうか?