Shift-JISからutf-8に直接変換
C言語で2ちゃんにつないで、ダウンロードした内容をUTF-8に変換する処理。
文字コード対応表はここのサイトUnicode対応 文字コード表のものを使わせてもらった。漢字とカナを変換するために、16進数で「9,a,b,c,d,e」から始まるものを全てくっつけた。
たぶん文字コード変換ではShift-JIS→UTF-8に直接変換する手段はなかったような…iconvとかでできるかな?
追記:2014/9/8
こういう処理はiconvで書きましょう。そのほうがコードも短いし処理も早いです(泣)。
iconv - Wikipedia
iconvがGPLだから企業のコードに使えない?
ならばnkf, icu, babel等優れた文字コード変換ライブラリは多数存在します。自分お手製の文字コード変換ライブラリなんて死んでも 作ってはいけません!
nkf Network Kanji Filter プロジェクト日本語トップページ - SourceForge.JP
以下、自作の文字コード変換処理…
#include <fstream> #include <iostream> #include <boost/asio.hpp> #include <boost/filesystem/path.hpp> #include <boost/filesystem/operations.hpp> #include <boost/filesystem/fstream.hpp> #include <zlib.h> #include <stdio.h> #include <stdlib.h> #include <string.h> using namespace std; using namespace boost::asio; namespace fs = boost::filesystem; #define SJIS_CHECK_STR strncmp(SJISHEX ,"8" , 1) == 0|| \ strncmp(SJISHEX ,"9" , 1) == 0|| \ strncmp(SJISHEX ,"e" , 1) == 0|| \ strncmp(SJISHEX ,"a" , 1) == 0|| \ strncmp(SJISHEX ,"b" , 1) == 0|| \ strncmp(SJISHEX ,"c" , 1) == 0|| \ strncmp(SJISHEX ,"d" , 1) == 0 #define HANKAKU_CHECK_STR strncmp(SJISHEX ,"a" , 1) == 0|| \ strncmp(SJISHEX ,"b" , 1) == 0|| \ strncmp(SJISHEX ,"c" , 1) == 0|| \ strncmp(SJISHEX ,"d" , 1) == 0 int main() { // ディレクトリ作成 fs::path dir( "./dat" ); fs::create_directory( dir ); // menu.2ch.net の http サービスに接続 ip::tcp::iostream s( "menu.2ch.net", "http" ); // 送信 s << "GET /bbsmenu.html HTTP/1.0 \r\n"; s << "Accept-Encoding: gzip \r\n"; s << "Host: menu.2ch.net \r\n"; s << "Accept: \r\n"; s << "Referer: http://menu.2ch.net/ \r\n"; s << "Accept-Language: ja \r\n"; s << "User-Agent: Mozilla/5.0 \r\n"; s << "Connection: close \r\n"; s << "\r\n"; s << flush; // 受信 string line; bool flag = false; // gzipのヘッダ作成 char HEX[] = {0x1f,0x8b,0x08,0x00}; // ios::binary はバイナリ形式で出力(省略するとアスキー形式で出力) fs::ofstream outputfilegzip( dir/"BoardList.gzip", std::ios::binary ); while( getline(s, line) ){ if ( flag ) { // 真の場合 outputfilegzip << line << endl; } else { // 偽の場合 unsigned int loc = line.find( *HEX , 0 ); if( loc != string::npos ) { outputfilegzip << line << endl; flag = true; } } } outputfilegzip.close(); line.clear(); // gzファイルをZlibを使って解凍する gzFile infile = gzopen("./dat/BoardList.gzip", "rb"); FILE *outfile = fopen("./dat/BoardListSJIS.txt", "wb"); char buffer[128]; int num_read = 0; while ((num_read = gzread(infile, buffer, sizeof(buffer))) > 0) { fwrite(buffer, 1, num_read, outfile); } // ファイルポインタを閉じる gzclose(infile); fclose(outfile); // 文字列変換処理 // ファイルポインタの用意 FILE *fp_sjis; int c_sjis; FILE *fp_utf8; int c_utf8; /* 読み込みモードでSJISのファイルをオープン */ if( fp_sjis != NULL ){ fp_sjis = fopen( "./dat/BoardListSJIS.txt", "r" ); } else { perror("版一覧リストのShift_JISファイル"); exit(EXIT_FAILURE); } /* 書き出しモードでSJISのファイルをオープン */ if( fp_utf8 != NULL ){ fp_utf8 = fopen( "./dat/BoardListUTF8.txt", "w" ); } else { perror("版一覧リストのUTF-8ファイル"); exit(EXIT_FAILURE); } // 判定用変数の準備 char SJISHEX[3]; // 変換テーブルから文字列を読み込むstring string lineTrans; // UTF-8への変換フラグ // flag_su 0:通常時 1:1文字目 2:2文字目 int flag_su = 0; // 変換テーブル探索用文字列 char search_table[5]; // 88a2\0 ← 最終型 // 変換ループ for(;;) { // SJISファイルを一文字ごとに読み出す c_sjis = fgetc( fp_sjis ); // SJISファイルが最終の文字ならばループから抜ける if( c_sjis == EOF ) { break;} sprintf(SJISHEX, "%02x", (char*)c_sjis); SJISHEX[2] = '\x0'; // 2週目でフラグが1だったら2にしておく if ( flag_su == 1 ) { flag_su = 2; } // Shift-JISの先頭バイトが見つかればフラグを1に if ( (SJIS_CHECK_STR) && flag_su != 1 && flag_su != 2 ){ flag_su = 1; } // switch文の開始 switch (flag_su) { // ascii文字だった場合そのまま書きだす case 0: // Shift_JIS以外のasciiコードならばそのまま書きだす // SJISからUTF-8に値渡し c_utf8 = c_sjis; fputc(c_utf8, fp_utf8); break; // 1文字目のShift_JISコードを見つけたので保存 case 1: // 1文字目が一致したので先頭1バイトを格納する char testHex[8]; sprintf(testHex, "%02x", (char*)c_sjis); search_table[0] = testHex[0]; search_table[1] = testHex[1]; search_table[2] = '\x0'; // もしも1文字目で変換が必要な半角カナ文字等だったらここで変換する if (HANKAKU_CHECK_STR) { printf("convert: %s ",search_table); // 変換テーブルは読み込み専用で開く ifstream transtable( "./dat/transtable.dat", std::ios::in ); // 対象となる文字列が見つかるまでループ while ( getline(transtable, lineTrans) ) { char scanstr[ 64 ]; strcpy( scanstr, lineTrans.c_str() ); // スキャンした文字列中のSJISとUTF8文字列へのポインタ char *psjis_kana = scanstr; psjis_kana = psjis_kana + 11; // 探索文字列の大文字化 for( int i=0; i<3; i++ ){ search_table[i] = toupper( search_table[i] ); } // scanstr中のSJIS文字列と一致すればループ脱出 if ( *psjis_kana == search_table[0] && *(psjis_kana+1) == search_table[1] ) { // UTF-8用のバイナリを作成して書きこむ char wb1[3] = { scanstr[21], scanstr[22], '\x0' }; char wb2[3] = { scanstr[23], scanstr[24], '\x0' }; char wb3[3] = { scanstr[25], scanstr[26], '\x0' }; printf("to %s%s%s \n",wb1,wb2,wb3); //char型文字列から変換 long nValue; char* wbEnd; nValue = ::strtol(wb1,&wbEnd,16); fputc((unsigned int)nValue, fp_utf8); nValue = ::strtol(wb2,&wbEnd,16); fputc((unsigned int)nValue, fp_utf8); nValue = ::strtol(wb3,&wbEnd,16); fputc((unsigned int)nValue, fp_utf8); } } // フラグをもとに戻す flag_su = 0; // 変換テーブルは毎回閉じる transtable.close(); } break; // 2文字目のShift_JISコードを見つけて変換テーブルに探しに行く case 2: sprintf(testHex, "%02x", (char*)c_sjis); search_table[2] = testHex[0]; search_table[3] = testHex[1]; search_table[4] = '\x0'; printf("convert: %s ",search_table); // 変換テーブルは読み込み専用で開く ifstream transtable( "./dat/transtable.dat", std::ios::in ); // 対象となる文字列が見つかるまでループ while ( getline(transtable, lineTrans) ) { char scanstr[ 64 ]; strcpy( scanstr, lineTrans.c_str() ); // スキャンした文字列中のSJISとUTF8文字列へのポインタ char *psjis = scanstr; psjis = psjis + 11; // 探索文字列の大文字化 for( int i=0; i<5; i++ ){ search_table[i] = toupper( search_table[i] ); } // scanstr中のSJIS文字列と一致すればループ脱出 if ( *psjis == search_table[0] && *(psjis+1) == search_table[1] && *(psjis+2) == search_table[2] && *(psjis+3) == search_table[3] ) { // UTF-8用のバイナリを作成して書きこむ char wb1[3] = { scanstr[21], scanstr[22], '\x0' }; char wb2[3] = { scanstr[23], scanstr[24], '\x0' }; char wb3[3] = { scanstr[25], scanstr[26], '\x0' }; printf("to %s%s%s \n",wb1,wb2,wb3); //char型文字列から変換 long nValue; char* wbEnd; nValue = ::strtol(wb1,&wbEnd,16); fputc((unsigned int)nValue, fp_utf8); nValue = ::strtol(wb2,&wbEnd,16); fputc((unsigned int)nValue, fp_utf8); nValue = ::strtol(wb3,&wbEnd,16); fputc((unsigned int)nValue, fp_utf8); break; } } // フラグをもとに戻す flag_su = 0; // 変換テーブルは毎回閉じる transtable.close(); break; }// switch文終了 } fclose( fp_sjis ); fclose( fp_utf8 ); }