ページ 1 / 1
utf-8をsjisに変換する
Posted: 2010年12月21日(火) 13:22
by K_I
過去ログを参考にし、utf-8をsjisに変換しようとしておりますが、
wctomb関数の戻り値が-1になりうまくいっておりません。
例えば、「井」をutf8に入力しました。
31行目、c = wctomb(mb, wc)を通るときに、wcの値が4E95になっており、
utf-16の文字コードになっているのを確認しましたが、cの戻り値が-1になっているので、
正しい値が取得できてないです。
wctombの使い方が間違っていますか?
よろしくお願い致します。
過去ログ(
http://f4.aaa.livedoor.jp/~pointc/log1243.html)を参考にしたコードです。
コード:
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
void UTF8ToSJIS(const char* utf8, char* sjis)
{
int c; char mb[2]; wchar_t wc;
s32 index = 0;
s32 i=0;
setlocale(LC_CTYPE, "");
while ((c = *(char*)utf8++) != 0x00) {
if (c < 0x80)
wc = c;
else if (c < 0xc0)
continue;
else if (c < 0xe0) {
wc = (c & 0x1f) << 6;
if ((c = *(char*)utf8++) == EOF) break;
wc |= c & 0x3f;
}
else if (c < 0xf0) {
wc = (c & 0x0f) << 12;
if ((c = *(char*)utf8++) == EOF) break;
wc |= (c & 0x3f) << 6;
if ((c = *(char*)utf8++) == EOF) break;
wc |= c & 0x3f;
}
else
continue;
c = wctomb(mb, wc);
if (c > 0) {
sjis[index] = *mb;
index+=c;
}
}
}
Re: utf-8をsjisに変換する
Posted: 2010年12月21日(火) 13:52
by Blue
wctombってUTF-8→Shift_JIS変換できないのでは?
ワイド文字コード文字列からマルチバイト文字コード文字列に変換するものですから、
UTF-8がマルチバイト文字コードですので一度Unicode(UTF16?UCS2か?)にしないと。
mbtowcでUTF-8→Unicodeに変換できるかは知らない。
Win32APIなら MultiByteToWideChar で変換できますけど。
Re: utf-8をsjisに変換する
Posted: 2010年12月21日(火) 14:02
by Blue
勘違いしていました。
過去ログのソースを元にしてコードを組んでいるのですね。
元になったソースは結局どれになりますか?
Re: utf-8をsjisに変換する
Posted: 2010年12月21日(火) 14:08
by Blue
>if ((c = *(char*)utf8++) == EOF)
ここら辺は間違いでしょうね。ファイルではないので '\0' と比較しなければならないのでは。
>sjis[index] = *mb;
これは間違いですね。
memcpyで
>fwrite(mb, 1, c, fout);
のようにコピーしてください。
memcoy(&shis[index], mb, c);
Re: utf-8をsjisに変換する
Posted: 2010年12月21日(火) 14:11
by K_I
返信ありがとうございます。
>元になったソースは結局どれになりますか?
No.2459:かずまさんのコードを参考にしております。
utf-8をutf16に変換してから、sjisにしているのだと思います。
コード:
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
void UTF8ToSJIS(FILE *fin, FILE *fout)
{
int c; char mb[2]; wchar_t wc;
while ((c = getc(fin)) != EOF) {
if (c < 0x80)
wc = c;
else if (c < 0xc0)
continue;
else if (c < 0xe0) {
wc = (c & 0x1f) << 6;
if ((c = getc(fin)) == EOF) break;
wc |= c & 0x3f;
}
else if (c < 0xf0) {
wc = (c & 0x0f) << 12;
if ((c = getc(fin)) == EOF) break;
wc |= (c & 0x3f) << 6;
if ((c = getc(fin)) == EOF) break;
wc |= c & 0x3f;
}
else
continue;
c = wctomb(mb, wc);
if (c > 0) fwrite(mb, 1, c, fout);
}
}
int main(void)
{
setlocale(LC_CTYPE, "");
UTF8ToSJIS(stdin, stdout);
return 0;
}
Re: utf-8をsjisに変換する
Posted: 2010年12月21日(火) 14:26
by toyo
char型をint型に代入する場合はunsigned charにしたほうがいいです
コード:
c = *(unsigned char*)utf8
Re: utf-8をsjisに変換する
Posted: 2010年12月21日(火) 14:27
by Blue
とりあえず、「井」が変換できることだけ確かめてみてた。
コード:
#include <stdlib.h>
#include <locale.h>
#include <memory.h>
void UTF8ToSJIS(const char* utf8, char* sjis)
{
char mb[2];
wchar_t wc;
int index = 0;
int c;
while ((c = (unsigned char)*(utf8++)) != '\0')
{
if (c < 0x80)
wc = c;
else if (c < 0xc0)
continue;
else if (c < 0xe0) {
wc = (c & 0x1f) << 6;
if ((c = (unsigned char)*(utf8++)) == '\0') break;
wc |= c & 0x3f;
}
else if (c < 0xf0) {
wc = (c & 0x0f) << 12;
if ((c = (unsigned char)*(utf8++)) == '\0') break;
wc |= (c & 0x3f) << 6;
if ((c = (unsigned char)*(utf8++)) == '\0') break;
wc |= c & 0x3f;
}
else
continue;
c = wctomb(mb, wc);
if (c > 0) {
memcpy(&sjis[index], mb, c);
index += c;
}
}
sjis[index] = '\0';
};
int main()
{
char sjis[256];
char utf8[] = "\xe4\xba\x95";
setlocale(LC_CTYPE, "");
UTF8ToSJIS(utf8, sjis);
return 0;
}
Re: utf-8をsjisに変換する
Posted: 2010年12月21日(火) 15:00
by K_I
Blueさんtoyoさん
ご指摘ありがとうございます。
Blueさんのコードをコピペして実行してみましたが、やはり、
以下の行で、cに-1が返ってきています。この時のwcの値は、「20117 L'\225'」でした。
c = wctomb(mb, wc);
使用している開発環境は、以下です。
・Microsoft Visual Studio2008(90日評価版)
・vivid runtime sdk v1.1 RC1
Androidでアプリ作ろうと思っているのですが、Androidで対応しているのは、UTF-8のみになるので、
Androidから入力された値をSJISへ変換がしたいのです。
この方法が無理であるのなら、別の方法も試してみたいと思っています。
Win32APIが使用できないので、MultiByteToWideCharは使えません。
他の方法をご存知でしたら教えていただきたいです。
よろしくお願いします。
Re: utf-8をsjisに変換する
Posted: 2010年12月21日(火) 15:15
by Blue
Shift_JIS文字コードに存在しない文字とかではないですよね?
表せる文字数は UTF-8 > UCS2 > Shift_JIS だったとおもうので、当然変換できない文字があるかと思われます。
ちなみにwctombって、Visual C++の実装だとWin32APIのWideCharToMultiByteを使っているようですね。
Android用にどうやって実行ファイルを作るのか分からないのでwctombを使っていて大丈夫かよくわからないですが・・・
いっそのことUnicode文字列で扱ったほうが何かと都合がよいのではないでしょうか?
Re: utf-8をsjisに変換する
Posted: 2010年12月21日(火) 15:35
by K_I
>Shift_JIS文字コードに存在しない文字とかではないですよね?
>表せる文字数は UTF-8 > UCS2 > Shift_JIS だったとおもうので、当然変換できない文字があるかと思われます。
char utf8[] = "\xe4\xba\x95";
「井」で試してみましたが、wctombにて-1でした。
>ちなみにwctombって、Visual C++の実装だとWin32APIのWideCharToMultiByteを使っているようですね。
>Android用にどうやって実行ファイルを作るのか分からないのでwctombを使っていて大丈夫かよくわからないですが・・・
WideCharToMultiByteは<windows.h>をインクルードできないので使用できないと思います。
wctombはコンパイルは通るので使用できると思っていました。結果が-1になってしまうので、
言われている様に、大丈夫ではないのかもしれません。
>いっそのことUnicode文字列で扱ったほうが何かと都合がよいのではないでしょうか?
当面、必要となるのは、キーボードからの入力受け取りだけなので、できれば、utf-8をsjisに変換できるのなら行いたいです。
Re: utf-8をsjisに変換する
Posted: 2010年12月21日(火) 16:43
by Blue
UTF-8<->Unicodeの変換はできているので、Shift_JISを使わずに内部的にUnicodeで処理するということはむりということでしょうか?
Shift_JISの入力や出力があり得るということなんですかね?
キー入力(UTF-8)→Unicode変換→Unicodeで内部処理→UTF-8変換→出力
Re: utf-8をsjisに変換する
Posted: 2010年12月21日(火) 16:59
by ISLe
AndroidアプリをCで作ろうとしているのですね。
JavaならOutputStreamWriterクラスで文字コード(Charset)を指定するだけで済むのですが。
Re: utf-8をsjisに変換する
Posted: 2010年12月21日(火) 17:14
by YuO
> 当面、必要となるのは、キーボードからの入力受け取りだけなので、できれば、utf-8をsjisに変換できるのなら行いたいです。
変換せずに済むのであれば変換しなくてよいですよね。
UTF-8で完結できない理由は何でしょうか。
> ちなみにwctombって、Visual C++の実装だとWin32APIのWideCharToMultiByteを使っているようですね。
> Android用にどうやって実行ファイルを作るのか分からないのでwctombを使っていて大丈夫かよくわからないですが・・・
wctombはISO規格に最初 (1990年版) からある標準関数ですので,wctomb自体を使うことは問題ないでしょう。
また,その文字列版wcstombsも最初からあります。
ただし,実際にcharやwchar_tで使われる符号化方法はロケール依存だったり実装依存だったりします。
また,setlocaleの第二引数を""にした場合は,「処理系定義の固有の影響」をしていすることになるのであって,charがShift_JISであることを意味しません。
Android上で正しく「Shift_JIS」をエンコードとして使うロケールを指定するようにしてはどうでしょうか。
Re: utf-8をsjisに変換する
Posted: 2010年12月21日(火) 18:44
by K_I
ご返答ありがとうございます。
>UTF-8<->Unicodeの変換はできているので、Shift_JISを使わずに内部的にUnicodeで処理するということはむりということでしょうか?
>Shift_JISの入力や出力があり得るということなんですかね?
>キー入力(UTF-8)→Unicode変換→Unicodeで内部処理→UTF-8変換→出力
>UTF-8で完結できない理由は何でしょうか。
文字を描画する際にsjisの並びで、文字テクスチャを用意してしまったため、
プログラム中にsjisの文字コードであることが前提のようなプログラム部分があるためです。
Shift_JISの入力や出力というよりも、sjisで内部処理部分を作ってしまったため、直す方が時間がかかりそうなので、
キー入力(UTF-8)→sjisで済むのなら、済ましたいです。
>また,setlocaleの第二引数を""にした場合は,「処理系定義の固有の影響」をしていすることになるのであって,charがShift_JISであることを意味しません。
>Android上で正しく「Shift_JIS」をエンコードとして使うロケールを指定するようにしてはどうでしょうか。
wctomb自体が互換性がwindowsになっているようなので、Androidでは使えない気がしてきましたが、
ロケールの指定で変わるのですか?setlocaleを使うことが初めてなので、もう少し詳しく教えていただけませんか?
Re: utf-8をsjisに変換する
Posted: 2010年12月22日(水) 02:00
by YuO
K_I さんが書きました:>UTF-8で完結できない理由は何でしょうか。
文字を描画する際にsjisの並びで、文字テクスチャを用意してしまったため、
プログラム中にsjisの文字コードであることが前提のようなプログラム部分があるためです。
Shift_JISの入力や出力というよりも、sjisで内部処理部分を作ってしまったため、直す方が時間がかかりそうなので、
キー入力(UTF-8)→sjisで済むのなら、済ましたいです。
突き放すようですが,ロケールや文字コードまわりの話が理解できていない場合,UTF-8ベースなりUTF-16ベースなりに直した方がよいです。
ロケールまわりは個人的にはCの暗部に突っ込んでいくような物だと思っています (ほぼ実装依存の世界なので)。
UTF-8とUTF-16やUCS-2の間の変換は機械的にできますし。
K_I さんが書きました:>また,setlocaleの第二引数を""にした場合は,「処理系定義の固有の影響」をしていすることになるのであって,charがShift_JISであることを意味しません。
>Android上で正しく「Shift_JIS」をエンコードとして使うロケールを指定するようにしてはどうでしょうか。
wctomb自体が互換性がwindowsになっているようなので、Androidでは使えない気がしてきましたが、
ロケールの指定で変わるのですか?setlocaleを使うことが初めてなので、もう少し詳しく教えていただけませんか?
ロケールというのは,例えば,
- 小数点は何か
- 多バイト文字の解釈に使われる文字コードは何か (規格にはこうは書いていないが)
といったような,国やら言語やら文化やらに依存した情報の集合です。
""は実行環境に依存したロケールの指定と同一,というのが建前ですが,どういう環境下でどういう結果になるのかは一切定められていません。
これ以上ロケールをちゃんと説明できる自信が私には無いので,説明は打ち切ってしまいますが,文字コード変換をしたいのであれば,
- ICUのような処理系や環境に依存しない外部ライブラリを使う
- MultiByeToWideCharのような処理系に依存せず環境に依存するが,結果のわかっているライブラリを使う
- 対象処理系の動作を理解した上で,ロケールを適切に設定し,標準関数を使う
- 自作する (普通は下策)
といった方法をとる必要があります。
Re: utf-8をsjisに変換する
Posted: 2010年12月22日(水) 06:57
by toyo
私がPSPでプログラムしたときはフリーの日本語フォントがjisコードのものしかなくユニコードからjisコードの変換は自分で行いました
変換表自体はネットで探せばあるので変換自体は簡単です
Re: utf-8をsjisに変換する
Posted: 2010年12月22日(水) 09:22
by K_I
ご返答ありがとうございます。
>ICUのような処理系や環境に依存しない外部ライブラリを使う
wctombではなく、一度ICUを調べてみようと思います。