文字コードについて。
C/C++での文字データのまとめ
先ずはデータ型
char:char型へのポインタ
Cスタイル文字列:
char型の配列やchar型へのポインタで構成される文字列型です。C言語の文字列操作関数(strlen、strcpy、strcatなど)を使用して操作することができますが、C++ではstd::stringやstd::wstringなどのクラスを使用することが推奨されます。また、ワイド文字版のCスタイル文字列(wchar_t型)もあります。
std::string:
標準ライブラリの基本的な文字列型通常の文字(char型)で構成されます。ASCII文字や拡張ASCII(例:ISO-8859-1)などの文字
を扱う場合に使用します。
UTF-8エンコードされた文字列を扱う場合、std::stringを使用することが一般的です。
std::wstring:
ワイド文字(wchar_t型)で構成される文字列型です。WindowsではUTF-16エンコーディング、Unix系OSではUTF-32エンコーディングが一般的です。Unicode文字を扱う場合に使用されることが多いです。
(注意)Windowsでも文字によってサロゲートペアで2バイトではなく4バイトの場合がある
サロゲートペアは、U+10000からU+10FFFFまでのコードポイントをエンコードするために使用されます。これには、古典的な文字、絵文字、音楽記号、数学記号などが含まれます。
std::u8string:
C++20では、std::u8stringという新しい文字列型が導入されました。std::u8stringは、char8_t型で構成され、UTF-8エンコーディングされた文字列を明示的に扱うことができます。ただし、C++20のstd::u8stringのサポートは、コンパイラによってはまだ不完全な場合があります。
std::u16string:
C++11で導入された、UTF-16エンコーディングの文字列型です。char16_t型で構成されており、サロゲートペアを含むUnicode文字を扱うことができます。
std::u32string:
C++11で導入された、UTF-32エンコーディングの文字列型です。char32_t型で構成されており、すべてのUnicode文字を扱うことができます。
std::basic_string:
C++標準ライブラリのテンプレートクラスで、std::string、std::wstring、std::u16string、std::u32stringの基底となっています。std::basic_stringを使って、独自の文字型で文字列クラスを定義することができます。
UTF-8:
UTF-8は、Unicodeの可変長エンコーディングの1つで、すべてのUnicode文字を表現できます。UTF-8は、1バイトから4バイトの範囲で各Unicode文字をエンコードし、ASCII文字は1バイトで表現されるため、ASCII互換性があります。これは、多くの既存のシステムやプロトコルとの互換性を維持しながら、世界中の言語や記号をサポートできるという利点があります。
C++では、UTF-8エンコードされた文字列を扱う場合、std::stringを使用することが一般的です。ただし、UTF-8エンコーディングでは、文字が可変長であるため、文字のインデックスに直接アクセスすることが難しくなります。したがって、文字列操作には注意が必要です。
C++17以降では、UTF-8リテラルを直接表現することができます。u8プレフィックスを使用して、UTF-8エンコーディングの文字列リテラルを作成できます。
#include <iostream>
#include <string>
int main() {
std::string utf8_str = u8"こんにちは、世界!";
std::cout << utf8_str << std::endl;
return 0;
}
また、C++20では、std::u8stringという新しい文字列型が導入されました。std::u8stringは、char8_t型で構成され、UTF-8エンコーディングされた文字列を明示的に扱うことができます。ただし、C++20のstd::u8stringのサポートは、コンパイラによってはまだ不完全な場合があります。
#include <iostream>
#include <string>
int main() {
std::u8string utf8_str = u8"こんにちは、世界!";
std::cout << reinterpret_cast<const char*>(utf8_str.data()) << std::endl;
return 0;
}
UTF-8文字列を扱う際には、適切なUnicode対応の文字列操作関数やライブラリを使用することが重要です。例えば、std::u8stringやstd::stringでUTF-8文字列を扱う場合、Boost.TextやICUなどのUnicode対応ライブラリを使用することが推奨されます。
UTF-16:
UTF-16(Unicode Transformation Format - 16-bit)は、Unicode文字を表現するための可変長エンコーディング方式です。UTF-16は、Unicode文字を2バイト(16ビット)または4バイト(32ビット)の符号単位で表現します。
基本多言語面(BMP)に含まれる文字(U+0000 から U+FFFF)は、2バイト(16ビット)で表現されます。これには、ほとんどの現代の文字が含まれます(ラテン文字、キリル文字、ギリシャ文字、CJK(中国、日本、韓国)の漢字など)。
補助面(U+10000 から U+10FFFF)の文字は、サロゲートペアと呼ばれる2つの2バイト(16ビット)符号単位で表現されます。これには、絵文字、古典的な音楽記号、ゴシック文字、古代文字、特殊記号などが含まれます。
UTF-16は、メモリ効率と互換性のバランスを取り、特に多くのアジアの言語で広く使われています。ただし、UTF-16は1文字あたりのバイト数が可変であるため、文字列処理に注意が必要です。サロゲートペアを考慮しない処理は、特定の文字が正しく解釈されないことがあります。
UTF-32:
UTF-32(Unicode Transformation Format - 32-bit)は、Unicode文字を表現するための固定長エンコーディング方式です。UTF-32では、すべてのUnicode文字が4バイト(32ビット)の符号単位で表現されます。
UTF-32の主な特徴は以下の通りです:
固定長エンコーディング:すべての文字が4バイトで表現されるため、文字数とバイト数の変換が容易で、ランダムアクセスが可能です。
サロゲートペアの問題がない:UTF-16では補助面の文字がサロゲートペアで表現されるため、文字列処理が複雑になることがありますが、UTF-32ではその問題がありません。
ただし、UTF-32の欠点は、メモリ効率が低いことです。すべての文字が4バイトで表現されるため、アルファベットや漢字などの文字に比べてメモリ消費が大きくなります。このため、UTF-32は一般的にメモリ効率が重要でない場合や、ランダムアクセスや簡単な文字列処理が優先される場合に使用されます。
文字数と実際のメモリ上のバイト数
UTF-8文字列の長さ
UTF-8エンコードされた文字列内の文字数をカウントする方法は、最初のバイトから文字列を走査し、UTF-8のリーディングバイト(先頭バイト)のみをカウントすることです。リーディングバイトは、次のようなビットパターンを持っています。
0xxxxxxx: 1バイト文字(ASCII互換)
110xxxxx: 2バイト文字のリーディングバイト
1110xxxx: 3バイト文字のリーディングバイト
11110xxx: 4バイト文字のリーディングバイト
以下のC++コードは、UTF-8エンコードされたstd::string内の文字数をカウントする関数の例です。
#include <iostream>
#include <string>
size_t utf8_strlen(const std::string& utf8_str) {
size_t count = 0;
for (unsigned char c : utf8_str) {
if ((c & 0xC0) != 0x80) { // Check if the byte is not a UTF-8 trailing byte (10xxxxxx)
++count;
}
}
return count;
}
int main() {
std::string utf8_str = u8"こんにちは、世界!";
size_t count = utf8_strlen(utf8_str);
std::cout << "The string has " << count << " characters." << std::endl;
return 0;
}
このコードは、UTF-8文字列を走査し、UTF-8のリーディングバイトをカウントして文字数を計算します。ただし、この方法は無効なUTF-8シーケンスに対してはエラーチェックを行いません。
より堅牢な方法として、std::codecvt_utf8や第三者製のUnicode対応ライブラリ(Boost.Text、ICUなど)を使用することが推奨されます。これらのライブラリは、エラーチェックや他のUnicode関連の操作を提供します
C++17以降では、std::codecvt_utf8を使用せず、代わりにUnicode対応のサードパーティライブラリ(Boost.Text、ICUなど)を利用することが推奨されます。
UTF-8の文字列のバイト数
UTF-8エンコードされた文字列のバイト数を調べるには、std::stringを使用できます。std::stringのsize()メソッドを使って、文字列内のバイト数を取得できます。UTF-8では、1文字が1バイトから4バイトまでの可変長で表現されるため、std::string::size()で直接バイト数が得られます。
#include <iostream>
#include <string>
int main() {
std::string utf8_str = u8"こんにちは、世界!";
// 文字列のバイト数を取得
std::size_t byte_count = utf8_str.size();
std::cout << "バイト数: " << byte_count << std::endl;
return 0;
}
UTF-16文字列の長さ
C++の標準ライブラリにあるstd::wstringやstd::u16stringを使用するか、C言語の標準ライブラリのwcslen関数を使用できます。
std::wstringおよびstd::u16stringのlength()またはsize()メンバ関数は、文字列の長さ(文字数)を返します。バイト数ではありません。
例えば、次のようにstd::wstringを使用してUTF-16文字列の長さを取得できます。
#include <iostream>
#include <string>
int main() {
std::wstring str = L"こんにちは";
std::size_t length = str.length(); // または str.size();
std::wcout << L"文字数: " << length << std::endl;
return 0;
}
C言語のwcslen関数も同様に、文字列の長さ(文字数)を返します。バイト数ではありません。
#include <locale.h>
#include <wchar.h>
#include <stdio.h>
int main() {
setlocale(LC_ALL, ""); // ロケールを設定
wchar_t str[] = L"こんにちは";
size_t length = wcslen(str);
wprintf(L"文字数: %zu\n", length);
return 0;
}
注意すべき点は、これらの関数は基本多言語面(BMP)の文字だけでなく、サロゲートペアを含む文字も1文字としてカウントします。したがって、サロゲートペアを正確にカウントしたい場合は、独自の関数を実装するか、サードパーティのライブラリを使用する必要があります。
UTF-16文字列のバイト数
UTF-16文字列の実際のバイト数をカウントするには、文字列を走査してサロゲートペアを考慮しながらカウントする必要があります。以下に、UTF-16文字列のバイト数をカウントするC++のコード例を示します
#include <iostream>
#include <string>
size_t utf16_byte_count(const std::wstring& str) {
size_t byte_count = 0;
for (size_t i = 0; i < str.length(); ++i) {
wchar_t ch = str[i];
// サロゲートペアの場合
if (ch >= 0xD800 && ch <= 0xDBFF && (i + 1) < str.length() && str[i + 1] >= 0xDC00 && str[i + 1] <= 0xDFFF) {
byte_count += 4; // サロゲートペアは4バイト
i++; // サロゲートペアの次の文字をスキップ
} else {
byte_count += 2; // 通常のUTF-16文字は2バイト
}
}
return byte_count;
}
int main() {
std::wstring str = L"こんにちは😀";
size_t byte_count = utf16_byte_count(str);
std::wcout << L"バイト数: " << byte_count << std::endl;
return 0;
}
このコードでは、utf16_byte_count関数を使ってUTF-16文字列のバイト数をカウントしています。文字列を走査し、サロゲートペアを検出した場合は、バイト数に4バイトを加算し、次の文字をスキップします。サロゲートペアでない通常のUTF-16文字は、バイト数に2バイトを加算します。この方法で、UTF-16文字列の実際のバイト数をカウントできます。
コマンドラインで文字化け無く表示する
まずはロケールについてstd::locale
ワイド文字やユニコードを表示する際にstd::cout std::woutなどの文字コードにロケールのセットが必要になる。
注意点
_wsetlocale およびsetlocale、はスレッドセーブでなないため
現代のC++プログラミングでは、std::localeを使用することが推奨されています。std::localeは、setlocaleと比較して以下のような利点があります。
スレッドセーフ: std::localeは、オブジェクト指向でスレッドセーフな方法でロケールを扱うことができます。これに対して、setlocaleはグローバルな状態を変更するため、マルチスレッド環境で問題が発生する可能性があります。
柔軟性: std::localeは、標準ライブラリのロケール対応関数と組み合わせて使用できます。また、独自のロケールに対応したオブジェクトを作成して、それをstd::localeに組み込むこともできます。
ただし、std::localeを使用する際には、標準ライブラリのロケール対応関数やクラスを適切に使用する必要があります。例えば、ファイルI/Oやフォーマットされた入出力などのロケール対応機能を利用する場合、std::iostreamやstd::fstreamクラスのメンバ関数を使ってロケールを設定する必要があります。
以下は、std::localeを使用してロケールを設定し、フォーマットされた出力を行う例です。
#include <iostream>
#include <iomanip>
#include <locale>
int main() {
std::locale user_locale(""); // ユーザーの環境設定に従ったデフォルトロケールを作成
std::cout.imbue(user_locale); // std::coutにロケールを設定
double number = 1234567.89;
std::cout << "Formatted number: " << std::fixed << std::setprecision(2) << number << std::endl;
return 0;
}
このコードは、デフォルトのロケールに従って、小数点以下2桁までの浮動小数点数を表示します。例えば、米国のロケールでは "1,234,567.89" と表示されます。
UTF-8 コードのみで対応する方法
コード内でコンソールの出力コードページを変更することができます。以下のC++コードは、SetConsoleOutputCP関数を使用して、Windowsコンソールの出力コードページをUTF-8(65001)に設定します。これにより、UTF-8文字列が正しく表示されるようになります。
#include <iostream>
#include <string>
#include <Windows.h>
int main() {
// Set the console output code page to UTF-8
SetConsoleOutputCP(CP_UTF8);
std::string utf8_str = u8"こんにちは、世界!";
std::cout << utf8_str << std::endl;
return 0;
}
ただし、この方法でもコマンドプロンプトのフォントがUnicode文字をサポートするフォントであることが前提となります。前述のように「Consolas」や「Lucida Console」などのフォントを選択してください。
この方法を使用することで、コード内でUTF-8の出力コードページを設定し、chcpコマンドを使わずにUTF-8文字列を正しく表示できます。ただし、この設定はプログラムの実行中にのみ適用され、プログラムが終了すると元のコードページに戻ります。
UTF-8 シェルの設定を変える方法
Windowsのコマンドプロンプト(cmd)でUTF-8文字列を正しく表示するには、以下の手順を実行します。
1.コマンドプロンプトの出力コードページをUTF-8に設定します。コマンド プロンプトを開き、以下のコマンドを入力して実行します。
chcp 65001
2.コマンドプロンプトのフォントを、Unicode文字をサポートするフォントに変更します。コマンドプロンプトのウィンドウのタイトルバーを右クリックし、「プロパティ」を選択し、フォントタブで適切なフォントを選択します。例えば、「Consolas」や「Lucida Console」などのフォントがUnicode文字をサポートしています。
3.C++プログラムで、UTF-8文字列を表示するために、標準出力に対応するC++ストリームオブジェクト(std::cout)を使用します。
#include <iostream>
#include <string>
int main() {
std::string utf8_str = u8"こんにちは、世界!";
std::cout << utf8_str << std::endl;
return 0;
}
4.プログラムをコンパイルして実行します。プログラムの実行結果がコマンドプロンプトに表示され、UTF-8文字列が正しく表示されます。
注意: コマンドプロンプトでUTF-8文字列を表示する場合、一部の古いWindowsバージョンや環境では、文字化けや表示に関する問題が発生することがあります。このような場合は、PowerShellを使用することを検討してください。PowerShellでは、UTF-8文字列の表示がより簡単に実現できます。
UTF-16: その1(Windows限定)
_wsetlocale(LC_ALL, L"")を使用してロケールを設定した後、std::wcoutを使ってUTF-16文字列を正しくコマンドプロンプトに出力することができます。以下に例を示します:
#include <iostream>
#include <string>
#include <locale.h>
int main() {
// ロケールを設定
std::locale user_locale(""); // ユーザーの環境設定に従ったデフォルトロケールを作成
std::wcout.imbue(user_locale); // std::wcoutにロケールを設定
// UTF-16文字列を定義
std::wstring utf16_str = L"こんにちは、世界!";
// 文字列を出力
std::wcout << utf16_str << std::endl;
return 0;
}
UTF-16: その2 (Windows限定)
Windowsのコマンドプロンプトは、通常UTF-16のワイド文字(wchar_t)をサポートしているため、WriteConsoleW関数を使用して文字化けなしでUTF-16文字列を出力できます。以下に例を示します:
#include <iostream>
#include <string>
#include <Windows.h>
int main() {
// UTF-16文字列を定義
std::wstring utf16_str = L"こんにちは、世界!";
// コンソールのハンドルを取得
HANDLE console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
// 文字列を出力
DWORD written;
WriteConsoleW(console_handle, utf16_str.c_str(), utf16_str.length(), &written, nullptr);
return 0;
}
UTF-16: その3 (LinuxとWindows)
Linuxのシェルでは、通常UTF-8エンコーディングがサポートされています。そのため、UTF-16文字列を出力するには、まずUTF-8に変換する必要があります。以下に、UTF-16文字列をUTF-8に変換してLinuxのシェルに出力する例を示します。この例ではC++11以降で利用可能なstd::wstring_convertとstd::codecvt_utf8_utf16を使用しています。
Windowsでもchcp 65001でUTF-8の設定にしていれば以下のコードで対応可能です。
#include <iostream>
#include <string>
#include <locale>
#include <codecvt>
int main() {
// UTF-16文字列を定義
std::u16string utf16_str = u"こんにちは、世界!";
// UTF-16からUTF-8に変換
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
std::string utf8_str = convert.to_bytes(utf16_str);
// 文字列を出力
std::cout << utf8_str << std::endl;
return 0;
}
このコードでは、std::u16stringを使用してUTF-16文字列を定義し、std::wstring_convertおよびstd::codecvt_utf8_utf16を使用してUTF-8に変換しています。変換後のUTF-8文字列はstd::stringに格納され、std::coutを使ってシェルに出力されます。これにより、LinuxのシェルでUTF-16文字列が正しく表示されます。
相互変換
Shift-JISからUTF-8
C++でShift-JISの文字コードからUTF-8への変換を行うには、std::wstring_convertとstd::codecvt_bynameを使います。以下に、Shift-JISからUTF-8への変換を行う例を示します。
#include <iostream>
#include <string>
#include <locale>
#include <codecvt>
int main() {
// Shift-JIS文字列を定義
std::string shift_jis_str = "こんにちは、世界!"; // ここでShift-JISエンコーディングで書かれた文字列を入力します。
// Shift-JISからUTF-16に変換
std::wstring_convert<std::codecvt_byname<wchar_t, char, std::mbstate_t>, wchar_t> convert_shift_jis_to_utf16(new std::codecvt_byname<wchar_t, char, std::mbstate_t>("Japanese"));
std::wstring utf16_str = convert_shift_jis_to_utf16.from_bytes(shift_jis_str);
// UTF-16からUTF-8に変換
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> convert_utf16_to_utf8;
std::string utf8_str = convert_utf16_to_utf8.to_bytes(utf16_str);
// 文字列を出力
std::cout << utf8_str << std::endl;
return 0;
}
このコードでは、std::wstring_convertとstd::codecvt_bynameを使用して、Shift-JIS文字列を一度UTF-16に変換し、次にstd::wstring_convertとstd::codecvt_utf8を使用して、UTF-16からUTF-8に変換しています。変換後のUTF-8文字列はstd::stringに格納され、std::coutを使って出力されます。
この方法でShift-JISの文字コードからUTF-8への変換が行えます。ただし、std::codecvt_bynameはC++17で非推奨とされ、C++20では削除されています。C++17以降では、他のライブラリ(例:ICU)を使うことを検討してください。
UTF-8からShift-JIS
C++でUTF-8の文字コードからShift-JISへの変換を行うには、std::wstring_convertとstd::codecvt_bynameを使います。以下に、UTF-8からShift-JISへの変換を行う例を示します。
#include <iostream>
#include <string>
#include <locale>
#include <codecvt>
int main() {
// UTF-8文字列を定義
std::string utf8_str = u8"こんにちは、世界!";
// UTF-8からUTF-16に変換
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> convert_utf8_to_utf16;
std::wstring utf16_str = convert_utf8_to_utf16.from_bytes(utf8_str);
// UTF-16からShift-JISに変換
std::wstring_convert<std::codecvt_byname<wchar_t, char, std::mbstate_t>, wchar_t> convert_utf16_to_shift_jis(new std::codecvt_byname<wchar_t, char, std::mbstate_t>("Japanese"));
std::string shift_jis_str = convert_utf16_to_shift_jis.to_bytes(utf16_str);
// 文字列を出力
std::cout << "Shift-JIS encoded string: " << std::endl;
std::cout << shift_jis_str << std::endl;
return 0;
}
このコードでは、std::wstring_convertとstd::codecvt_utf8を使用して、UTF-8文字列を一度UTF-16に変換し、次にstd::wstring_convertとstd::codecvt_bynameを使用して、UTF-16からShift-JISに変換しています。変換後のShift-JIS文字列はstd::stringに格納され、std::coutを使って出力されます。
この方法でUTF-8の文字コードからShift-JISへの変換が行えます。ただし、std::codecvt_bynameはC++17で非推奨とされ、C++20では削除されています。C++17以降では、他のライブラリ(例:ICU)を使うことを検討してください。
UTF-8からUTF-16
C++でUTF-8からUTF-16への変換を行うには、std::wstring_convertとstd::codecvt_utf8を使用します。以下に、UTF-8からUTF-16への変換を行う例を示します。
#include <iostream>
#include <string>
#include <locale>
#include <codecvt>
int main() {
// UTF-8文字列を定義
std::string utf8_str = u8"こんにちは、世界!";
// UTF-8からUTF-16に変換
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> convert_utf8_to_utf16;
std::wstring utf16_str = convert_utf8_to_utf16.from_bytes(utf8_str);
// 文字列を出力
std::wcout << L"UTF-16 encoded string: " << std::endl;
std::wcout << utf16_str << std::endl;
return 0;
}
このコードでは、std::wstring_convertとstd::codecvt_utf8を使用して、UTF-8文字列をUTF-16に変換しています。変換後のUTF-16文字列はstd::wstringに格納され、std::wcoutを使って出力されます。
この方法でUTF-8からUTF-16への変換が行えます。
UTF-16からUTF-8
C++でUTF-16からUTF-8への変換を行うには、std::wstring_convertとstd::codecvt_utf8を使用します。以下に、UTF-16からUTF-8への変換を行う例を示します。
#include <iostream>
#include <string>
#include <locale>
#include <codecvt>
int main() {
// UTF-16文字列を定義
std::wstring utf16_str = L"こんにちは、世界!";
// UTF-16からUTF-8に変換
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> convert_utf16_to_utf8;
std::string utf8_str = convert_utf16_to_utf8.to_bytes(utf16_str);
// 文字列を出力
std::cout << "UTF-8 encoded string: " << std::endl;
std::cout << utf8_str << std::endl;
return 0;
}
このコードでは、std::wstring_convertとstd::codecvt_utf8を使用して、UTF-16文字列をUTF-8に変換しています。変換後のUTF-8文字列はstd::stringに格納され、std::coutを使って出力されます。
この方法でUTF-16からUTF-8への変換が行えます。
UTF-16からUTF-32
C++でUTF-16からUTF-32への変換を行うには、std::wstring_convertとstd::codecvt_utf16を使用します。以下に、UTF-16からUTF-32への変換を行う例を示します。
#include <iostream>
#include <string>
#include <locale>
#include <codecvt>
int main() {
// UTF-16文字列を定義
std::u16string utf16_str = u"こんにちは、世界!";
// UTF-16からUTF-32に変換
std::wstring_convert<std::codecvt_utf16<char32_t, 0x10ffff, std::little_endian>, char32_t> convert_utf16_to_utf32;
std::u32string utf32_str = convert_utf16_to_utf32.from_bytes(reinterpret_cast<const char*>(utf16_str.data()), reinterpret_cast<const char*>(utf16_str.data() + utf16_str.size()));
// 文字列を出力
std::u32string utf32_display_str = utf32_str + U'\0';
std::cout << "UTF-32 encoded string: " << std::endl;
std::cout << reinterpret_cast<const char*>(utf32_display_str.data()) << std::endl;
return 0;
}
このコードでは、std::wstring_convertとstd::codecvt_utf16を使用して、UTF-16文字列をUTF-32に変換しています。変換後のUTF-32文字列はstd::u32stringに格納され、std::coutを使って出力されます。
この方法でUTF-16からUTF-32への変換が行えます。ただし、std::codecvt_utf16はC++17で非推奨とされ、C++20では削除されています。C++17以降では、他のライブラリ(例:ICU)を使うことを検討してください。
UTF-32からUTF-16
C++でUTF-32からUTF-16への変換を行うには、std::wstring_convertとstd::codecvt_utf16を使用します。以下に、UTF-32からUTF-16への変換を行う例を示します。
#include <iostream>
#include <string>
#include <locale>
#include <codecvt>
int main() {
// UTF-32文字列を定義
std::u32string utf32_str = U"こんにちは、世界!";
// UTF-32からUTF-16に変換
std::wstring_convert<std::codecvt_utf16<char32_t, 0x10ffff, std::little_endian>, char32_t> convert_utf32_to_utf16;
std::string utf16_bytes = convert_utf32_to_utf16.to_bytes(utf32_str);
std::u16string utf16_str(reinterpret_cast<const char16_t*>(utf16_bytes.data()), utf16_bytes.size() / sizeof(char16_t));
// 文字列を出力
std::u16string utf16_display_str = utf16_str + u'\0';
std::wcout << L"UTF-16 encoded string: " << std::endl;
std::wcout << reinterpret_cast<const wchar_t*>(utf16_display_str.data()) << std::endl;
return 0;
}
このコードでは、std::wstring_convertとstd::codecvt_utf16を使用して、UTF-32文字列をUTF-16に変換しています。変換後のUTF-16文字列はstd::u16stringに格納され、std::wcoutを使って出力されます。
この方法でUTF-32からUTF-16への変換が行えます。ただし、std::codecvt_utf16はC++17で非推奨とされ、C++20では削除されています。C++17以降では、他のライブラリ(例:ICU)を使うことを検討してください。
std::wstring から std::u16string
std::wstring は、プラットフォーム固有のワイド文字エンコーディングを使用するための型です。std::wstring は、wchar_t 型の文字を格納しますが、wchar_t のサイズはプラットフォームやコンパイラによって異なります。これは、Windows では通常 16 ビットであり、UTF-16 を表現できますが、Unix ベースのシステムでは 32 ビットであり、UTF-32 を表現できます。
従って、std::u16string と std::wstring を同じと考えることは、プラットフォーム固有の違いにより問題が生じる可能性があるため、適切ではありません。
以下のコードはwchar_t が UTF-16 エンコーディングのプラットフォーム(主に Windows)でのみ適切に動作します。
#include <string>
#include <locale>
#include <codecvt>
int main() {
std::wstring wstr = L"こんにちは、世界!";
std::wstring_convert<std::codecvt_utf16<wchar_t, 0x10ffff, std::little_endian>, wchar_t> convert;
std::u16string u16str = convert.from_bytes(reinterpret_cast<const char*>(wstr.data()), reinterpret_cast<const char*>(wstr.data() + wstr.size()));
}
ただし、std::wstring_convert と std::codecvt は C++17 で非推奨になっており、C++20 では削除されています。したがって、C++17 よりも新しいバージョンを使用している場合は、他の変換方法(例えば、ICU ライブラリを使用する)を検討することをお勧めします。
次節のICUを使ったコードをお勧めします。
相互変換 ICUバージョン
Shift-JISからUTF-8 (ICU)
ICU (International Components for Unicode) ライブラリを使用して、Shift-JISからUTF-8に変換する方法について説明します。まず、ICUライブラリをインストールしておく必要があります。
以下に、ICUを使ってShift-JISからUTF-8への変換を行うC++コード例を示します。
#include <iostream>
#include <string>
#include <unicode/ucnv.h>
std::string ShiftJisToUtf8(const std::string& input) {
UErrorCode error_code = U_ZERO_ERROR;
UConverter* sjis_converter = ucnv_open("Shift-JIS", &error_code);
if (U_FAILURE(error_code)) {
std::cerr << "Failed to create Shift-JIS converter" << std::endl;
return "";
}
int32_t utf8_len = ucnv_toAlgorithmic(UCNV_UTF8, sjis_converter, nullptr, 0, input.c_str(), input.length(), &error_code);
if (error_code != U_BUFFER_OVERFLOW_ERROR) {
std::cerr << "Failed to estimate buffer size for UTF-8 conversion" << std::endl;
ucnv_close(sjis_converter);
return "";
}
error_code = U_ZERO_ERROR;
std::string utf8_str(utf8_len, '\0');
ucnv_toAlgorithmic(UCNV_UTF8, sjis_converter, &utf8_str[0], utf8_len, input.c_str(), input.length(), &error_code);
ucnv_close(sjis_converter);
if (U_FAILURE(error_code)) {
std::cerr << "Failed to convert Shift-JIS to UTF-8" << std::endl;
return "";
}
return utf8_str;
}
int main() {
std::string sjis_str = "こんにちは、世界!(Shift-JIS)"; // Shift-JISでエンコードされた文字列を用意してください。
std::string utf8_str = ShiftJisToUtf8(sjis_str);
std::cout << "UTF-8 encoded string: " << utf8_str << std::endl;
return 0;
}
このコードでは、ShiftJisToUtf8関数を使ってShift-JISエンコードされた文字列をUTF-8に変換しています。ucnv_open関数でShift-JISのコンバーターを開き、ucnv_toAlgorithmic関数で変換を実行しています。
注意: この例では、Shift-JISでエンコードされた文字列を直接コード内に記述していますが、実際にはShift-JISでエンコードされたファイルやデータを読み込む際に使用してください。
ICUを使うことで、Shift-JISからUTF-8への変換が容易に行えます。他の文字コードの変換も、同様の方法で実行できます。ただし、ICUライブラリをプロジェクトにリンクする必要があることに注意してください。
UTF-8からShift-JIS (ICU)
ICU (International Components for Unicode) ライブラリを使用して、UTF-8からShift-JISに変換する方法について説明します。まず、ICUライブラリをインストールしておく必要があります。
以下に、ICUを使ってUTF-8からShift-JISへの変換を行うC++コード例を示します。
#include <iostream>
#include <string>
#include <unicode/ucnv.h>
std::string Utf8ToShiftJis(const std::string& input) {
UErrorCode error_code = U_ZERO_ERROR;
UConverter* sjis_converter = ucnv_open("Shift-JIS", &error_code);
if (U_FAILURE(error_code)) {
std::cerr << "Failed to create Shift-JIS converter" << std::endl;
return "";
}
int32_t sjis_len = ucnv_fromAlgorithmic(sjis_converter, UCNV_UTF8, nullptr, 0, input.c_str(), input.length(), &error_code);
if (error_code != U_BUFFER_OVERFLOW_ERROR) {
std::cerr << "Failed to estimate buffer size for Shift-JIS conversion" << std::endl;
ucnv_close(sjis_converter);
return "";
}
error_code = U_ZERO_ERROR;
std::string sjis_str(sjis_len, '\0');
ucnv_fromAlgorithmic(sjis_converter, UCNV_UTF8, &sjis_str[0], sjis_len, input.c_str(), input.length(), &error_code);
ucnv_close(sjis_converter);
if (U_FAILURE(error_code)) {
std::cerr << "Failed to convert UTF-8 to Shift-JIS" << std::endl;
return "";
}
return sjis_str;
}
int main() {
std::string utf8_str = u8"こんにちは、世界!(UTF-8)";
std::string sjis_str = Utf8ToShiftJis(utf8_str);
// Shift-JISでエンコードされた文字列を扱う処理
// この例では、Shift-JIS文字列をコンソールに出力していますが、実際には適切なShift-JIS対応の処理を行ってください。
return 0;
}
このコードでは、Utf8ToShiftJis関数を使ってUTF-8エンコードされた文字列をShift-JISに変換しています。ucnv_open関数でShift-JISのコンバーターを開き、ucnv_fromAlgorithmic関数で変換を実行しています。
ICUを使うことで、UTF-8からShift-JISへの変換が容易に行えます。他の文字コードの変換も、同様の方法で実行できます。ただし、ICUライブラリをプロジェクトにリンクする必要があることに注意してください。
UTF-8からUTF-16 (ICU)
ICU (International Components for Unicode) ライブラリを使用して、UTF-8からUTF-16に変換する方法について説明します。まず、ICUライブラリをインストールしておく必要があります。
以下に、ICUを使ってUTF-8からUTF-16への変換を行うC++コード例を示します。
#include <iostream>
#include <string>
#include <vector>
#include <unicode/ucnv.h>
#include <unicode/ustring.h>
std::u16string Utf8ToUtf16(const std::string& input) {
UErrorCode error_code = U_ZERO_ERROR;
int32_t utf16_len = 0;
u_strFromUTF8(nullptr, 0, &utf16_len, input.c_str(), input.length(), &error_code);
if (error_code != U_BUFFER_OVERFLOW_ERROR) {
std::cerr << "Failed to estimate buffer size for UTF-16 conversion" << std::endl;
return u"";
}
error_code = U_ZERO_ERROR;
std::u16string utf16_str(utf16_len, u'\0');
u_strFromUTF8(&utf16_str[0], utf16_len + 1, nullptr, input.c_str(), input.length(), &error_code);
if (U_FAILURE(error_code)) {
std::cerr << "Failed to convert UTF-8 to UTF-16" << std::endl;
return u"";
}
return utf16_str;
}
int main() {
std::string utf8_str = u8"こんにちは、世界!(UTF-8)";
std::u16string utf16_str = Utf8ToUtf16(utf8_str);
// UTF-16でエンコードされた文字列を扱う処理
// この例では、UTF-16文字列をそのまま保持していますが、実際には適切なUTF-16対応の処理を行ってください。
return 0;
}
このコードでは、Utf8ToUtf16関数を使ってUTF-8エンコードされた文字列をUTF-16に変換しています。u_strFromUTF8関数で変換を実行しています。
ICUを使うことで、UTF-8からUTF-16への変換が容易に行えます。他の文字コードの変換も、同様の方法で実行できます。ただし、ICUライブラリをプロジェクトにリンクする必要があることに注意してください。
UTF-16からUTF-8 (ICU)
ICU (International Components for Unicode) ライブラリを使用して、UTF-16からUTF-8に変換する方法について説明します。まず、ICUライブラリをインストールしておく必要があります。
以下に、ICUを使ってUTF-16からUTF-8への変換を行うC++コード例を示します。
#include <iostream>
#include <string>
#include <vector>
#include <unicode/ucnv.h>
#include <unicode/ustring.h>
std::string Utf16ToUtf8(const std::u16string& input) {
UErrorCode error_code = U_ZERO_ERROR;
int32_t utf8_len = 0;
u_strToUTF8(nullptr, 0, &utf8_len, input.c_str(), input.length(), &error_code);
if (error_code != U_BUFFER_OVERFLOW_ERROR) {
std::cerr << "Failed to estimate buffer size for UTF-8 conversion" << std::endl;
return "";
}
error_code = U_ZERO_ERROR;
std::string utf8_str(utf8_len, '\0');
u_strToUTF8(&utf8_str[0], utf8_len + 1, nullptr, input.c_str(), input.length(), &error_code);
if (U_FAILURE(error_code)) {
std::cerr << "Failed to convert UTF-16 to UTF-8" << std::endl;
return "";
}
return utf8_str;
}
int main() {
std::u16string utf16_str = u"こんにちは、世界!(UTF-16)";
std::string utf8_str = Utf16ToUtf8(utf16_str);
// UTF-8でエンコードされた文字列を扱う処理
std::cout << "Converted string: " << utf8_str << std::endl;
return 0;
}
このコードでは、Utf16ToUtf8関数を使ってUTF-16エンコードされた文字列をUTF-8に変換しています。u_strToUTF8関数で変換を実行しています。
ICUを使うことで、UTF-16からUTF-8への変換が容易に行えます。他の文字コードの変換も、同様の方法で実行できます。ただし、ICUライブラリをプロジェクトにリンクする必要があることに注意してください。
UTF-16からUTF-32 (ICU)
ICU (International Components for Unicode) ライブラリを使用して、UTF-16からUTF-32に変換する方法について説明します。まず、ICUライブラリをインストールしておく必要があります。
以下に、ICUを使ってUTF-16からUTF-32への変換を行うC++コード例を示します。
#include <iostream>
#include <string>
#include <unicode/ucnv.h>
#include <unicode/ustring.h>
std::u32string Utf16ToUtf32(const std::u16string& input) {
UErrorCode error_code = U_ZERO_ERROR;
int32_t utf32_len = 0;
u_strToUTF32(nullptr, 0, &utf32_len, input.c_str(), input.length(), &error_code);
if (error_code != U_BUFFER_OVERFLOW_ERROR) {
std::cerr << "Failed to estimate buffer size for UTF-32 conversion" << std::endl;
return U"";
}
error_code = U_ZERO_ERROR;
std::u32string utf32_str(utf32_len, U'\0');
u_strToUTF32(&utf32_str[0], utf32_len + 1, nullptr, input.c_str(), input.length(), &error_code);
if (U_FAILURE(error_code)) {
std::cerr << "Failed to convert UTF-16 to UTF-32" << std::endl;
return U"";
}
return utf32_str;
}
int main() {
std::u16string utf16_str = u"こんにちは、世界!(UTF-16)";
std::u32string utf32_str = Utf16ToUtf32(utf16_str);
// UTF-32でエンコードされた文字列を扱う処理
// 例として、UTF-32の文字数を出力
std::cout << "Number of characters in UTF-32 string: " << utf32_str.length() << std::endl;
return 0;
}
このコードでは、Utf16ToUtf32関数を使ってUTF-16エンコードされた文字列をUTF-32に変換しています。u_strToUTF32関数で変換を実行しています。
ICUを使うことで、UTF-16からUTF-32への変換が容易に行えます。他の文字コードの変換も、同様の方法で実行できます。ただし、ICUライブラリをプロジェクトにリンクする必要があることに注意してください。
UTF-32からUTF16 (ICU)
ICU (International Components for Unicode) ライブラリを使用して、UTF-32からUTF-16に変換する方法について説明します。まず、ICUライブラリをインストールしておく必要があります。
以下に、ICUを使ってUTF-32からUTF-16への変換を行うC++コード例を示します。
#include <iostream>
#include <string>
#include <unicode/ucnv.h>
#include <unicode/ustring.h>
std::u16string Utf32ToUtf16(const std::u32string& input) {
UErrorCode error_code = U_ZERO_ERROR;
int32_t utf16_len = 0;
u_strToUTF16(nullptr, 0, &utf16_len, input.c_str(), input.length(), &error_code);
if (error_code != U_BUFFER_OVERFLOW_ERROR) {
std::cerr << "Failed to estimate buffer size for UTF-16 conversion" << std::endl;
return u"";
}
error_code = U_ZERO_ERROR;
std::u16string utf16_str(utf16_len, u'\0');
u_strToUTF16(&utf16_str[0], utf16_len + 1, nullptr, input.c_str(), input.length(), &error_code);
if (U_FAILURE(error_code)) {
std::cerr << "Failed to convert UTF-32 to UTF-16" << std::endl;
return u"";
}
return utf16_str;
}
int main() {
std::u32string utf32_str = U"こんにちは、世界!(UTF-32)";
std::u16string utf16_str = Utf32ToUtf16(utf32_str);
// UTF-16でエンコードされた文字列を扱う処理
// 例として、UTF-16の文字数を出力
std::cout << "Number of characters in UTF-16 string: " << utf16_str.length() << std::endl;
return 0;
}
このコードでは、Utf32ToUtf16関数を使ってUTF-32エンコードされた文字列をUTF-16に変換しています。u_strToUTF16関数で変換を実行しています。
ICUを使うことで、UTF-32からUTF-16への変換が容易に行えます。他の文字コードの変換も、同様の方法で実行できます。ただし、ICUライブラリをプロジェクトにリンクする必要があることに注意してください。
std::wstring から std::u16string (ICU)
以下は、ICU ライブラリを使用して std::wstring を std::u16string に変換する方法です。このコードはプラットフォームに依存せず、wchar_t のエンコーディングが UTF-16 であることを前提としていません。
#include <string>
#include <unicode/ucnv.h>
std::u16string wstring_to_u16string(const std::wstring& wstr) {
UErrorCode status = U_ZERO_ERROR;
UConverter *conv = ucnv_openU("UTF-32", &status);
if (U_FAILURE(status)) {
throw std::runtime_error("Failed to open ICU converter");
}
int32_t src_len = static_cast<int32_t>(wstr.size());
const UChar *src = reinterpret_cast<const UChar *>(wstr.data());
int32_t dest_len = ucnv_toUChars(conv, nullptr, 0, src, src_len, &status);
if (status != U_BUFFER_OVERFLOW_ERROR) {
ucnv_close(conv);
throw std::runtime_error("Failed to calculate UTF-16 buffer size");
}
status = U_ZERO_ERROR;
std::u16string u16str(dest_len, '\0');
ucnv_toUChars(conv, u16str.data(), dest_len, src, src_len, &status);
ucnv_close(conv);
if (U_FAILURE(status)) {
throw std::runtime_error("Failed to convert from std::wstring to std::u16string");
}
return u16str;
}
int main() {
std::wstring wstr = L"こんにちは、世界!";
std::u16string u16str = wstring_to_u16string(wstr);
}
このコードでは、ICU の UConverter を使用して std::wstring を std::u16string に変換しています。wstring_to_u16string 関数を使用して、変換を行うことができます。注意してください。このコードは wchar_t のエンコーディングが UTF-32 であることを前提としています。異なるエンコーディングが使用されている場合は、適切に変換するために ucnv_openU() の第一引数を修正する必要があります。
文字列操作
文字列の中の文字列を探す
C++でUTF-8の文字列の中から特定のキーワードが含まれているかどうかチェックする方法について説明します。この例では、std::stringを使ってUTF-8文字列を扱います。std::string::find()関数を使用して、指定されたキーワードが見つかるかどうかをチェックできます。
以下に、UTF-8文字列の中に特定のキーワードが含まれているかをチェックするC++コード例を示します。
#include <iostream>
#include <string>
bool ContainsKeyword(const std::string& input, const std::string& keyword) {
return input.find(keyword) != std::string::npos;
}
int main() {
std::string input = u8"こんにちは、世界!";
std::string keyword1 = u8"世界";
std::string keyword2 = u8"さようなら";
bool contains_keyword1 = ContainsKeyword(input, keyword1);
bool contains_keyword2 = ContainsKeyword(input, keyword2);
std::cout << "Input contains '" << keyword1 << "': " << std::boolalpha << contains_keyword1 << std::endl;
std::cout << "Input contains '" << keyword2 << "': " << std::boolalpha << contains_keyword2 << std::endl;
return 0;
}
このコードでは、ContainsKeyword関数を使って、入力文字列inputにキーワードkeyword1とkeyword2が含まれているかどうかをチェックしています。std::string::find()関数がキーワードの位置を見つけられなかった場合、std::string::nposが返されます。この値を使って、キーワードが見つかったかどうかを判断できます。
なおstd::stringをstd::wstringにするとwchar_t
u16stringにするとUTF-16
u32stringにするとUTF-32として使えます。
文字列と文字列を連結する
UTF-8の文字列を連結するには、C++のstd::stringを使用できます。operator+を使って2つの文字列を簡単に連結できます。また、operator+=を使って、1つの文字列に別の文字列を追加することもできます。
以下に、UTF-8の文字列を連結するC++コード例を示します。
#include <iostream>
#include <string>
int main() {
std::string str1 = "こんにちは、";
std::string str2 = "世界!";
// Using operator+ to concatenate two strings
std::string combined = str1 + str2;
std::cout << "Combined string: " << combined << std::endl;
// Using operator+= to append one string to another
str1 += str2;
std::cout << "Appended string: " << str1 << std::endl;
return 0;
}
このコードでは、str1とstr2という2つのUTF-8文字列があります。operator+を使って、両方の文字列を連結し、combinedという新しい文字列に結果を格納しています。次に、operator+=を使って、str1にstr2を追加し、結果をstr1に格納しています。どちらの方法でも、文字列を連結できます。
なおstd::stringをstd::wstringにするとUTF-16
u32stringにするとUTF-32として使えます。
UTF-8 文字列の一部を削除する
UTF-8の文字列でマルチバイト文字を考慮してn文字目以降を削除するには、以下のようなコードを使用できます。
#include <iostream>
#include <string>
int main() {
std::string str = u8"こんにちは、世界!";
int n = 5; // 文字数を指定
int byte_position = 0;
int char_count = 0;
while (byte_position < str.size() && char_count < n) {
if ((str[byte_position] & 0xC0) != 0x80) {
// マルチバイト文字の先頭バイトか単一バイト文字の場合
char_count++;
}
byte_position++;
}
// n文字以降を削除する
str.erase(byte_position);
std::cout << "Truncated string: " << str << std::endl;
return 0;
}
このコードでは、バイト単位で文字列を走査し、マルチバイト文字や単一バイト文字を正しくカウントしています。n文字目に到達したときのバイト位置を取得し、その位置でstr.erase(byte_position)を呼び出しています。これにより、UTF-8文字列から正しくn文字目以降を削除できます。
UTF-16 文字列の一部を削除する
パス文字列からファイル名を取り出す
パス文字列からパスだけ取り出す
文字列操作 ICUバージョン
UTF-8 文字列中の文字列を探す (ICU)
ICU ライブラリを使用して UTF-8 の文字列の中から特定のキーワードが含まれているかどうかをチェックする方法を以下に示します。まず、ICU ライブラリをインストールし、適切にリンクしてください。
#include <iostream>
#include <string>
#include <unicode/unistr.h> // ICU の UnicodeString を使うために必要
#include <unicode/utypes.h> // ICU の UErrorCode を使うために必要
int main() {
std::string utf8_input = "こんにちは、世界!";
std::string utf8_keyword = "世界";
// UTF-8 文字列を ICU の UnicodeString に変換
icu::UnicodeString input_ustring = icu::UnicodeString::fromUTF8(utf8_input);
icu::UnicodeString keyword_ustring = icu::UnicodeString::fromUTF8(utf8_keyword);
// キーワードが含まれているかどうかをチェック
if (input_ustring.indexOf(keyword_ustring) >= 0) {
std::cout << "キーワードが含まれています" << std::endl;
} else {
std::cout << "キーワードが含まれていません" << std::endl;
}
return 0;
}
この例では、UTF-8 の文字列を ICU の UnicodeString オブジェクトに変換し、indexOf() 関数を使用してキーワードが含まれているかどうかをチェックしています。キーワードが含まれていれば、indexOf() はキーワードの開始位置(0 以上のインデックス)を返し、含まれていなければ -1 を返します。
改行コードは何故に複数あるのか
歴史的な理由
改行コードには複数の種類が存在するのは、主に歴史的な理由からです。異なるオペレーティングシステムやデバイスが独自の改行コードを持っており、それらが現在まで引き継がれています。
CR (キャリッジリターン): この改行コードは、ASCII コード 13 (0x0D) を使います。古いマシンや電気タイプライターなどの機械に由来し、キャリッジ(紙を押さえる部分)を文書の左端に戻すために使用されていました。Apple の Mac OS 9 以前のバージョンで使用されていました。
LF (ラインフィード): この改行コードは、ASCII コード 10 (0x0A) を使います。ラインフィードは、紙の次の行に移動することを意味します。現在では、主に UNIX 系のオペレーティングシステム(Linux や macOS など)で使用されています。
CRLF (キャリッジリターンとラインフィード): この改行コードは、ASCII コード 13 と 10 (0x0D 0x0A) を組み合わせて使用します。CRLF は、キャリッジを左端に戻し、次の行に移動するという意味を持ちます。現在では、Microsoft Windows オペレーティングシステムで使用されています。
インターネットの普及や異なるオペレーティングシステム間でのデータ交換が一般的になるにつれ、改行コードの違いが問題になることがあります。そのため、多くのテキストエディターやプログラミング言語は、異なる改行コードを自動的に検出して適切に処理できるようになっています。また、一部のプロトコルやファイル形式では、特定の改行コードが標準として定められていることもあります。
ワイド文字やユニコードの場合改行コードはどうなる?
ワイド文字や Unicode でも、基本的には同じ改行コードが使われます。ただし、ワイド文字(wchar_t)や Unicode 文字(char16_t、char32_t)の場合、通常の ASCII コードではなく、対応する Unicode コードポイントを使用します。
CR (キャリッジリターン): Unicode コードポイント U+000D が使われます。
LF (ラインフィード): Unicode コードポイント U+000A が使われます。
CRLF (キャリッジリターンとラインフィード): Unicode コードポイント U+000D と U+000A の組み合わせが使われます。
これらのコードポイントは、ASCII と Unicode の両方で同じ意味を持つため、ワイド文字や Unicode 文字でのテキスト処理でも同様に改行コードを扱うことができます。ただし、プログラミング言語やライブラリによっては、ワイド文字や Unicode 文字に対応した改行コードを処理するための専用の関数や機能が提供されている場合があります。そのため、適切な関数や機能を使って改行コードを処理することが重要です。