C 日本語文字列 新しいページはコチラ

提供: yonewiki
移動: 案内, 検索
(マルチバイト文字列、ワイド文字列の相互変換)
3行: 3行:
 
<br />
 
<br />
 
== '''日本語文字列''' ==
 
== '''日本語文字列''' ==
char型の配列で1byte、1文字を表現できるascii文字コードというものを使っていましたが、<br />
+
char型の配列で1byte、1文字を表現できるascii文字コードというものを使っていましたが、問題点はいくつかありますが、そのままでも日本語全角文字は表現できます。日本語文字コードは2Byteで表現されます。
問題点はいくつかありますが、そのままでも日本語全角文字は表現できます。日本語文字コードは2Byteで表現されます。<br />
+
全角のアルファベットからカタカナ、ひらがな、漢字、記号、あまり使わない漢字を含めて65536種類を00 00からFF FFまでで、表現しています。最初の1byteが0x80~0x9F、0xE0~0xFCならばasciiコードでは定義していないため、その後ろの1byteも読み込んで1文字だと処理してくれます。マルチバイト文字と呼んでいます。asciiコードですでに使われている部分は使えないとしても、日本語文字コードは15616種類を使えます。これでも十分です。<br />
全角のアルファベットからカタカナ、ひらがな、漢字、記号、あまり使わない漢字を含めて65536種類を00 00からFF FFまで<br />
+
 
で表現しています。最初の1byteが0x80~0x9F、0xE0~0xFCならばasciiコードでは定義していないため、その後ろの1byteも読み込んで1文字だと処理してくれます。<br />
+
 
マルチバイト文字と呼んでいます。asciiコードですでに使われている部分は使えないとしても、日本語文字コードは15616種類を使えます。これでも十分です。<br />
+
 
<br />
+
問題点1は文字数と配列の大きさが一致しないことです。加えて、0x80 0x5cのように2byte文字コードの中に0x5cが登場すると、0x5c='\'ですので、次の文字はエスケープシーケンスだとみなされ2byteずつ出力してくれる手順より優先して、その次にくる文字の1byteの処理をしようとします。この結果文字化けが発生します。2byte文字の下位byteに0x5cが登場するのは、以下のような文字です。<span style="color:red">但し、現在のVisualStudioC++2012では、内部的に解決するので、この問題は発生しません。とは言え、文字列検索\の検索とかで支障があるやもしれません。</span>  
問題点1は文字数と配列の大きさが一致しないことです。<br />
+
 
加えて、0x80 0x5cのように2byte文字コードの中に0x5cが登場すると、0x5c='\'ですので、次の文字はエスケープシーケンスだとみなされ<br />
+
 
2byteずつ出力してくれる手順より優先して、その次にくる文字の1byteの処理をしようとします。この結果文字化けが発生します。2byte文字の下位byteに0x5cが<br />
+
登場するのは、以下のような文字です。<span style="color:red">但し、現在のVisualStudioC++2012では、内部的に解決するので、この問題は発生しません。とは言え、文字列検索\の検索とかで支障があるやもしれません。</span> <br />
+
 
―,ソ,Ы,Ⅸ,噂,浬,欺,圭,構,蚕,十,申,曾,箪,貼,能,表,暴,予,禄,兔,喀,媾,彌,拿,杤,歃,濬,畚,秉,綵,臀,藹,觸,軆,鐔,饅,鷭,偆,砡,纊,犾<br />
 
―,ソ,Ы,Ⅸ,噂,浬,欺,圭,構,蚕,十,申,曾,箪,貼,能,表,暴,予,禄,兔,喀,媾,彌,拿,杤,歃,濬,畚,秉,綵,臀,藹,觸,軆,鐔,饅,鷭,偆,砡,纊,犾<br />
普段使わない文字が多いですが、使いそうなのは―,ソ,Ⅸ,噂,欺,圭,構,蚕,十,申,曾,貼,能,表,暴,予,といったあたりでしょうか。使う使わないは、それぞれの立場で異なるので、<br />
+
 
そういった分類は意味を成しませんが、ともかくこれらの文字が出てきたらエスケープシーケンスを打ち切るために'\\'という形にすればよく、<br />
+
 
\個,表\示,能\力とかにする手法があります。出力に限ればそれで済むことですが、検索処理でこれにはまると、面倒過ぎる。<br />
+
普段使わない文字が多いですが、使いそうなのは―,ソ,Ⅸ,噂,欺,圭,構,蚕,十,申,曾,貼,能,表,暴,予,といったあたりでしょうか。使う使わないは、それぞれの立場で異なるので、そういった分類は意味を成しませんが、ともかくこれらの文字が出てきたらエスケープシーケンスを打ち切るために'\\'という形にすればよく、十\個,表\示,能\力とかにする手法があります。出力に限ればそれで済むことですが、検索処理でこれにはまると、面倒過ぎる。<br />
※勘違いしてはいけないことですが、printf文で出力するときに必要となる手法としてです。<br />
+
 
テキスト文書が能\力といった形で保存しておくということを言っているのではないです。プログラム側だけで対処すべきことです。<br />
+
 
それはメモ帳のようなテキストエディタで「表示」と記述してANSI(実際はShift_JISでCP932)形式で保存しても、バイナリエディタで開いたら95 5C 8E A6と保存されることでも<br />
+
※勘違いしてはいけないことですが、printf文で出力するときに必要となる手法としてです。テキスト文書が能\力といった形で保存しておくということを言っているのではないです。プログラム側だけで対処すべきことです。それはメモ帳のようなテキストエディタで「表示」と記述してANSI(実際はShift_JISでCP932)形式で保存しても、バイナリエディタで開いたら95 5C 8E A6と保存されることでも理解できると思います。95 5C 5C 8E A6と保存していたら、あるテキストエディタ「表\示」とそのまま画面に出力され、適当なプログラムの方では「表示」とされることになります。このような問題から、日本語をそのままchar型でマルチバイト文字列として扱うのはよろしくないということがわかります。※0x5cをみつけたら、もう一個\を加える処理とか、マルチバイトの先頭にくる文字コードが来たら2byteで1文字とか計算したりして、昔はPerlとかでCGI組むときでは、このままつかってたこともありました。(汗<br />
理解できると思います。95 5C 5C 8E A6と保存していたら、あるテキストエディタ「表\示」とそのまま画面に出力され、適当なプログラムの方では「表示」とされることになります。<br />
+
 
<br />
+
 
このような問題から、日本語をそのままchar型でマルチバイト文字列として扱うのはよろしくないということがわかります。<br />
+
※0x5cをみつけたら、もう一個\を加える処理とか、マルチバイトの先頭にくる文字コードが来たら2byteで1文字とか計算したりして、昔はPerlとかでCGI組むときでは、このままつかってたこともありました。(汗<br />
+
 
今はいろいろ便利な関数が用意されているので、そういったことは自分で対処しなくてよくなりましたね。<br />
 
今はいろいろ便利な関数が用意されているので、そういったことは自分で対処しなくてよくなりましたね。<br />
<br />
+
 
 +
 
 +
 
 
それで、解決策は?<br />
 
それで、解決策は?<br />
<br />
+
 
実はいくつかありまして…。どれがいいとか悪いとかは、それぞれなんですけど…あの~その~面倒ですが、そのいくつかを紹介しようかと思います。<br />
+
 
「おいおい…一つにしてよ。どうすればいいかわからんやん。」という声が聞こえてきますが、全くその通りなんですけど、いまだに宙に浮いている問題でして、<br />
+
 
統一まではできないかと思います。<br />
+
実はいくつかありまして…。どれがいいとか悪いとかは、それぞれなんですけど…あの~その~面倒ですが、そのいくつかを紹介しようかと思います。「おいおい…一つにしてよ。どうすればいいかわからんやん。」という声が聞こえてきますが、全くその通りなんですけど、いまだに宙に浮いている問題でして、統一まではできないかと思います。でも一番いいのはこれってのはあります。でも、それはそれで、「そんなことせなあかんの?話が違う、帰るわ!」って思われるかもしれません。<br />
でも一番いいのはこれってのはあります。でも、それはそれで、「そんなことせなあかんの?話が違う、帰るわ!」って思われるかもしれません。<br />
+
 
<br />
+
  
 
== '''マルチバイト文字列、ワイド文字列''' ==
 
== '''マルチバイト文字列、ワイド文字列''' ==
39行: 36行:
  
 
*ワイド文字列<br />
 
*ワイド文字列<br />
固定の2byte以上のメモリ空間に英数字ascii範囲とか関係なくすべて同じ固定の領域に格納する方法。デメリットとしては、文字列でメモリ空間をかなり無駄にしてしまうということ。<br />
+
固定の2byte以上のメモリ空間に英数字ascii範囲とか関係なくすべて同じ固定の領域に格納する方法。デメリットとしては、文字列でメモリ空間をかなり無駄にしてしまうということ。あえて英数字のみ対応のアプリを作るのは、このデメリットと引き換えにして、メモリの節約をしていることになります。それか面倒だから、asciiコードのみ対応にしたとか…。でも、言いにくいことなんですけど…、いろんな方式をいろんな人が使っている昨今でして、全体的に網羅しておかないと変換とかしないとダメなので、覚えることが多いのも事実です。Unicodeって言う方式もこれです。Unicodeの符号化方式のUTF-16は、基本的には半角の英数字も含めて、2byteで1文字を表すためメモリは無駄にしますが、変換効率が高いために実行速度が速くなるというメリットがあります。実行速度の速さにあやかれるほどのプログラムを作るかどうかは未知数です。<br />
あえて英数字のみ対応のアプリを作るのは、このデメリットと引き換えにして、メモリの節約をしていることになります。それか面倒だから、asciiコードのみ対応にしたとか…。<br />
+
 
でも、言いにくいことなんですけど…、いろんな方式をいろんな人が使っている昨今でして、全体的に網羅しておかないと変換とかしないとダメなので、覚えることが多いのも事実です。<br />
+
 
Unicodeって言う方式もこれです。<br />
+
VisualSutdioのプロジェクトの設定でもUnicode文字列とマルチバイト文字列、どっちも使わないってのが設定できます。VisualStudioをアクティブにしている状態で[Alt]+[F7]でプロジェクトのプロパティが表示されるダイアログが表示されます。左側のツリー構造から構成プロパティの中の全般を選択すると右側のビュー表示されるリストに文字セットというのがあります。リストには「Unicode文字セットを使用する/マルチバイト文字セットを使用する/設定なし」の3つがあり、ここで選択した設定にしたがって、Visual C++だけの機能になりますが、TCHAR型という文字列変数を定義することで、設定にしたがって、マルチバイトおよびUnicodeを判別してコンパイルしてくれます。因みにワイド文字列型では、wchar_t型というのを使うのですが、TCHAR型は、Unicode設定だとwchar_tに置き換わることになります。<br />
Unicodeの符号化方式のUTF-16は、基本的には半角の英数字も含めて、2byteで1文字を表すためメモリは無駄にしますが、変換効率が高いために実行速度が速くなるというメリットがあります。<br />
+
 
実行速度の速さにあやかれるほどのプログラムを作るかどうかは未知数です。<br />
+
 
 +
ワイド文字列では、文字列リテラルへは L("yonewiki") としなければならないし、例えば文字列を引数にする関数もwprintf(L("cStr=%s"),cStr );とかに多数の書き換えが必要になります。そして、ワイド文字がどこの国の言葉を扱うのかを定義するには、setlocale関数で設定が必要で、setlocale( LC_ALL, "Japanese" );※リテラルの設定では省略されていますが、setlocale( LC_ALL, "Japanese_Japan.932" ); />
 +
と設定していることになります。出力するときには日本語のShift_JISにしてねということです。今はWindowsPCのコマンドプロンプトで動作を確認しているからです。<br />
 +
 
  
VisualSutdioのプロジェクトの設定でもUnicode文字列とマルチバイト文字列、どっちも使わないってのが設定できます。<br />
 
VisualStudioをアクティブにしている状態で[Alt]+[F7]でプロジェクトのプロパティが表示されるダイアログが表示されます。<br />
 
左側のツリー構造から構成プロパティの中の全般を選択すると右側のビュー表示されるリストに文字セットというのがあります。<br />
 
リストには「Unicode文字セットを使用する/マルチバイト文字セットを使用する/設定なし」の3つがあり、ここで選択した設定にしたがって<br />
 
Visual C++だけの機能になりますが、TCHAR型という文字列変数を定義することで、設定にしたがって、マルチバイトおよびUnicodeを判別してコンパイルしてくれます。<br />
 
因みにワイド文字列型では、wchar_t型というのを使うのですが、TCHAR型は、Unicode設定だとwchar_tに置き換わることになります。<br />
 
<br />
 
ワイド文字列では、文字列リテラルへは L("yonewiki") としなければならないし、<br />
 
例えば文字列を引数にする関数もwprintf(L("cStr=%s"),cStr );とかに多数の書き換えが必要になります。<br />
 
そして、ワイド文字がどこの国の言葉を扱うのかを定義するには、<br />
 
setlocale関数で設定が必要で、<br />
 
setlocale( LC_ALL, "Japanese" );<br />
 
※リテラルの設定では省略されていますが、setlocale( LC_ALL, "Japanese_Japan.932" );<br />
 
と設定していることになります。出力するときには日本語のShift_JISにしてねということです。<br />
 
今はWindowsPCのコマンドプロンプトで動作を確認しているからです。
 
<br />
 
 
※ちなみに関数のリファレンスはmsdnが最強だと思うわけでして、<br />
 
※ちなみに関数のリファレンスはmsdnが最強だと思うわけでして、<br />
*C++Runtimeリファレンス<br />
+
*C++Runtimeリファレンス(※実行時に動的に呼び出せるという意味でRuntimeとついています。通常はRuntimeライブラリはWindowsのバージョンによって異なるライブラリが入っていますが、Versionが上がっても基本的には、同じようなものだと考えて差し支えないです。静的にもコンパイルできますので、Windows系 Visual C++で使えるC++リファレンスと思ってよいかと。でもいろんなバージョンがあるからこそ、MSVCRTxx.dllが無いのでエラーってなったりする不具合もネット界隈を賑わしています。全部、最初から配ればいいのにMicrosoft…何やってんだ…素人には手ごわいエラーだけに印象悪いっしょ。ちょっと調べることができたら解決できるんですけどね。まぁなんのこっちゃわからん人には難しいわな。)<br />
 
http://msdn.microsoft.com/ja-jp/library/634ca0c2(v=vs.90).aspx<br />
 
http://msdn.microsoft.com/ja-jp/library/634ca0c2(v=vs.90).aspx<br />
 
*setlocale<br />
 
*setlocale<br />

2013年12月7日 (土) 00:00時点における版



個人用ツール
名前空間

変種
操作
案内
ツールボックス