マルチバイト・ワイド文字の処理
文字列処理
| @@ -0,0 +1,21 @@ | ||
| 1 | +all: libchproc.a example | |
| 2 | + | |
| 3 | +libchproc.a: mbslen.o converter.o | |
| 4 | + ar rcs libchproc.a \ | |
| 5 | + mbslen.o \ | |
| 6 | + converter.o | |
| 7 | + | |
| 8 | +mbslen.o: mbslen.c | |
| 9 | + gcc -c mbslen.c | |
| 10 | + | |
| 11 | +converter.o: converter.c | |
| 12 | + gcc -c converter.c | |
| 13 | + | |
| 14 | +example: example.c libchproc.a | |
| 15 | + gcc -oexample example.c libchproc.a | |
| 16 | + | |
| 17 | +clean: | |
| 18 | + rm -f *.o | |
| 19 | + rm -f libchproc.a | |
| 20 | + rm -f example | |
| 21 | + |
| @@ -0,0 +1,13 @@ | ||
| 1 | +文字列処理のプログラムコードです。 | |
| 2 | + | |
| 3 | +make すると、静的ライブラリ libchproc.a と | |
| 4 | +例題プログラム (example) がビルドされます。 | |
| 5 | +生成物をクリーンアップするには、make clean | |
| 6 | +してください。 | |
| 7 | + | |
| 8 | +* ファイル | |
| 9 | +chproc.h -- ライブラリのためのヘッダファイル | |
| 10 | +mbslen.c -- マルチバイト文字列の文字数を調べる関数 mbslen() | |
| 11 | +converter.c -- マルチバイト、ワイド文字列を相互に変換 | |
| 12 | +example.c -- 関数の使用例 | |
| 13 | + |
| @@ -0,0 +1,12 @@ | ||
| 1 | +#ifndef _CHP_H | |
| 2 | +#define _CHP_H | |
| 3 | + | |
| 4 | +#include <wchar.h> | |
| 5 | + | |
| 6 | +int mbslen(const char *s, size_t *len_r); | |
| 7 | + | |
| 8 | +char* to_mbs(const wchar_t *s); | |
| 9 | +wchar_t* to_wcs(const char *s); | |
| 10 | + | |
| 11 | +#endif /* _CHP_H */ | |
| 12 | + |
| @@ -0,0 +1,114 @@ | ||
| 1 | +/* converter.c | |
| 2 | + * | |
| 3 | + * ワイド文字列をマルチバイト文字列へ、またその逆に、 | |
| 4 | + * 文字列を変換する。 | |
| 5 | + * | |
| 6 | + * マルチバイト、ワイド文字列を相互に変換する際、 | |
| 7 | + * 固定サイズの配列を使わず、必要バイト数を計算し | |
| 8 | + * 動的にメモリを割り当てて変換を行う。 | |
| 9 | + * | |
| 10 | + * 変換された文字列は、malloc() で動的に確保している | |
| 11 | + * ので、使用後は free() で解放する必要がある。 | |
| 12 | + */ | |
| 13 | + | |
| 14 | +#include <stdio.h> | |
| 15 | +#include <stdlib.h> | |
| 16 | +#include <string.h> | |
| 17 | +#include <stdint.h> | |
| 18 | +#include <wchar.h> | |
| 19 | + | |
| 20 | +/* to_mbs() -- ワイド文字列をマルチバイト文字列へ変換する | |
| 21 | + * | |
| 22 | + * 引数 s をマルチバイト文字列へ変換した文字列を返す。 | |
| 23 | + * 何らかのエラーが発生した場合は NULL を返す。 | |
| 24 | + * 返された文字列を使い終わったら free() で解放すること。 | |
| 25 | + * | |
| 26 | + * この関数は wcstombs() を使い動的にメモリを割り当てた | |
| 27 | + * 文字列を生成する例である。 | |
| 28 | + */ | |
| 29 | +char* to_mbs(const wchar_t *s) | |
| 30 | +{ | |
| 31 | + size_t bytes; | |
| 32 | + char *str; | |
| 33 | + | |
| 34 | + // 引数チェック | |
| 35 | + if (s == NULL) | |
| 36 | + return NULL; | |
| 37 | + | |
| 38 | + // wcstombs() の第1引数を NULL にすると、 | |
| 39 | + // マルチバイト文字での長さを返す。 | |
| 40 | + if ((bytes = wcstombs(NULL, s, 0)) == (size_t)-1) | |
| 41 | + return NULL; | |
| 42 | + | |
| 43 | + // 文字長に NUL 文字分の長さを加える | |
| 44 | + // (桁溢れしたらエラーで終了) | |
| 45 | + if ((bytes += 1) < 1) | |
| 46 | + return NULL; | |
| 47 | + | |
| 48 | + // メモリ確保 | |
| 49 | + if ((str = malloc(bytes)) == NULL) | |
| 50 | + return NULL; | |
| 51 | + memset(str, 0, bytes); | |
| 52 | + | |
| 53 | + // 確保したメモリ領域に文字列の変換結果を | |
| 54 | + // 格納する | |
| 55 | + if (wcstombs(str, s, bytes) == (size_t)-1) { | |
| 56 | + free(str); | |
| 57 | + return NULL; | |
| 58 | + } | |
| 59 | + | |
| 60 | + return str; | |
| 61 | +} | |
| 62 | + | |
| 63 | +/* to_wcs() -- マルチバイト文字列をワイド文字列へ変換する | |
| 64 | + * | |
| 65 | + * 引数 s をワイド文字列へ変換した文字列を返す。 | |
| 66 | + * 何らかのエラーが発生した場合は NULL を返す。 | |
| 67 | + * 返された文字列を使い終わったら free() で解放すること。 | |
| 68 | + * | |
| 69 | + * この関数は mbstowcs() を使い動的にメモリを割り当てた | |
| 70 | + * ワイド文字列を生成する例である。 | |
| 71 | + */ | |
| 72 | +wchar_t* to_wcs(const char *s) | |
| 73 | +{ | |
| 74 | + size_t len, bytes; | |
| 75 | + wchar_t *str; | |
| 76 | + | |
| 77 | + // 引数チェック | |
| 78 | + if (s == NULL) | |
| 79 | + return NULL; | |
| 80 | + | |
| 81 | + // mbstowcs() の第1引数を NULL にすると | |
| 82 | + // ワイド文字での文字数を返す | |
| 83 | + if ((len = mbstowcs(NULL, s, 0)) == (size_t)-1) | |
| 84 | + return NULL; | |
| 85 | + | |
| 86 | + // 文字数に NUL 文字分の長さを加える | |
| 87 | + // (桁溢れしたらエラーで終了) | |
| 88 | + if ((len += 1) < 1) | |
| 89 | + return NULL; | |
| 90 | + | |
| 91 | + // 文字数に、1文字のサイズを掛け算して、 | |
| 92 | + // 必要バイト数を計算する。 | |
| 93 | + // ただし、桁溢れ防止のために、 | |
| 94 | + // 表現できる最大文字数に制限する。 | |
| 95 | + // (最大文字数を超えていたらエラーで終了) | |
| 96 | + if (len > (SIZE_MAX / sizeof(wchar_t))) | |
| 97 | + return NULL; | |
| 98 | + bytes = sizeof(wchar_t) * len; | |
| 99 | + | |
| 100 | + // メモリ確保 | |
| 101 | + if ((str = malloc(bytes)) == NULL) | |
| 102 | + return NULL; | |
| 103 | + memset(str, 0, bytes); | |
| 104 | + | |
| 105 | + // 確保したメモリ領域に文字列の変換結果を | |
| 106 | + // 格納する | |
| 107 | + if (mbstowcs(str, s, len) == (size_t)-1) { | |
| 108 | + free(str); | |
| 109 | + return NULL; | |
| 110 | + } | |
| 111 | + | |
| 112 | + return str; | |
| 113 | +} | |
| 114 | + |
| @@ -0,0 +1,60 @@ | ||
| 1 | +/* example.c | |
| 2 | + * | |
| 3 | + * 文字処理の例。 | |
| 4 | + */ | |
| 5 | + | |
| 6 | +#include <stdio.h> | |
| 7 | +#include <stdlib.h> | |
| 8 | +#include <string.h> | |
| 9 | +#include <wchar.h> | |
| 10 | +#include <locale.h> | |
| 11 | +#include "chproc.h" | |
| 12 | + | |
| 13 | +int main() | |
| 14 | +{ | |
| 15 | + char *mbs = "朝から晩まで、Internet"; | |
| 16 | + char *mbs2; | |
| 17 | + wchar_t *ws; | |
| 18 | + wchar_t *ws2 = L"明け方まで、MMORPG"; | |
| 19 | + size_t len; | |
| 20 | + | |
| 21 | + // 初期化処理として、ロケールを設定する必要がある。 | |
| 22 | + if (setlocale(LC_ALL, "") == NULL) { | |
| 23 | + fprintf(stderr, "setlocale() failed.\n"); | |
| 24 | + exit(1); | |
| 25 | + } | |
| 26 | + | |
| 27 | + // マルチバイト文字列の文字数を調べる | |
| 28 | + if (mbslen(mbs, &len)) { | |
| 29 | + fprintf(stderr, "mbslen() failed.\n"); | |
| 30 | + exit(1); | |
| 31 | + } | |
| 32 | + printf("%u\n\n", len); | |
| 33 | + | |
| 34 | + // ワイド文字列に変換する | |
| 35 | + if ((ws = to_wcs(mbs)) == NULL) { | |
| 36 | + fprintf(stderr, "to_wcs() failed.\n"); | |
| 37 | + exit(1); | |
| 38 | + } | |
| 39 | + | |
| 40 | + // ワイド文字列の出力は、%s ではなく %S なので注意! | |
| 41 | + printf("%S\n\n", ws); | |
| 42 | + | |
| 43 | + // メモリ解放 | |
| 44 | + free(ws); | |
| 45 | + | |
| 46 | + // 今度は、ワイド文字列をマルチバイト文字列にする | |
| 47 | + if ((mbs2 = to_mbs(ws2)) == NULL) { | |
| 48 | + fprintf(stderr, "to_mbs() failed.\n"); | |
| 49 | + exit(1); | |
| 50 | + } | |
| 51 | + if (mbslen(mbs2, &len)) { | |
| 52 | + fprintf(stderr, "mbslen() failed.\n"); | |
| 53 | + exit(1); | |
| 54 | + } | |
| 55 | + printf("%u\n\n%s\n", len, mbs2); | |
| 56 | + free(mbs2); | |
| 57 | + | |
| 58 | + return 0; | |
| 59 | +} | |
| 60 | + |
| @@ -0,0 +1,56 @@ | ||
| 1 | +/* mbslen.c | |
| 2 | + * | |
| 3 | + * 関数 mbslen() を作る。 | |
| 4 | + * mbslen() はマルチバイト文字列の文字数を返す。 | |
| 5 | + * strlen() とは異なり文字列の「バイト数」ではなく、 | |
| 6 | + * 「文字数」である。 | |
| 7 | + */ | |
| 8 | + | |
| 9 | +#include <stdio.h> | |
| 10 | +#include <stdlib.h> | |
| 11 | +#include <string.h> | |
| 12 | +#include <wchar.h> | |
| 13 | + | |
| 14 | +/* mbslen() -- マルチバイト文字列の文字数を返す | |
| 15 | + * | |
| 16 | + * s で指定された文字列の文字数を len_r で示される | |
| 17 | + * 場所に格納する。 この関数の返り値は、成功ならば | |
| 18 | + * 0 を、エラーならば 0 以外を返す。 | |
| 19 | + * | |
| 20 | + * この関数は mbrlen() で文字数を調べる例である。 | |
| 21 | + */ | |
| 22 | +int mbslen(const char *s, size_t *len_r) | |
| 23 | +{ | |
| 24 | + size_t r; | |
| 25 | + size_t n = 0; // 文字数 | |
| 26 | + size_t m = 0; // 調べ終わった合計バイト数 | |
| 27 | + mbstate_t state; | |
| 28 | + | |
| 29 | + // 引数チェック | |
| 30 | + if (s == NULL) | |
| 31 | + return 1; // error | |
| 32 | + | |
| 33 | + // 状態初期化 | |
| 34 | + memset(&state, 0, sizeof(mbstate_t)); | |
| 35 | + | |
| 36 | + // mbrlen() で文字数を調べる | |
| 37 | + while (r = mbrlen(&s[m], MB_CUR_MAX, &state)) { | |
| 38 | + | |
| 39 | + // mbrln() の返り値がエラーかどうかチェック | |
| 40 | + if (r == (size_t)-1 || r == (size_t)-2) | |
| 41 | + return 1; // error | |
| 42 | + | |
| 43 | + // 合計バイト数に加算 | |
| 44 | + m += r; | |
| 45 | + | |
| 46 | + // 合計文字数を増やす | |
| 47 | + n++; | |
| 48 | + } | |
| 49 | + | |
| 50 | + // 結果を返す | |
| 51 | + if (len_r != NULL) | |
| 52 | + *len_r = n; | |
| 53 | + | |
| 54 | + return 0; // 正常終了 | |
| 55 | +} | |
| 56 | + |