(c言語)全角記号を半角記号にしたい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Timi116

(c言語)全角記号を半角記号にしたい

#1

投稿記事 by Timi116 » 1ヶ月前

初めて質問さてていただきます。
c言語である文字列中の全角の記号(-,"など)を半角(-,")のように変換させるプログラムが組みたいのですがやり方がわからず困っています。1文字ずつ比較して置き換える方法(char c; if(c=='-')c='-';のような感じ)でやってみたんですけど上手く行きません。どのように書けば良いでしょうか?よろしくお願いします。

アバター
あたっしゅ
記事: 163
登録日時: 8年前
住所: 東京23区
連絡を取る:

Re: (c言語)全角記号を半角記号にしたい

#2

投稿記事 by あたっしゅ » 1ヶ月前

失敗しているプログラムを見せてください。
手提鞄あたっしゅ、[MrAtassyu] C095 月東L26a 手提鞄屋魚有店(てさげかばんやうおありてん)

Timi116

Re: (c言語)全角記号を半角記号にしたい

#3

投稿記事 by Timi116 » 1ヶ月前

コード:

 
#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言語)全角記号を半角記号にしたい

#4

投稿記事 by かずま » 1ヶ月前

フォーラムルールに従って、質問してください。

文字コードに関するプログラミングは、
環境(OS やコンパイラ)に依存するからです。
ソースコード上の全角文字が Shift-JIS か Unicode(UTF-8) か
によって、コンパイル方法が変わったりもします。

Timi116

Re: (c言語)全角記号を半角記号にしたい

#5

投稿記事 by Timi116 » 1ヶ月前

コンパイラはモバイルCというスマホのやつを使ってます。osはAndroidです。文字コードはUTF-8です

かずま

Re: (c言語)全角記号を半角記号にしたい

#6

投稿記事 by かずま » 1ヶ月前

次のコードでいかがでしょうか?
こちらには、モバイル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;
}
元のプログラムがなぜダメだったのか分かりますか?

Timi116

Re: (c言語)全角記号を半角記号にしたい

#7

投稿記事 by Timi116 » 1ヶ月前

そちらのコード試してみたのですが、エラーは出なかったのですが、文字が出力されませんでした。
かずま さんが書きました:
1ヶ月前
元のプログラムがなぜダメだったのか分かりますか?
たぶんですが、buffer==’-’というところがうまく動いていないのが原因だと思うので、-のサイズが
通常のchar型のサイズと違うため比較が出来なかったのではと思っているのですが、どうでしょうか。

かずま

Re: (c言語)全角記号を半角記号にしたい

#8

投稿記事 by かずま » 1ヶ月前

Timi116 さんが書きました:
1ヶ月前
そちらのコード試してみたのですが、エラーは出なかったのですが、文字が出力されませんでした。
どんな入力を与えたのですか?
不具合を報告するときは、具体的な情報を示してください。
入力のすべての文字が出力されなかったのか、
半角の - や " が出力されなかったのか、などを含めて。

元のプログラムのダメだった理由は、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言語)全角記号を半角記号にしたい

#9

投稿記事 by かずま » 1ヶ月前

かずま さんが書きました:
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);
この 2つの printf は、デバッグに使ったものなので削除してください。

Timi116

Re: (c言語)全角記号を半角記号にしたい

#10

投稿記事 by Timi116 » 1ヶ月前

かずま さんが書きました:
1ヶ月前
どんな入力を与えたのですか?
不具合を報告するときは、具体的な情報を示してください。
入力のすべての文字が出力されなかったのか、
半角の - や " が出力されなかったのか、などを含めて。
ファイルの中身は、

コード:

”abc-defg”
です。どの文字も出力はされませんでした。

送っていただいたコードで実行してみたところ無事動作しました。ありがとうございます!
動作はなんとなく分かるのですが、解説いただけるとありがたいです。

かずま

Re: (c言語)全角記号を半角記号にしたい

#11

投稿記事 by かずま » 1ヶ月前

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]; に変換結果が入るので、それを出力します。

Timi116

Re: (c言語)全角記号を半角記号にしたい

#12

投稿記事 by Timi116 » 1ヶ月前

いろいろお手数おかけしました。
ありがとうございました!

かずま

Re: (c言語)全角記号を半角記号にしたい

#13

投稿記事 by かずま » 1ヶ月前

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言語)全角記号を半角記号にしたい

#14

投稿記事 by かずま » 1ヶ月前

ちょっとまずい部分がありました。
次のように修正します。

コード:

	int c;
	while ((c = fgetc(fp)) != EOF) {
		s[0] = c;
		int len = mb_len(s);

Timi116

Re: (c言語)全角記号を半角記号にしたい

#15

投稿記事 by Timi116 » 3週間前

返信遅れて申し訳ありません。
補足のプログラムもありがとうございます。
#8 のテストプログラムの実行結果では、9行目でエラーが出るので動きません。
Charactor too large for encoding charactor literal type とでます。
wchar_t のプログラムは自分で理解できたので説明は大丈夫です。
それと自分でいろいろやってみたときに、wchar_t の部分をwprintfに変更すると
正常に動いていました。

返信

“C言語何でも質問掲示板” へ戻る