コンピューター:C言語講座:全角・半角変換について
概要
プログラムを作成していると、全角の数字・アルファベットを半角にしたり、その逆を行いたい、ということが良くあります。たとえば2バイト文字の数字で書かれた文書から数字を数値として内部処理したい場合など。特に文書管理物などで良く出てくると思いますが、仕様を決めるお客さんにとってそんなことは簡単なことだ、と思われてしまう割に意外と手間がかかりませんか?
SolarisやSunOSなどでは独自の日本語処理ライブラリが付属していて助かる場合もありますが、移植性を考えるとやっぱり1つは確実な物を自分で持っておきたいところです。
そんな物コードの特性を考えれば簡単だ、といきなりASCIIコードとSJIS(EUC)コードをにらめっこして式を考えても良いのですが、意外とSJISで作らなければならないのに自分の環境がEUCだったりして実験に困るものです。
そこで今回は実に泥臭く、変換する文字をすべてソース中に埋め込んでしまうことにします。速度的には比較が多くなるのでもちろん落ちますが、ソースを動かしたい環境のコードに変換してコンパイルすればSJISでもEUCでも使えるという大きなメリット(人によってはどうでも良いことかもしれませんが・・・)があります。このくらい自分でも作れるわい、という人でも意外とキーを打つだけでも疲れるので、念のためサンプルも掲載します。
サンプル
#include <stdio.h> #include <string.h> int han2zen(char *str) { char *buf,*p,*ptr; buf=(char *)calloc(strlen(str)*2+1,sizeof(char)); for(ptr=str,p=buf;*ptr!='\0';*ptr++){ switch((int)*ptr){ case ' ': strcpy(p," ");p+=2;break; case '!': strcpy(p,"!");p+=2;break; case '"': strcpy(p,"”");p+=2;break; case '#': strcpy(p,"#");p+=2;break; case '$': strcpy(p,"$");p+=2;break; case '%': strcpy(p,"%");p+=2;break; case '&': strcpy(p,"&");p+=2;break; case '\'': strcpy(p,"’");p+=2;break; case '(': strcpy(p,"(");p+=2;break; case ')': strcpy(p,")");p+=2;break; case '*': strcpy(p,"*");p+=2;break; case '+': strcpy(p,"+");p+=2;break; case ',': strcpy(p,",");p+=2;break; case '-': strcpy(p,"−");p+=2;break; case '.': strcpy(p,".");p+=2;break; case '/': strcpy(p,"/");p+=2;break; case '0': strcpy(p,"0");p+=2;break; case '1': strcpy(p,"1");p+=2;break; case '2': strcpy(p,"2");p+=2;break; case '3': strcpy(p,"3");p+=2;break; case '4': strcpy(p,"4");p+=2;break; case '5': strcpy(p,"5");p+=2;break; case '6': strcpy(p,"6");p+=2;break; case '7': strcpy(p,"7");p+=2;break; case '8': strcpy(p,"8");p+=2;break; case '9': strcpy(p,"9");p+=2;break; case ':': strcpy(p,":");p+=2;break; case ';': strcpy(p,";");p+=2;break; case '<': strcpy(p,"<");p+=2;break; case '=': strcpy(p,"=");p+=2;break; case '>': strcpy(p,">");p+=2;break; case '?': strcpy(p,"?");p+=2;break; case '@': strcpy(p,"@");p+=2;break; case 'A': strcpy(p,"A");p+=2;break; case 'B': strcpy(p,"B");p+=2;break; case 'C': strcpy(p,"C");p+=2;break; case 'D': strcpy(p,"D");p+=2;break; case 'E': strcpy(p,"E");p+=2;break; case 'F': strcpy(p,"F");p+=2;break; case 'G': strcpy(p,"G");p+=2;break; case 'H': strcpy(p,"H");p+=2;break; case 'I': strcpy(p,"I");p+=2;break; case 'J': strcpy(p,"J");p+=2;break; case 'K': strcpy(p,"K");p+=2;break; case 'L': strcpy(p,"L");p+=2;break; case 'M': strcpy(p,"M");p+=2;break; case 'N': strcpy(p,"N");p+=2;break; case 'O': strcpy(p,"O");p+=2;break; case 'P': strcpy(p,"P");p+=2;break; case 'Q': strcpy(p,"Q");p+=2;break; case 'R': strcpy(p,"R");p+=2;break; case 'S': strcpy(p,"S");p+=2;break; case 'T': strcpy(p,"T");p+=2;break; case 'U': strcpy(p,"U");p+=2;break; case 'V': strcpy(p,"V");p+=2;break; case 'W': strcpy(p,"W");p+=2;break; case 'X': strcpy(p,"X");p+=2;break; case 'Y': strcpy(p,"Y");p+=2;break; case 'Z': strcpy(p,"Z");p+=2;break; case '[': strcpy(p,"[");p+=2;break; case '\\': strcpy(p,"¥");p+=2;break; case ']': strcpy(p,"]");p+=2;break; case '^': strcpy(p,"^");p+=2;break; case '_': strcpy(p,"_");p+=2;break; case '`': strcpy(p,"‘");p+=2;break; case 'a': strcpy(p,"a");p+=2;break; case 'b': strcpy(p,"b");p+=2;break; case 'c': strcpy(p,"c");p+=2;break; case 'd': strcpy(p,"d");p+=2;break; case 'e': strcpy(p,"e");p+=2;break; case 'f': strcpy(p,"f");p+=2;break; case 'g': strcpy(p,"g");p+=2;break; case 'h': strcpy(p,"h");p+=2;break; case 'i': strcpy(p,"i");p+=2;break; case 'j': strcpy(p,"j");p+=2;break; case 'k': strcpy(p,"k");p+=2;break; case 'l': strcpy(p,"l");p+=2;break; case 'm': strcpy(p,"m");p+=2;break; case 'n': strcpy(p,"n");p+=2;break; case 'o': strcpy(p,"o");p+=2;break; case 'p': strcpy(p,"p");p+=2;break; case 'q': strcpy(p,"q");p+=2;break; case 'r': strcpy(p,"r");p+=2;break; case 's': strcpy(p,"s");p+=2;break; case 't': strcpy(p,"t");p+=2;break; case 'u': strcpy(p,"u");p+=2;break; case 'v': strcpy(p,"v");p+=2;break; case 'w': strcpy(p,"w");p+=2;break; case 'x': strcpy(p,"x");p+=2;break; case 'y': strcpy(p,"y");p+=2;break; case 'z': strcpy(p,"z");p+=2;break; case '{': strcpy(p,"{");p+=2;break; case '|': strcpy(p,"|");p+=2;break; case '}': strcpy(p,"}");p+=2;break; default: *p=*ptr; p++; *p='\0'; break; } } strcpy(str,buf); free(buf); return(0); } int zen2han(char *str) { char *buf,*p,*ptr; buf=(char *)calloc(strlen(str)+1,sizeof(char)); for(ptr=str,p=buf;*ptr!='\0';*ptr++){ if(strncmp(ptr," ",2)==0){*p=' ';p++;ptr++;} else if(strncmp(ptr,"!",2)==0){*p='!';p++;ptr++;} else if(strncmp(ptr,"”",2)==0){*p='"';p++;ptr++;} else if(strncmp(ptr,"#",2)==0){*p='#';p++;ptr++;} else if(strncmp(ptr,"$",2)==0){*p='$';p++;ptr++;} else if(strncmp(ptr,"%",2)==0){*p='%';p++;ptr++;} else if(strncmp(ptr,"&",2)==0){*p='&';p++;ptr++;} else if(strncmp(ptr,"’",2)==0){*p='\'';p++;ptr++;} else if(strncmp(ptr,"(",2)==0){*p='(';p++;ptr++;} else if(strncmp(ptr,")",2)==0){*p=')';p++;ptr++;} else if(strncmp(ptr,"*",2)==0){*p='*';p++;ptr++;} else if(strncmp(ptr,"+",2)==0){*p='+';p++;ptr++;} else if(strncmp(ptr,",",2)==0){*p=',';p++;ptr++;} else if(strncmp(ptr,"−",2)==0){*p='-';p++;ptr++;} else if(strncmp(ptr,".",2)==0){*p='.';p++;ptr++;} else if(strncmp(ptr,"/",2)==0){*p='/';p++;ptr++;} else if(strncmp(ptr,"0",2)==0){*p='0';p++;ptr++;} else if(strncmp(ptr,"1",2)==0){*p='1';p++;ptr++;} else if(strncmp(ptr,"2",2)==0){*p='2';p++;ptr++;} else if(strncmp(ptr,"3",2)==0){*p='3';p++;ptr++;} else if(strncmp(ptr,"4",2)==0){*p='4';p++;ptr++;} else if(strncmp(ptr,"5",2)==0){*p='5';p++;ptr++;} else if(strncmp(ptr,"6",2)==0){*p='6';p++;ptr++;} else if(strncmp(ptr,"7",2)==0){*p='7';p++;ptr++;} else if(strncmp(ptr,"8",2)==0){*p='8';p++;ptr++;} else if(strncmp(ptr,"9",2)==0){*p='9';p++;ptr++;} else if(strncmp(ptr,":",2)==0){*p=':';p++;ptr++;} else if(strncmp(ptr,";",2)==0){*p=';';p++;ptr++;} else if(strncmp(ptr,"<",2)==0){*p='<';p++;ptr++;} else if(strncmp(ptr,"=",2)==0){*p='=';p++;ptr++;} else if(strncmp(ptr,">",2)==0){*p='>';p++;ptr++;} else if(strncmp(ptr,"?",2)==0){*p='?';p++;ptr++;} else if(strncmp(ptr,"@",2)==0){*p='@';p++;ptr++;} else if(strncmp(ptr,"A",2)==0){*p='A';p++;ptr++;} else if(strncmp(ptr,"B",2)==0){*p='B';p++;ptr++;} else if(strncmp(ptr,"C",2)==0){*p='C';p++;ptr++;} else if(strncmp(ptr,"D",2)==0){*p='D';p++;ptr++;} else if(strncmp(ptr,"E",2)==0){*p='E';p++;ptr++;} else if(strncmp(ptr,"F",2)==0){*p='F';p++;ptr++;} else if(strncmp(ptr,"G",2)==0){*p='G';p++;ptr++;} else if(strncmp(ptr,"H",2)==0){*p='H';p++;ptr++;} else if(strncmp(ptr,"I",2)==0){*p='I';p++;ptr++;} else if(strncmp(ptr,"J",2)==0){*p='J';p++;ptr++;} else if(strncmp(ptr,"K",2)==0){*p='K';p++;ptr++;} else if(strncmp(ptr,"L",2)==0){*p='L';p++;ptr++;} else if(strncmp(ptr,"M",2)==0){*p='M';p++;ptr++;} else if(strncmp(ptr,"N",2)==0){*p='N';p++;ptr++;} else if(strncmp(ptr,"O",2)==0){*p='O';p++;ptr++;} else if(strncmp(ptr,"P",2)==0){*p='P';p++;ptr++;} else if(strncmp(ptr,"Q",2)==0){*p='Q';p++;ptr++;} else if(strncmp(ptr,"R",2)==0){*p='R';p++;ptr++;} else if(strncmp(ptr,"S",2)==0){*p='S';p++;ptr++;} else if(strncmp(ptr,"T",2)==0){*p='T';p++;ptr++;} else if(strncmp(ptr,"U",2)==0){*p='U';p++;ptr++;} else if(strncmp(ptr,"V",2)==0){*p='V';p++;ptr++;} else if(strncmp(ptr,"W",2)==0){*p='W';p++;ptr++;} else if(strncmp(ptr,"X",2)==0){*p='X';p++;ptr++;} else if(strncmp(ptr,"Y",2)==0){*p='Y';p++;ptr++;} else if(strncmp(ptr,"Z",2)==0){*p='Z';p++;ptr++;} else if(strncmp(ptr,"[",2)==0){*p='[';p++;ptr++;} else if(strncmp(ptr,"¥",2)==0){*p='\\';p++;ptr++;} else if(strncmp(ptr,"]",2)==0){*p=']';p++;ptr++;} else if(strncmp(ptr,"^",2)==0){*p='^';p++;ptr++;} else if(strncmp(ptr,"_",2)==0){*p='_';p++;ptr++;} else if(strncmp(ptr,"‘",2)==0){*p='`';p++;ptr++;} else if(strncmp(ptr,"a",2)==0){*p='a';p++;ptr++;} else if(strncmp(ptr,"b",2)==0){*p='b';p++;ptr++;} else if(strncmp(ptr,"c",2)==0){*p='c';p++;ptr++;} else if(strncmp(ptr,"d",2)==0){*p='d';p++;ptr++;} else if(strncmp(ptr,"e",2)==0){*p='e';p++;ptr++;} else if(strncmp(ptr,"f",2)==0){*p='f';p++;ptr++;} else if(strncmp(ptr,"g",2)==0){*p='g';p++;ptr++;} else if(strncmp(ptr,"h",2)==0){*p='h';p++;ptr++;} else if(strncmp(ptr,"i",2)==0){*p='i';p++;ptr++;} else if(strncmp(ptr,"j",2)==0){*p='j';p++;ptr++;} else if(strncmp(ptr,"k",2)==0){*p='k';p++;ptr++;} else if(strncmp(ptr,"l",2)==0){*p='l';p++;ptr++;} else if(strncmp(ptr,"m",2)==0){*p='m';p++;ptr++;} else if(strncmp(ptr,"n",2)==0){*p='n';p++;ptr++;} else if(strncmp(ptr,"o",2)==0){*p='o';p++;ptr++;} else if(strncmp(ptr,"p",2)==0){*p='p';p++;ptr++;} else if(strncmp(ptr,"q",2)==0){*p='q';p++;ptr++;} else if(strncmp(ptr,"r",2)==0){*p='r';p++;ptr++;} else if(strncmp(ptr,"s",2)==0){*p='s';p++;ptr++;} else if(strncmp(ptr,"t",2)==0){*p='t';p++;ptr++;} else if(strncmp(ptr,"u",2)==0){*p='u';p++;ptr++;} else if(strncmp(ptr,"v",2)==0){*p='v';p++;ptr++;} else if(strncmp(ptr,"w",2)==0){*p='w';p++;ptr++;} else if(strncmp(ptr,"x",2)==0){*p='x';p++;ptr++;} else if(strncmp(ptr,"y",2)==0){*p='y';p++;ptr++;} else if(strncmp(ptr,"z",2)==0){*p='z';p++;ptr++;} else if(strncmp(ptr,"{",2)==0){*p='{';p++;ptr++;} else if(strncmp(ptr,"|",2)==0){*p='|';p++;ptr++;} else if(strncmp(ptr,"}",2)==0){*p='}';p++;ptr++;} else{ *p=*ptr; p++; } } strcpy(str,buf); free(buf); return(0); }
zen2han(),han2zen()とも文字列をただ渡すだけです。ただし、返答も同じアドレスを書き換えて行いますので、文字列バッファのサイズは十分に気を付けてください。基本的にzen2han()は長くなりませんが、han2zen()は最大で2倍の長さになります。han2zen()はまあまあ速度的にも良いと思いますが、zen2han()はstrncmp()を呼びまくるので遅いです。もっとも最近はコンピューターの速度が速いので下手に速度を上げて移植性を下げるよりも賢いかも知れません。
なお、このようなソースを作る際にいちいち全部キーを入力するようでは疲れてしまいます。少なくともASCII文字などはソースの雛形を作るような簡単なプログラムを作って楽をしましょう。
まとめ
こんな課題はつまらん、といわれてしまうかもしれませんが、このソースはSJIS,EUCでは動きますが、JISでは動かない、ということなどちゃんと気がつきましたか?簡単な物こそしっかりと自分で理解しているライブラリが役に立つものです。このようなライブラリをしっかり自分で持っていれば依頼主からの「こんなの簡単でしょ」攻撃も難なく「もちろん」と答えられるようになります。
※SJISの場合、han2zen()でswitch文の前にSJIS1バイト目だったらスキップする処理を入れないと文字化けになります。SJIS2バイト目はASCIIと重なりますので。
#define issjiskanji(c) ((0x81 <= (unsigned char)(c&0xff) && (unsigned char)(c&0xff) <= 0x9f) \ || (0xe0 <= (unsigned char)(c&0xff) && (unsigned char)(c&0xff) <= 0xfc)) とデファインしておいて、 for(ptr=str,p=buf;*ptr!='\0';*ptr++){ if(issjiskanji(*ptr)){ /* SJIS漢字1バイト目の場合 */ *p=*ptr; p++; ptr++; *p=*ptr; p++; *p='\0'; continue; } switch((int)*ptr){ case ' ': strcpy(p," ");p+=2;break; case '!': strcpy(p,"!");p+=2;break;