この記事では、Visual Cを使用して、ShiftJISの全角文字と小文字a-zが混在する文字列から、小文字のa-zのみを大文字に変更するサンプルコードを紹介します。サンプルコードでは、指定された入力ファイルから文字列を読み込み、変換後の文字列を標準出力に表示します。
ソースコード
以下のソースコードは、プログラムに引数としてファイル名を指定し、そのファイルから文字列を読み込んで処理を行います。引数が指定されていない場合は、使用方法を表示します。
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
void convert_to_uppercase(char* str) {
while (*str) {
if ( ( (0x81 <= (unsigned char)*str && (unsigned char)*str <= 0x9F) ||
(0xE0 <= (unsigned char)*str && (unsigned char)*str <= 0xEF)) &&
( (0x40 <= (unsigned char)*(str + 1) && (unsigned char)*(str + 1) <= 0x7E) ||
(0x80 <= (unsigned char)*(str + 1) && (unsigned char)*(str + 1) <= 0xFC)
) ) {
// ShiftJISの全角文字をスキップ
str += 2;
} else if ('a' <= *str && *str <= 'z') {
*str = toupper((unsigned char)*str);
str++;
} else {
str++;
}
}
}
int main(int argc, char* argv[]) {
if (argc != 2) {
printf("Usage: %s <filename>\n", argv[0]);
return 1;
}
FILE* file;
if (fopen_s(&file, argv[1], "r") != 0) {
perror("Could not open file");
return 1;
}
fseek(file, 0, SEEK_END);
long file_size = ftell(file);
fseek(file, 0, SEEK_SET);
if (file_size < 0) {
perror("Invalid file size");
fclose(file);
return 1;
}
char* buffer = (char*)malloc((size_t)file_size + 1);
if (!buffer) {
perror("Could not allocate memory");
fclose(file);
return 1;
}
size_t read_size = fread(buffer, 1, (size_t)file_size, file);
buffer[read_size] = '\0';
fclose(file);
printf("Original: %s\n", buffer);
convert_to_uppercase(buffer);
printf("Converted: %s\n", buffer);
free(buffer);
return 0;
}
ShiftJISの全角文字と小文字a-zが混在する文字列をif (‘a’ <= *str && *str <= ‘z’)の判定のみで対応すると全角文字の2バイトのうち2バイト目に(‘a’ <= *str && *str <= ‘z’)範囲のデータが変更される危険性があります。
テスト用入力ファイル
以下はテスト用入力ファイル(test.txt)の内容です。
[電子データの#小文字abcを試しに&大文字にhen*kouする__sample__データ.]
test.exe test.txtを実行しましとtest.txtの内容が問題なく標準出力として出力されます。
[電子データの#小文字ABCを試しに&大文字にHEN*KOUする__SAMPLE__データ.]
注意事項
変数 *strを char ではなく unsigned char にする必要があります。char
型が符号付き、即ち*strに例えとして0x93
の値が負の値としてセットされている場合、具体的には、0x93
は2の補数表現で -109
となります。これにより、比較が意図した通りに動作しない可能性があります。char が符号付きの場合、特に日本語のShiftJISコード範囲(0x81~0x9F、0xE0~0xEF)を扱うときに問題が発生するためです。
unsigned charではなくcharで判定するようソースを修正した場合、
if ( ( (0x81 <= *str && *str <= 0x9F) ||
(0xE0 <= *str && *str <= 0xEF)) &&
( (0x40 <= *(str + 1) && *(str + 1) <= 0x7E) ||
(0x80 <= *(str + 1) && *(str + 1) <= 0xFC) ) )
入力データ
[電子データの#小文字abcを試しに&大文字にhen*kouする__sample__データ.]
出力結果(NG)
以下のよう文字化けする箇所が発生します。
[泥参ェータの#小文字ABCを試しに&大文字にHEN*KOUする__SAMPLE__ェータ.]
まとめ
Visual Cを使用して、ShiftJISの全角文字と小文字a-zが混在する文字列から、a-zの小文字のみを大文字に変更するサンプルコードを紹介しました。プログラムは、入力ファイルから文字列を読み込み、変換して標準出力に表示します。char 型が符号付きの場合の問題点にも注意が必要です。この記事を参考に、同様の文字列操作を行うプログラムを作成してみてください。
コメント