ページ 1 / 1
(c言語)全角記号を半角記号にしたい
Posted: 2018年10月12日(金) 17:28
by Timi116
初めて質問さてていただきます。
c言語である文字列中の全角の記号(-,"など)を半角(-,")のように変換させるプログラムが組みたいのですがやり方がわからず困っています。1文字ずつ比較して置き換える方法(char c; if(c=='-')c='-';のような感じ)でやってみたんですけど上手く行きません。どのように書けば良いでしょうか?よろしくお願いします。
Re: (c言語)全角記号を半角記号にしたい
Posted: 2018年10月13日(土) 08:48
by あたっしゅ
失敗しているプログラムを見せてください。
Re: (c言語)全角記号を半角記号にしたい
Posted: 2018年10月13日(土) 10:32
by Timi116
コード:
#include<stdio.h>
#include<string.h>
int main()
{
char filename[FILENAME_MAX];
char buffer;
FILE *fp;
printf("ファイル名を入力してください:");
scanf("%s",filename);
if((fp=fopen(filename,"r"))==NULL){
printf("ファイルが見つかりません");
return -1;
}
while ((buffer = fgetc(fp)) != EOF) {
if (buffer == '−')buffer = '-';
if (buffer == '”')buffer = '"';
printf("%c", buffer);
}
fclose(fp);
return 0;
}
ファイルから読み込む形式にしたいのでこんな感じです。
Re: (c言語)全角記号を半角記号にしたい
Posted: 2018年10月13日(土) 10:37
by かずま
フォーラムルールに従って、質問してください。
文字コードに関するプログラミングは、
環境(OS やコンパイラ)に依存するからです。
ソースコード上の全角文字が Shift-JIS か Unicode(UTF-8) か
によって、コンパイル方法が変わったりもします。
Re: (c言語)全角記号を半角記号にしたい
Posted: 2018年10月13日(土) 12:02
by Timi116
コンパイラはモバイルCというスマホのやつを使ってます。osはAndroidです。文字コードはUTF-8です
Re: (c言語)全角記号を半角記号にしたい
Posted: 2018年10月13日(土) 13:11
by かずま
次のコードでいかがでしょうか?
こちらには、モバイルC がないので確認できません。
コード:
#include <stdio.h> // printf, scanf
#include <wchar.h> // fgetwc, putwchar
#include <locale.h> // setlocale
int main(void)
{
char filename[FILENAME_MAX];
wchar_t buffer;
FILE *fp;
setlocale(LC_ALL, "");
printf("ファイル名を入力してください:");
scanf("%s", filename);
if ((fp = fopen(filename, "r")) == NULL) {
printf("ファイルが見つかりません");
return -1;
}
while ((buffer = fgetwc(fp)) != WEOF) {
if (buffer == L'-') buffer = L'-';
if (buffer == L'"') buffer = L'"';
putwchar(buffer);
}
fclose(fp);
return 0;
}
元のプログラムがなぜダメだったのか分かりますか?
Re: (c言語)全角記号を半角記号にしたい
Posted: 2018年10月13日(土) 15:21
by Timi116
そちらのコード試してみたのですが、エラーは出なかったのですが、文字が出力されませんでした。
かずま さんが書きました: ↑6年前
元のプログラムがなぜダメだったのか分かりますか?
たぶんですが、buffer==’-’というところがうまく動いていないのが原因だと思うので、-のサイズが
通常のchar型のサイズと違うため比較が出来なかったのではと思っているのですが、どうでしょうか。
Re: (c言語)全角記号を半角記号にしたい
Posted: 2018年10月14日(日) 01:26
by かずま
Timi116 さんが書きました: ↑6年前
そちらのコード試してみたのですが、エラーは出なかったのですが、文字が出力されませんでした。
どんな入力を与えたのですか?
不具合を報告するときは、具体的な情報を示してください。
入力のすべての文字が出力されなかったのか、
半角の - や " が出力されなかったのか、などを含めて。
元のプログラムのダメだった理由は、char が 1バイトだからです。
通常の半角文字は1バイトですが、全角文字は 2~3バイトになります。
そして、fgetc は、1バイトを読み込む関数です。
次のテストプログラムでどのように表示されますか?
コード:
#include <stdio.h>
int main(void)
{
const char s[] = """;
unsigned char c;
for (const char *p = s; c = *p; p++) printf(" %02x", c);
putchar('\n');
printf("%08x\n", '"');
printf("%04x\n", L'"');
}
私は次のような結果を予想しています。
コード:
ef bc 82
00efbc82
ff02
さて、wchar_t を使ってだめなら、次のコードはどうでしょうか?
コード:
#include <stdio.h> // printf, scanf, fgets, fputs
#include <string.h> // strncmp, memcpy
int mb_len(const char *p)
{
unsigned char b = *p;
if (b < 0x80) return 1;
if (b < 0xe0) return 2;
if (b < 0xf0) return 3;
if (b < 0xf8) return 4;
if (b < 0xfc) return 5;
return 6;
}
int main()
{
char filename[FILENAME_MAX];
FILE *fp;
char s1[1024], s2[1024];
int len1 = mb_len("-");
int len2 = mb_len(""");
printf("ファイル名を入力してください:");
scanf("%s", filename);
if ((fp = fopen(filename, "r")) == NULL) {
printf("ファイルが見つかりません");
return -1;
}
while (fgets(s1, sizeof s1, fp)) {
char *p1 = s1, *p2 = s2;
while (*p1) {
printf(" %02x", *p1 & 0xff);
int len = mb_len(p1);
printf("len = %d, len1=%d, len2=%d\n", len, len1, len2);
if (!strncmp(p1, "-", len1)) *p2++ = '-';
else if (!strncmp(p1, """, len2)) *p2++ = '"';
else memcpy(p2, p1, len), p2 += len;
p1 += len;
}
*p2 = 0;
fputs(s2, stdout);
}
fclose(fp);
return 0;
}
Re: (c言語)全角記号を半角記号にしたい
Posted: 2018年10月14日(日) 01:29
by かずま
かずま さんが書きました: ↑6年前
コード:
while (fgets(s1, sizeof s1, fp)) {
char *p1 = s1, *p2 = s2;
while (*p1) {
printf(" %02x", *p1 & 0xff);
int len = mb_len(p1);
printf("len = %d, len1=%d, len2=%d\n", len, len1, len2);
この 2つの printf は、デバッグに使ったものなので削除してください。
Re: (c言語)全角記号を半角記号にしたい
Posted: 2018年10月14日(日) 15:20
by Timi116
かずま さんが書きました: ↑6年前
どんな入力を与えたのですか?
不具合を報告するときは、具体的な情報を示してください。
入力のすべての文字が出力されなかったのか、
半角の - や " が出力されなかったのか、などを含めて。
ファイルの中身は、
です。どの文字も出力はされませんでした。
送っていただいたコードで実行してみたところ無事動作しました。ありがとうございます!
動作はなんとなく分かるのですが、解説いただけるとありがたいです。
Re: (c言語)全角記号を半角記号にしたい
Posted: 2018年10月14日(日) 20:23
by かずま
UTF-8 は多バイト文字(multi-byte character) です。
コード:
1バイト文字
\t \n 09 0a
!"#...-./ 21 22 23 ... 2d 2e 2f
012...9 30 31 32 ... 39
ABC...Z 41 42 43 ... 5a
abc...z 61 62 63 ... 7a
2バイト文字
¢£ c2 a2 c2 a3
αβγ ce b1 ce b2 ce b3
3バイト文字
あいう e3 81 82 e3 81 84 e3 81 86
漢字 e6 bc a2 e5 ad 97
次のような構造です。
コード:
00 - 7f 1バイト文字
80 - bf 多バイト文字の後続バイト
c0 - df 2バイトの先頭バイト
e0 - ef 3バイトの先頭バイト
f0 - f7 4バイトの先頭バイト
f8 - fb 5バイトの先頭バイト
fc - fd 6バイトの先頭バイト
これにより 1文字のバイト数が分かります。
"abあcd\n" を fgets で読み込むと、
char s1[] = { 0x61, 0x62, 0xe3, 0x81, 0x82, 0x63, 0x64, 0x0a, 0x00 };
char *p1 でこの中を指しながら、mb_len で求めたバイト長ずつ進めていけば
1文字ずつ参照できます。
strncmp(p1, "あ", 3) で比較すれば、"あ" かどうか分かります。
"あ" だったら、変換したい文字を p2 の指すところにコピーすればよい。
そうでなければ、p1 の指す文字を p2 の指すところにコピーすればよい。
char s2[1024]; に変換結果が入るので、それを出力します。
Re: (c言語)全角記号を半角記号にしたい
Posted: 2018年10月15日(月) 21:04
by Timi116
いろいろお手数おかけしました。
ありがとうございました!
Re: (c言語)全角記号を半角記号にしたい
Posted: 2018年10月16日(火) 14:32
by かずま
fgets, fputs の代わりに、fgetc, puthcar を使ってもできますよ。
コード:
#include <stdio.h> // printf, scanf, fgetc, putchar
#include <string.h> // strncmp
int mb_len(const char *p)
{
unsigned char b = *p;
if (b < 0x80) return 1;
if (b < 0xe0) return 2;
if (b < 0xf0) return 3;
if (b < 0xf8) return 4;
if (b < 0xfc) return 5;
return 6;
}
int main()
{
char filename[FILENAME_MAX];
FILE *fp;
char s[3];
printf("ファイル名を入力してください:");
scanf("%s", filename);
if ((fp = fopen(filename, "r")) == NULL) {
printf("ファイルが見つかりません");
return -1;
}
while ((s[0] = fgetc(fp)) != EOF) {
int len = mb_len(s);
if (len == 3) {
s[1] = fgetc(fp), s[2] = fgetc(fp);
if (!strncmp(s, "-", 3)) putchar('-');
else if (!strncmp(s, """, 3)) putchar('"');
else putchar(s[0]), putchar(s[1]), putchar(s[2]);
}
else {
putchar(s[0]);
while (--len > 0) putchar(fgetc(fp));
}
}
fclose(fp);
return 0;
}
#6 の wchar_t を使うプログラムの説明は要りませんか?
また、そのプログラムがモバイルCで正しく動かなかった原因を探る
ため #8 のテストプログラムの実行結果を教えてもらえませんか?
Re: (c言語)全角記号を半角記号にしたい
Posted: 2018年10月16日(火) 15:12
by かずま
ちょっとまずい部分がありました。
次のように修正します。
コード:
int c;
while ((c = fgetc(fp)) != EOF) {
s[0] = c;
int len = mb_len(s);
Re: (c言語)全角記号を半角記号にしたい
Posted: 2018年10月21日(日) 16:00
by Timi116
返信遅れて申し訳ありません。
補足のプログラムもありがとうございます。
#8 のテストプログラムの実行結果では、9行目でエラーが出るので動きません。
Charactor too large for encoding charactor literal type とでます。
wchar_t のプログラムは自分で理解できたので説明は大丈夫です。
それと自分でいろいろやってみたときに、wchar_t の部分をwprintfに変更すると
正常に動いていました。