この章では、文字列の複数バイト表現とワイド文字表現の相互変換のためのインタフェース、および iconv() 汎用コード変換インタフェースを紹介し、その利用方法を説明します。
Solaris では、テキストデータを複数バイト表現 (ファイルコードとも呼ぶ) の形でファイルに格納します。一方、アプリケーションの内部でテキストデータを取り扱う際には、第 2 章「国際化 API での日本語処理」、第 3 章「日本語ロケールと文字分類」で紹介したように、ワイド文字表現 (プロセスコードとも呼ぶ) の形で行うと便利な場合があります。したがって、日本語データを扱うアプリケーションでは複数バイト表現とワイド文字表現の相互変換を行う場面がしばしば生じます。XPG ではこの用途の API を用意しており、アプリケーションでのさまざまな相互変換を支援します。
また、日本語テキストで使用される文字集合は同じでもエンコーディングが異なるために、アプリケーションがテキストデータとして正しく取り扱えない場合があります。アプリケーションが自らの責任でエンコーディングの変換を行うように開発することもできますが、その場合、アプリケーションは変換可能なすべてのエンコーディングに関する情報を含んでいなくてはなりません。また、新しいエンコーディングをサポートする場合には、アプリケーションの再コンパイルが必要になります。
このような事態を避けるためには、コード変換に関するルール、または変換サービスそのものをアプリケーション本体から切り離し、変換前のエンコーディングと変換後のエンコーディングを指定して、動的に変換サービスを呼び出します。XPG ではこの用途の API を用意しており、汎用的なコード変換を支援します。
表 4-1 で主な複数バイト・ワイド文字の相互変換のための API を紹介します。この他、printf(3S)、scanf(3S) などのマニュアルページも参照してください。
表 4-1 複数バイト・ワイド文字相互変換 API|
インタフェース名 |
作用 |
|---|---|
|
mbtowc(pwc,s,n) |
s の先頭から最大 n バイト調べ、複数バイト 1 文字分をワイド文字表現にして pwc へ格納 |
|
mbstowcs(pwcs,s,n) |
s の先頭から複数バイト文字列をワイド文字列に変換する。最大 n ワイド文字変換したら終了 |
|
wctomb(s,wc) |
ワイド文字 wc を複数バイト表現に変換し s へ格納 |
|
wcstombs(s,pwcs,n) |
pwcs からワイド文字列を複数バイト表現に変換しながら s に格納。変換した複数バイトの合計が最大 n バイトになれば終了 |
|
mblen(s,n) |
s の先頭から最大 n バイト調べ複数バイト 1 文字分を構成するバイト数を返す |
|
fgetwc(stream) |
入力ストリームから 1 複数バイト分を読み込みワイド文字表現で返す |
|
ungetwc(wc, stream) |
ワイド文字 wc を stream へプッシュバックする |
|
fgetws(ws,n,stream) |
入力ストリーム stream から複数バイト文字列を読み込み、最大 n-1 ワイド文字分を ws に格納する |
|
fputwc(wc,stream) |
出力ストリーム stream へワイド文字 wc を出力 |
|
fputws(ws,stream) |
出力ストリーム stream へワイド文字列 ws を出力 |
例 4-1 では、あるファイルに対してこれらの API を適用した複数バイト・ワイド文字の相互変換のプログラム例を紹介します。これらの API を使用する場合は、適切なヘッダファイルを取り込むこと (mbtowc()、mbstowcs()、wctomb()、wcstombs()、mblen() は stdlib.h を、ungetwc()、fgetws()、fputwc()、fputws() は wchar.h を取り込む) および setlocale() を処理の最初の段階で呼び出して動作ロケールを適切に設定することが必要です。
sun% cat my_mbwc.c
/*
* Read lines from stdin and
* count the number of chars
* that belong to specific category.
* Counting will stop if input reaches
* EOF. It is assumed that each line
* has at most BUFSIZ - 1 byte length.
*
* To categorize each chars, iswctype()
* is used. Therefore, it is necessary
* to convert the input multibyte buffer
* to the wide char buffer. mbstowcs()
* is called for that purpose.
*/
#include <stdio.h>
#include <locale.h>
#include <stdlib.h>
#include <wchar.h>
static char mbbuf[BUFSIZ];
static wchar_t wcbuf[BUFSIZ];
int
main(int argc, char *argv[])
{
size_t retval;
int i, alpha_char, ideo_char, kana_char, other_char;
setlocale(LC_ALL, "");
alpha_char = ideo_char = kana_char = other_char = 0;
while(fgets(mbbuf, BUFSIZ, stdin) != NULL) {
retval = mbstowcs(wcbuf, mbbuf, BUFSIZ);
if (retval == (size_t)-1) {
fprintf(stderr, "Invalid char is found during mbstowcs()¥n");
exit(-1);
}
retval = wcslen((const wchar_t *)wcbuf);
for (i = 0; i < retval; i++) {
if (iswctype(wcbuf[i], wctype("jisx0201r"))) {
} else if (iswctype(wcbuf[i], wctype("alpha"))) {
alpha_char++;
} else {
other_char++;
}
}
}
fprintf(stdout, "The input consist of¥n");
fprintf(stdout, "%d Alphabetical chars,¥n", alpha_char);
fprintf(stdout, "%d JIS X 0208 Kanji chars,¥n", ideo_char);
fprintf(stdout, "%d JIS X 0201 Kana chars and¥n", kana_char);
fprintf(stdout, "%d other chars.¥n", other_char);
return(0);
}
sun% cc -o my_mbwc my_mbwc.c
sun% cat file6
/* Here's the content of file3 */
新しいシステム*は現在のネットワーク*環境を変えることなく
インターネット*とのシームレス*な接続を可能にします。また
セキュリティ*の問題も新しい認証テクノロジー*を用いることで
アドミニストレータ*の負担を減らしています。
/* Here's the content of file5 */
ひらがなはかたかなに置換されます。
カタカナハヒラガナニ置換サレマス。
漢字、記号、全角alphabetや
JIS X 0201 カナナドハ* 置換 サレマセン*。
sun% ./my_mbwc < file6
The input consist of
54 Alphabetical chars,
31 JIS X 0208 Kanji chars,
56 JIS X 0201 Kana chars and
117 other chars.
* の部分のカタカナは、半角カタカナになります。
汎用コード変換の API は表 4-2 のとおりです。変換前エンコーディングと変換後エンコーディングを指定する名称と指定の意味については iconv_ja(5) のマニュアルページ、および『JFP ユーザーズガイド』の第 6 章「フィルタを用いたコード変換」を参照してください。
表 4-2 汎用コード変換 API|
インタフェース名 |
作用 |
|---|---|
|
iconv_open() |
変換元コードと変換先コードから変換に必要な情報を得る |
|
iconv() |
得られた情報をもとに実際の変換を行う |
|
iconv_open() |
変換に必要だった情報を解放する |
例 4-2 では iconv() インタフェースを用いて iconv(1) コマンドのサブセットに相当するフィルタを作成します。これらの API を使用する場合は、iconv.h ヘッダファイルを取り込むことが必要です。一般的な国際化 API と異なり、iconv() では、変換前、変換後のそれぞれの文字集合およびエンコーディングに関する情報を変換記述子を通して入手します。したがって、次のプログラム例でも setlocale()が呼び出されていないことに注意してください。
sun% cat my_iconv.c
/*
* Read lines from a stdin and convert the encoding.
* It is assumed that each line has at most BUFSIZ - 1
* byte length.
* Both of source and destination encodings are passed
* from the command line.
*
* Note: Calling iconv() itself doesn't need to call
* setlocale() in advance.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <iconv.h>
int
main(int argc, char *argv[])
{
iconv_t icv_hook;
char in_buf[BUFSIZ];
char out_buf[BUFSIZ];
char *inp;
char *outp;
char *from_code;
char *to_code;
extern char *optarg;
extern int optind;
size_t ret_val;
size_t in_buf_left;
size_t out_buf_left;
int i;
if (argc != 5) {
fprintf(stderr, "usage: %s -f -t ¥n", argv[0]);
exit(-1);
}
while ((i = getopt(argc, argv, "f:t:")) != EOF)
switch (i) {
case `f':
from_code = optarg;
break;
case `t':
to_code = optarg;
break;
default:
fprintf(stderr, "usage: %s -f -t ¥n", argv[0]);
exit(-1);
}
icv_hook = iconv_open(to_code, from_code);
if (icv_hook == (iconv_t)-1) {
perror("iconv_open()");
exit(-1);
}
i = 0;
while(fgets(in_buf, BUFSIZ, stdin) != NULL){
if (!in_buf[0]) {
perror("fgets()");
exit(-1);
}
i++;
memset(out_buf, 0, BUFSIZ);
in_buf_left = strlen(in_buf);
out_buf_left = BUFSIZ;
inp = in_buf;
outp = out_buf;
errno = 0;
ret_val = iconv(icv_hook,
(const char **)inp, in_buf_left, outp, out_buf_left);
if (ret_val == (size_t)-1) {
if (errno == EILSEQ)
perror("EILSEQ");
else if (errno == E2BIG)
perror("E2BIG");
else if (errno == EINVAL)
perror("EINVAL");
fprintf(stderr, "Line number is %d¥n", i);
exit(-1);
}
write(STDOUT_FILENO, out_buf, (BUFSIZ - out_buf_left));
}
iconv_close(icv_hook);
return(0);
}
sun% cat file3
新しいシステム*は現在のネットワーク*環境を変えることなく
インターネット*とのシームレス*な接続を可能にします。また
セキュリティ*の問題も新しい認証テクノロジー*を用いることで
アドミニストレータ*の負担を減らしています。
sun% cc -o my_iconv my_iconv.c
sun% cat file3 | ./my_iconv -f eucJP -t PCK | ./my_iconv -f PCK -t eucJP
新しいシステム*は現在のネットワーク*環境を変えることなく
インターネット*とのシームレス*な接続を可能にします。また
セキュリティ*の問題も新しい認証テクノロジー*を用いることで
アドミニストレータ*の負担を減らしています。
* の部分のカタカナは、半角カタカナになります。