先日の文字列をインプレイスで反転させるコードは、ASCII文字専用でした。
軽量言語では str.reverse() みたいな感じで多バイト文字でも簡単に反転できますが、C/C++ でやるとなると、かなり難しいです(私にとっては)。
まず、文字コードの判定から始まって、1バイト文字と多バイト文字の混在にも配慮しないといけないし、Shift_JISなどは2バイト目に’5C’が来るいわゆるダメ文字もあったりして、非常に厄介です。
まあ、しかし頭の体操には丁度よいのではないかということで、ぼちぼち書いてみたのが以下のコードです。
#include <stdlib.h> char * revStr( char * str ){ int len = strlen( str ); char *buf; buf = (char *)malloc(sizeof(str)); int j = 0; for( int i = len-1; i >= 0; i-- ){ if (str[i]>=(char)0x00 && str[i]<(char)0x7F) { buf[j] = str[i]; j += 1; }else if(str[i]>=(char)0xC2 && str[i]<=(char)0xDF){ buf[j] = str[i]; buf[j+1] = str[i+1]; j += 2; }else if(str[i]>=(char)0xE0 && str[i]<=(char)0xEF){ buf[j]= str[i]; buf[j+1] = str[i+1]; buf[j+2] = str[i+2]; j += 3; }else if(str[i]>=(char)0xF0 && str[i]<=(char)0xF4){ buf[j]= str[i]; buf[j+1] = str[i+1]; buf[j+2] = str[i+2]; buf[j+3] = str[i+3]; j += 4; } } buf[j] = ''; return buf; } int main () { char *str = revStr("グンミーチャ デー リブラ!"); printf("%s", str); free(str); return 0; }
文字コードはUTF-8に決め打ちです。と言うのも、UTF-8は先頭が0x00…0x7Fだったら1バイト、0xC2…0xDFなら2バイトというふうに確定できるので、扱いやすいのです。そのかわり、仮名・漢字は1文字で3バイト、一部の記号は4バイトだったりします。
インプレイスを維持するのはさすがに無理でした。普通にバッファを確保しています。
—
次に Objective-C というか、Cocoa フレームワークを使ってみました。若干非効率になってしまってますが、バイト数だのに煩わされなくていいのでラクですね。
#import <Foundation/Foundation.h> int main (int argc, const char * argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init]; NSMutableString *str = [NSMutableString stringWithString:@"まにわしらさぎ"]; NSString *tmp; int len = [str length]; for( int i = 0; i < len/2; i++ ){ tmp = [str substringWithRange:NSMakeRange(i,1)]; [str replaceCharactersInRange:NSMakeRange(i,1) withString:[str substringWithRange:NSMakeRange(len-i-1,1)]]; [str replaceCharactersInRange:NSMakeRange(len-i-1,1) withString:tmp]; } NSLog(@"%@", str); [pool drain]; return 0; }