utf-8をsjisに変換する

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
K_I

utf-8をsjisに変換する

#1

投稿記事 by K_I » 13年前

過去ログを参考にし、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;
		}
    }
}

Blue

Re: utf-8をsjisに変換する

#2

投稿記事 by Blue » 13年前

wctombってUTF-8→Shift_JIS変換できないのでは?

ワイド文字コード文字列からマルチバイト文字コード文字列に変換するものですから、
UTF-8がマルチバイト文字コードですので一度Unicode(UTF16?UCS2か?)にしないと。

mbtowcでUTF-8→Unicodeに変換できるかは知らない。
Win32APIなら MultiByteToWideChar で変換できますけど。

Blue

Re: utf-8をsjisに変換する

#3

投稿記事 by Blue » 13年前

勘違いしていました。
過去ログのソースを元にしてコードを組んでいるのですね。

元になったソースは結局どれになりますか?

Blue

Re: utf-8をsjisに変換する

#4

投稿記事 by Blue » 13年前

>if ((c = *(char*)utf8++) == EOF)
ここら辺は間違いでしょうね。ファイルではないので '\0' と比較しなければならないのでは。

>sjis[index] = *mb;
これは間違いですね。
memcpyで
>fwrite(mb, 1, c, fout);
のようにコピーしてください。

memcoy(&shis[index], mb, c);

K_I

Re: utf-8をsjisに変換する

#5

投稿記事 by K_I » 13年前

返信ありがとうございます。

>元になったソースは結局どれになりますか?

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;
}

アバター
toyo
記事: 35
登録日時: 13年前
住所: 宮崎県

Re: utf-8をsjisに変換する

#6

投稿記事 by toyo » 13年前

コード:

c = *(char*)utf8
char型をint型に代入する場合はunsigned charにしたほうがいいです

コード:

c = *(unsigned char*)utf8

Blue

Re: utf-8をsjisに変換する

#7

投稿記事 by Blue » 13年前

とりあえず、「井」が変換できることだけ確かめてみてた。

コード:

#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;
}

K_I

Re: utf-8をsjisに変換する

#8

投稿記事 by K_I » 13年前

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は使えません。
他の方法をご存知でしたら教えていただきたいです。
よろしくお願いします。

Blue

Re: utf-8をsjisに変換する

#9

投稿記事 by Blue » 13年前

Shift_JIS文字コードに存在しない文字とかではないですよね?
表せる文字数は UTF-8 > UCS2 > Shift_JIS だったとおもうので、当然変換できない文字があるかと思われます。


ちなみにwctombって、Visual C++の実装だとWin32APIのWideCharToMultiByteを使っているようですね。
Android用にどうやって実行ファイルを作るのか分からないのでwctombを使っていて大丈夫かよくわからないですが・・・


いっそのことUnicode文字列で扱ったほうが何かと都合がよいのではないでしょうか?

K_I

Re: utf-8をsjisに変換する

#10

投稿記事 by K_I » 13年前

>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に変換できるのなら行いたいです。

Blue

Re: utf-8をsjisに変換する

#11

投稿記事 by Blue » 13年前

UTF-8<->Unicodeの変換はできているので、Shift_JISを使わずに内部的にUnicodeで処理するということはむりということでしょうか?
Shift_JISの入力や出力があり得るということなんですかね?


キー入力(UTF-8)→Unicode変換→Unicodeで内部処理→UTF-8変換→出力

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: utf-8をsjisに変換する

#12

投稿記事 by ISLe » 13年前

AndroidアプリをCで作ろうとしているのですね。
JavaならOutputStreamWriterクラスで文字コード(Charset)を指定するだけで済むのですが。

YuO
記事: 947
登録日時: 13年前
住所: 東京都世田谷区

Re: utf-8をsjisに変換する

#13

投稿記事 by YuO » 13年前

> 当面、必要となるのは、キーボードからの入力受け取りだけなので、できれば、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」をエンコードとして使うロケールを指定するようにしてはどうでしょうか。

K_I

Re: utf-8をsjisに変換する

#14

投稿記事 by K_I » 13年前

ご返答ありがとうございます。

>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を使うことが初めてなので、もう少し詳しく教えていただけませんか?

YuO
記事: 947
登録日時: 13年前
住所: 東京都世田谷区

Re: utf-8をsjisに変換する

#15

投稿記事 by YuO » 13年前

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のような処理系に依存せず環境に依存するが,結果のわかっているライブラリを使う
  • 対象処理系の動作を理解した上で,ロケールを適切に設定し,標準関数を使う
  • 自作する (普通は下策)
といった方法をとる必要があります。

アバター
toyo
記事: 35
登録日時: 13年前
住所: 宮崎県

Re: utf-8をsjisに変換する

#16

投稿記事 by toyo » 13年前

私がPSPでプログラムしたときはフリーの日本語フォントがjisコードのものしかなくユニコードからjisコードの変換は自分で行いました
変換表自体はネットで探せばあるので変換自体は簡単です

K_I

Re: utf-8をsjisに変換する

#17

投稿記事 by K_I » 13年前

ご返答ありがとうございます。

>ICUのような処理系や環境に依存しない外部ライブラリを使う

wctombではなく、一度ICUを調べてみようと思います。

閉鎖

“C言語何でも質問掲示板” へ戻る