Latin9 文字セットでフォーマットされたいくつかの文字列を UTF-8 に変換する必要があります。組み込みシステムに含まれていないため、iconv を使用できません。利用可能なコードがあるかどうか知っていますか?
2 に答える
コード ポイント1
は127
、Latin-9 (ISO-8859-15) と UTF-8 の両方で同じです。
Latin-9 のコード ポイントは U+20AC、 UTF-8 では164
\xe2\x82\xac =です。
Latin-9 のコード ポイントは U+0160、\xc5\xa0 = UTF-8 です。
Latin-9 のコード ポイントは U+0161、\xc5\xa1 = UTF-8 です。
Latin-9 のコード ポイントは U+017D、\xc5\xbd = UTF-8 です。
Latin-9 のコード ポイントは U+017E、UTF-8 では \xc5\xbe = です。
Latin-9 のコード ポイントは U+0152、\xc5\x92 = UTF-8 です。
Latin-9 のコード ポイントは U+0153、\xc5\x93 = UTF-8 です。
Latin-9 のコード ポイントは U+0178、\xc5\xb8 = UTF-8 です。226 130 172
166
197 160
168
197 161
180
197 189
184
197 190
188
197 146
189
197 147
190
197 184
Latin-9 のコード ポイント128 .. 191
(上に挙げたものを除く) はすべて \xc2\x80 .. \xc2\xbf = 194 128 .. 194 191
UTF-8 にマップされます。
Latin-9 のコード ポイント192 .. 255
はすべて \xc3\x80 .. \xc3\xbf = 195 128 .. 195 191
UTF-8 にマップされます。
これは、Latin-9 コード ポイント 1..127 が UTF-8 で 1 バイト長、コード ポイント 164 が 3 バイト長、残り (128..163 および 165..255) が 2 バイト長であることを意味します。
最初に Latin-9 入力文字列をスキャンすると、結果の UTF-8 文字列の長さを判断できます。必要に応じて、組み込みシステムで作業している場合は、最後から最初に向かって逆方向に作業することで、その場で変換を行うことができます。
編集:
どちらの方法でも変換に使用できる 2 つの関数を次に示します。これらは、使用後に必要な動的に割り当てられたコピーを返しfree()
ます。NULL
エラーが発生した場合にのみ返されます (メモリ不足、 errno == ENOMEM
)。NULL
変換元の または空の文字列が指定された場合、関数は動的に割り当てられた空の文字列を返します。
つまり、これらの関数を使い終わったら、常にfree()
これらの関数によって返されるポインターを呼び出す必要があります。(free(NULL)
許可され、何もしません。)
は、入力にゼロ バイトが含まれていない場合latin9_to_utf8()
とまったく同じ出力を生成することが確認されています。iconv
この関数は標準の C 文字列を使用します。つまり、0 バイトは文字列の終わりを示します。
は、入力に ISO-8859-15 の Unicode コード ポイントのみが含まれ、ゼロ バイトがない場合とutf8_to_latin9()
まったく同じ出力を生成することが確認されています。iconv
ランダムな UTF-8 文字列が与えられると、この関数は、Latin-1 の 8 つのコード ポイントを Latin-9 の同等のものにマップします。つまり、通貨記号をユーロにマップします。iconv はそれらを無視するか、それらのエラーを考慮します。
この動作は、関数が-> ->および-> ->往復の両方utf8_to_latin9()
に適していることを意味します。 Latin 1
UTF-8
Latin 1
Latin 9
UTF-8
Latin9
#include <stdlib.h> /* for realloc() and free() */
#include <string.h> /* for memset() */
#include <errno.h> /* for errno */
/* Create a dynamically allocated copy of string,
* changing the encoding from ISO-8859-15 to UTF-8.
*/
char *latin9_to_utf8(const char *const string)
{
char *result;
size_t n = 0;
if (string) {
const unsigned char *s = (const unsigned char *)string;
while (*s)
if (*s < 128) {
s++;
n += 1;
} else
if (*s == 164) {
s++;
n += 3;
} else {
s++;
n += 2;
}
}
/* Allocate n+1 (to n+7) bytes for the converted string. */
result = malloc((n | 7) + 1);
if (!result) {
errno = ENOMEM;
return NULL;
}
/* Clear the tail of the string, setting the trailing NUL. */
memset(result + (n | 7) - 7, 0, 8);
if (n) {
const unsigned char *s = (const unsigned char *)string;
unsigned char *d = (unsigned char *)result;
while (*s)
if (*s < 128) {
*(d++) = *(s++);
} else
if (*s < 192) switch (*s) {
case 164: *(d++) = 226; *(d++) = 130; *(d++) = 172; s++; break;
case 166: *(d++) = 197; *(d++) = 160; s++; break;
case 168: *(d++) = 197; *(d++) = 161; s++; break;
case 180: *(d++) = 197; *(d++) = 189; s++; break;
case 184: *(d++) = 197; *(d++) = 190; s++; break;
case 188: *(d++) = 197; *(d++) = 146; s++; break;
case 189: *(d++) = 197; *(d++) = 147; s++; break;
case 190: *(d++) = 197; *(d++) = 184; s++; break;
default: *(d++) = 194; *(d++) = *(s++); break;
} else {
*(d++) = 195;
*(d++) = *(s++) - 64;
}
}
/* Done. Remember to free() the resulting string when no longer needed. */
return result;
}
/* Create a dynamically allocated copy of string,
* changing the encoding from UTF-8 to ISO-8859-15.
* Unsupported code points are ignored.
*/
char *utf8_to_latin9(const char *const string)
{
size_t size = 0;
size_t used = 0;
unsigned char *result = NULL;
if (string) {
const unsigned char *s = (const unsigned char *)string;
while (*s) {
if (used >= size) {
void *const old = result;
size = (used | 255) + 257;
result = realloc(result, size);
if (!result) {
if (old)
free(old);
errno = ENOMEM;
return NULL;
}
}
if (*s < 128) {
result[used++] = *(s++);
continue;
} else
if (s[0] == 226 && s[1] == 130 && s[2] == 172) {
result[used++] = 164;
s += 3;
continue;
} else
if (s[0] == 194 && s[1] >= 128 && s[1] <= 191) {
result[used++] = s[1];
s += 2;
continue;
} else
if (s[0] == 195 && s[1] >= 128 && s[1] <= 191) {
result[used++] = s[1] + 64;
s += 2;
continue;
} else
if (s[0] == 197 && s[1] == 160) {
result[used++] = 166;
s += 2;
continue;
} else
if (s[0] == 197 && s[1] == 161) {
result[used++] = 168;
s += 2;
continue;
} else
if (s[0] == 197 && s[1] == 189) {
result[used++] = 180;
s += 2;
continue;
} else
if (s[0] == 197 && s[1] == 190) {
result[used++] = 184;
s += 2;
continue;
} else
if (s[0] == 197 && s[1] == 146) {
result[used++] = 188;
s += 2;
continue;
} else
if (s[0] == 197 && s[1] == 147) {
result[used++] = 189;
s += 2;
continue;
} else
if (s[0] == 197 && s[1] == 184) {
result[used++] = 190;
s += 2;
continue;
}
if (s[0] >= 192 && s[0] < 224 &&
s[1] >= 128 && s[1] < 192) {
s += 2;
continue;
} else
if (s[0] >= 224 && s[0] < 240 &&
s[1] >= 128 && s[1] < 192 &&
s[2] >= 128 && s[2] < 192) {
s += 3;
continue;
} else
if (s[0] >= 240 && s[0] < 248 &&
s[1] >= 128 && s[1] < 192 &&
s[2] >= 128 && s[2] < 192 &&
s[3] >= 128 && s[3] < 192) {
s += 4;
continue;
} else
if (s[0] >= 248 && s[0] < 252 &&
s[1] >= 128 && s[1] < 192 &&
s[2] >= 128 && s[2] < 192 &&
s[3] >= 128 && s[3] < 192 &&
s[4] >= 128 && s[4] < 192) {
s += 5;
continue;
} else
if (s[0] >= 252 && s[0] < 254 &&
s[1] >= 128 && s[1] < 192 &&
s[2] >= 128 && s[2] < 192 &&
s[3] >= 128 && s[3] < 192 &&
s[4] >= 128 && s[4] < 192 &&
s[5] >= 128 && s[5] < 192) {
s += 6;
continue;
}
s++;
}
}
{
void *const old = result;
size = (used | 7) + 1;
result = realloc(result, size);
if (!result) {
if (old)
free(old);
errno = ENOMEM;
return NULL;
}
memset(result + used, 0, size - used);
}
return (char *)result;
}
は一般に文字セット変換の正しい解決策ですが、上記iconv()
の 2 つの関数は組み込み環境やその他の制約のある環境で確かに役立ちます。
128-255 latin9 コードからバイトの UTF-8 シーケンスへの変換テーブルを作成するのは比較的簡単です。iconv を使用してこれを行うこともできます。または、128-255 latin9 コードでファイルを作成し、適切なテキスト エディターを使用して UTF-8 に変換することもできます。次に、このデータを使用して変換テーブルを作成できます。