C言語関係掲示板

過去ログ

No.1243 UTF8⇒SJISの方法

[戻る] [ホームページ]
No.2452

文字コード変換(UTF8⇒SJIS)の方法を教えてください.
投稿者---ガリンペイロ(2004/08/03 23:05:48)


現在,C言語にて用意されたファイルを読み込んで,文字コードの変換(UTF8⇒SJIS)に挑戦しています.
googleや参考書等でかなり調べたのですが,解りませんでした.VBなら解ったのですが・・・(^^;
どなたかUTF8⇒SJISの方法を教えてください.よろしくお願い致します.

【環境】WindowsXP,VC++6.0



No.2453

Re:文字コード変換(UTF8⇒SJIS)の方法を教えてください.
投稿者---ぽこ(2004/08/04 00:25:15)


>現在,C言語にて用意されたファイルを読み込んで,文字コードの変換(UTF8⇒SJIS)に挑戦しています.
>【環境】WindowsXP,VC++6.0

WideCharToMultiByte()では駄目ですか?



No.2454

Re:文字コード変換(UTF8⇒SJIS)の方法を教えてください.
投稿者---RAPT(2004/08/04 00:29:51)


下記のページに SJIS→UTF8エンコード処理のコードを掲載していますが、
参考になりますか? 単に逆に処理してやればいいだけかと。
UTF-8エンコードについて



No.2455

Re:文字コード変換(UTF8⇒SJIS)の方法を教えてください.
投稿者---Sciggepy(2004/08/04 01:26:44)


私自身はそういうプログラムを作ったことがあります。WindowsならMultiByteToWideCharなどが使えますが、標準のC言語では結構面倒です。
でも、UTF-7の変換よりはましです。
UTF-8の構造とビット演算、mbtowcあたりを理解すれば、作るのには十分です。

(参考)S-JIS→UTF-8の場合(fin:入力ストリーム fout:出力ストリーム)
#define GET4BITS(n) ((unsigned char)((n)&0xf))
#define GET5BITS(n) ((unsigned char)((n)&0x1f))
#define GET6BITS(n) ((unsigned char)((n)&0x3f))
#define ISDBCSLB(c) (((c)>=0x81)&&((c)<=0x9f)||((c)>=0xe0)&&((c)<=0xfc))

void SJIStoUTF8(FILE *fin,FILE *fout)
{
    int c,cb;
    unsigned char mb[2],utf8[3];
    unsigned short wc;

    while((c=fgetc(fin))!=EOF) if(ISDBCSLB(c)) {
        mb[0]=(unsigned char)c;
        if((c=fgetc(fin))!=EOF) {
            mb[1]=(unsigned char)c;
            mbtowc(&wc,mb,2);
            if((wc>=0x80)&&(wc<=0x7ff)) {
                cb=2;
                utf8[1]=GET6BITS(wc)+0x80;
                utf8[0]=GET6BITS(wc>>6)+0xc0;
            } else if(wc>=0x800) {
                cb=3;
                utf8[2]=GET6BITS(wc)+0x80;
                utf8[1]=GET6BITS(wc>>6)+0x80;
                utf8[0]=(wc>>12)+0xe0;
            }
            if(!fwrite(utf8,cb,1,fout)) {
                fprintf(stderr,MSG_ERR_OUTPUT);
                break;
            }
        } else {
            mb[1]=0;
            mbtowc(&wc,mb,2);
            if(wc<=0x7f) {
                cb=1;
                utf8[0]=mb[0];
            } else if((wc>=0x80)&&(wc<=0x7ff)) {
                cb=2;
                utf8[1]=GET6BITS(wc)+0x80;
                utf8[0]=GET6BITS(wc>>6)+0xc0;
            } else if(wc>=0x800) {
                cb=3;
                utf8[2]=GET6BITS(wc)+0x80;
                utf8[1]=GET6BITS(wc>>6)+0x80;
                utf8[0]=(wc>>12)+0xe0;
            }
            if(!fwrite(utf8,cb,1,fout)) {
                fprintf(stderr,MSG_ERR_OUTPUT);
                break;
            }
        }
    } else {
        mb[0]=(unsigned char)c;
        mb[1]=0;
        mbtowc(&wc,mb,2);
        if(wc<=0x7f) {
            cb=1;
            utf8[0]=mb[0];
        } else if((wc>=0x80)&&(wc<=0x7ff)) {
            cb=2;
            utf8[1]=GET6BITS(wc)+0x80;
            utf8[0]=GET6BITS(wc>>6)+0xc0;
        } else if(wc>=0x800) {
            cb=3;
            utf8[2]=GET6BITS(wc)+0x80;
            utf8[1]=GET6BITS(wc>>6)+0x80;
            utf8[0]=(wc>>12)+0xe0;
        }
        if(!fwrite(utf8,cb,1,fout)) {
            fprintf(stderr,MSG_ERR_OUTPUT);
            break;
        }
    }
}

(補足)この関数を呼び出す前に、setlocale(LC_ALL,"");が必要です。


No.2456

Re:文字コード変換(UTF8⇒SJIS)の方法を教えてください.
投稿者---Sciggepy(2004/08/04 12:05:07)


自分でツッコミ
>(補足)この関数を呼び出す前に、setlocale(LC_ALL,"");が必要です。
他のロケールを書き換えないために、setlocale(LC_CTYPE,"");とした方がよいか。


No.2459

Re:文字コード変換(UTF8⇒SJIS)の方法を教えてください.
投稿者---かずま(2004/08/04 19:28:55)


>(参考)S-JIS→UTF-8の場合(fin:入力ストリーム fout:出力ストリーム)
質問者は UTF8 -> 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;
}

----------------------------------------------------------------------
SJIS -> UTF-8 なら、

#include <stdio.h>
#include <stdlib.h>
#include <locale.h>

#define IS_SJIS(c)  (((c) ^ 0x20) - 0xa1u < 60)

void SJIStoUTF8(FILE *fin, FILE *fout)
{
    int c;  char mb[2];  wchar_t wc;

    while ((c = getc(fin)) != EOF) {
        mb[0] = c;
        if (IS_SJIS(c)) {
            if ((c = getc(fin)) == EOF) break;
            mb[1] = c;
            if (mbtowc(&wc, mb, 2) != 2) continue;
        }
        else
            if (mbtowc(&wc, mb, 1) != 1) continue;

        if (wc <= 0x7f)
            putc(wc, fout);
        else if (wc <= 0x7ff) {
            putc(wc >> 6   | 0xc0, fout);
            putc(wc & 0x3f | 0x80, fout);
        }
        else {
            putc(wc >> 12       | 0xe0, fout);
            putc(wc >> 6 & 0x3f | 0x80, fout);
            putc(wc      & 0x3f | 0x80, fout);
        }
    }
}

int main(void)
{
    setlocale(LC_CTYPE, "");
    SJIStoUTF8(stdin, stdout);
    return 0;
}



No.2460

Re:文字コード変換(UTF8⇒SJIS)の方法を教えてください.
投稿者---Sciggepy(2004/08/04 22:00:17)


全部書いてしまっていいものなのか?とりあえず、もう書かれてしまったので、参考までに、自作の関数を載せておきます。
void UTF8toSJIS(FILE *fin,FILE *fout)
{
    int c,cb;
    unsigned char mb[2],utf8[3];
    unsigned short wc;

    while((c=fgetc(fin))!=EOF) if(c>>7) {
        if(c>>6) {
            utf8[0]=GET4BITS(c);
            if((c=fgetc(fin))==EOF) {
                fprintf(stderr,MSG_WRN_INVLCHR,(int)utf8[0]);
                break;
            }
            utf8[1]=GET6BITS(c);
            if((c=fgetc(fin))==EOF) {
                fprintf(stderr,MSG_WRN_INVLCHR,(((int)utf8[0]<<6)|((int)utf8[1])));
                break;
            }
            utf8[2]=GET6BITS(c);
            wc=utf8[0];
            wc<<=6;
            wc+=utf8[1];
            wc<<=6;
            wc+=utf8[2];
            if(!wc) fprintf(stderr,MSG_WRN_INVLCHR,((int)utf8[0]<<12)|((int)utf8[1]<<6)|((int)utf8[2]));
            mb[1]=0;
            wctomb(mb,wc);
            if((mb[0]>0x7f)&&(!mb[1])) cb=1; else cb=2;
            if(!fwrite(mb,cb,1,fout)) {
                fprintf(stderr,MSG_ERR_OUTPUT);
                break;
            }
        } else {
            utf8[0]=GET5BITS(c);
            if((c=fgetc(fin))==EOF) {
                fprintf(stderr,MSG_WRN_INVLCHR,(int)utf8[0]);
                break;
            }
            utf8[1]=GET6BITS(c);
            wc=utf8[0];
            wc<<=6;
            wc+=utf8[1];
            if(!wc) fprintf(stderr,MSG_WRN_INVLCHR,((int)utf8[0]<<4)|((int)utf8[1]));
            wctomb(mb,wc);
            if(!fwrite(mb,2,1,fout)) {
                fprintf(stderr,MSG_ERR_OUTPUT);
                break;
            }
        }
    } else  if(fputc(c,fout)==EOF) {
        fprintf(stderr,MSG_ERR_OUTPUT);
        break;
    }
}



No.2462

Re:文字コード変換(UTF8⇒SJIS)の方法を教えてください.
投稿者---かずま(2004/08/05 03:21:59)


> 全部書いてしまっていいものなのか?とりあえず、もう書かれてしまったので、
> 参考までに、自作の関数を載せておきます。
そのプログラムでは「abあいαβアイ」という文字列が変換できませんよ。

文字:  a    b    あ        い        α     β     ア         イ
SJIS: 61   62   82 a0     82 a2     83 bf  83 c0  b1        b2
UCS2: 0061 0062 3042      3044      03b1   03b2   ff71      ff72
UTF8: 61   62   e3 81 82  e3 81 84  ce b1  ce b2  ef bd b1  ef bd b2



No.2463

Re:文字コード変換(UTF8⇒SJIS)の方法を教えてください.
投稿者---Sciggepy(2004/08/05 12:18:30)


>そのプログラムでは「abあいαβアイ」という文字列が変換できませんよ。
UTF-8のコード ビット列 内容 
0xxx xxxx  1バイトコード 
10xx xxxx  2バイトコード、3バイトコードの2、3文字目  
110x xxxx  2バイトコードの先頭バイト  
1110 xxxx  3バイトコードの先頭バイト 
3バイトコードの先頭を1100と間違えていたとは...


No.2477

Re:文字コード変換(UTF8⇒SJIS)の方法を教えてください.
投稿者---かずま(2004/08/12 18:34:54)


> UTF-8のコード ビット列 内容 
> 0xxx xxxx  1バイトコード 
> 10xx xxxx  2バイトコード、3バイトコードの2、3文字目  
> 110x xxxx  2バイトコードの先頭バイト  
> 1110 xxxx  3バイトコードの先頭バイト 
> 3バイトコードの先頭を1100と間違えていたとは...
3バイトコードの先頭バイトが 1100 xxxx であると間違えていたとしたら、 
その判定方法は、次のいずれかになるはずです。

    if ((c & 0xf0) == 0xc0)
    if ((c >> 4 == 0x0c)
    if (c >= 0xc0 && c <= 0xcf)

もとのプログラムの if (c >> 6) では、01xx xxxx、10xx xxxx、11xx xxxx
の値しか判別できず、しかもそのプログラムでは if (c >> 7) が前にありま
すから、1xxx xxxx が 3バイトコードの先頭だということになっています。



No.2478

Re:文字コード変換(UTF8⇒SJIS)の方法を教えてください.
投稿者---Sciggepy(2004/08/12 19:21:01)


>もとのプログラムの if (c >> 6) では、01xx xxxx、10xx xxxx、11xx >xxxxの値しか判別できず、しかもそのプログラムでは if (c >> 7) が前にありますから、
>1xxx xxxx が 3バイトコードの先頭だということになっています。
前のプログラムの問題に関しては解決済みですが、ビット演算子の使い方には注意が必要でした。
前にUTF-7の変換を行うプログラムを作ろうとしたときも、なぜか無関係の
M i c r o s o f t . W i n d o w s . G d i P l u s
のような文字列が出力されて、困ったことがありました。



No.2464

皆さま、ありがとうございます!!
投稿者---ガリンペイロ(2004/08/05 19:18:52)


丁寧に教えて頂き、本当にありがとうございます。
皆さまの回答を参考にして完成させたいと思います。
完成したら、また報告・感謝レス致します。