人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

C言語の質問です。

文字列の中に全角スペースで区切った単語が複数あります。
全角スペースを検索することにより、単語ごとに出力したかったのですが上手く動作しませんでした。
出力する単語によっては文字化けが発生します。
文字化けしないようにするにはどうしたらよいでしょうか?
(文字コードはEUCです。)

>||
int main()
{
int i;
char words[100] = "飛行機 電車 train ";
char *pt1, *pt2

pt1 = pt2 = words;

for(i=0; i<3; i++){
pt2 = strstr(pt1, " ")
*pt2 = "\0";

printf("%s\n",pt1);
pt1 = pt2 + 2;
}
return 0;
}
||<

文字列を処理する関数で全角を利用するのに注意が必要であることは調べてわかったのですが、実際にどのように処理すればいいのかが調べきれませんでした。よろしくお願いします。

●質問者: ktoshi
●カテゴリ:コンピュータ
✍キーワード:Char PT2 単語 文字コード 文字列
○ 状態 :終了
└ 回答数 : 8/8件

▽最新の回答へ

1 ● mark_hk
●15ポイント

strstr関数は半角1文字だけ検索するので予想通りに動作しなかったと思います。

解決方法としては

1.文字列の間を「半角スペースにする」

2.pt2 = strstr(pt1, " ")の部分を

int j;

for (j = 0; j < strlen(pt1); ++j) {

if (0 == strncmp(pt1, " ", 2) {

pt2 = pt1;

break;

}

++pt1;

}

という風に全角文字列で比較するように変更する

のどちらかですかね。構造的には1の方が簡単ですね。

◎質問者からの返答

文字列の間はわけあって「全角スペース」しか使えないです。

2の方を明日試してみます。ありがとうございました。


2 ● kazu1107
●5ポイント

このコードをそのまま動かしたらコンパイルすら出来ないと思いますが・・・。

まぁそこら辺は適当に修正して、コンパイルしてみました。

まず修正するべきは、for文の中にある「*pt2 = "\0";」で、これは「*pt2 = '\0';」で意図する結果がでると思います。

動作&コンパイル環境、その状況などがわからないので文字化けについてはコメントしづらいです。

◎質問者からの返答

すみません。

家だとコンパイルする環境を作ってないので、適当にコードを書いてしまいました。

知りたいのは文字化けのとこと、文字列を処理する関数での全角の扱い方ですので、よろしくお願いします。

ありがとうございました。


3 ● くまっぷす
●15ポイント

http://www.ncad.co.jp/~komata/c-kouza21.htm

こちらにstrstrではないですがstrtokを使ってEUCを処理するとハマるパターンについて書かれています。

文字化けするのはEUCのコードの中に0xa1が含まれていて、全角スペース(0xa1a1)と間違ってしまうケースですね。strstrだとたまたま0xa1a1という並びがあると文字の途中でも切れ目だと認識してしまうため文字化けします。

マルチバイト文字列を扱うのは結構大変です。標準的な(UNIX系な)Cであれば

http://always-pg.com/c/runtime_rd/string/mbstowcs.html

あたりにあるようにマルチバイト文字列をワイド文字列(2バイト)に変換して、ワイド文字列を扱うwcsstrなどで検索する必要があります。

http://always-pg.com/c/runtime_rd/string/strstr.html

Windows限定だと_mbsstrが使えそうですが。

http://www.microsoft.com/JAPAN/developer/library/vccore/_crt_str...

◎質問者からの返答

URLの方は明日、読ませてもらいます。

ありがとうございました。

ちなみに環境はLINUX+REDHATです(バージョンは分かりません)。gccでコンパイルしています。


4 ● dungeon-master
●30ポイント

1バイト見て文字種別を判断し、それが「2バイト文字の第1バイト」を示す値なら、

続く1バイトを拾って「2バイト文字の第2バイト」として扱う必要があります。

(同様に、3バイト文字領域を示すなら、続く2バイトを拾う)


「飛行機 電車(以下略)」という文字列は、バイナリ16進で1バイトずつ表すと

C8,F4,B9,D4,B5,A1,A1,A1,C5,C5,BC,D6 …と並んでいるはずです。

C8を見て2バイト文字の第1バイトであると判断し、続くF4とあわせて「飛」です。

F4は使ってしまったので、次はB9でこれも2バイト文字の第1バイトになりますから

次のD4と合わせて「行」、同様にB5,A1で「機」、A1,A1で全角スペースです。

問題のプログラムは、単語の区切りとして全角スペース=A1:A1を探していますが、

文字の区切りを考慮せずにstrstr()で探索しているため、先のような文字列では

期待している全角スペースにたどり着く前に「機」の第2バイトと全角スペースの

第1バイトのペアで、A1:A1を検知してしまうため失敗します。


1バイト文字か2バイト文字のみで構成される前提で、こんなかんじかと。

main()
{
 unsigned char words[100] = "飛行機 電車 train ";
 unsigned char *pt1,*pt2
 int i;
 pt1 = pt2 = words;
 for( i=0;i<3;i++ ){
 if( strcmp(pt2," ") ){
 pt2+= ( *pt2>0x80 )? 2:1;
 }else{
 *pt2=0;
 printf("%s\n",pt1);
 pt2+=2;
 pt1=pt2;
 }
 }
}

コンパイルもしていないので、動くかどうかわからんですけど。

◎質問者からの返答

試してみます。

詳しい説明ありがとうございました。


5 ● noboru
●20ポイント

文字化けする理由は「飛行機」の「機」の文字の euc-jp でのコードが 0xb5, 0xa1 で、全角スペースが 0xa1, 0xa1 だからです。これが繋がっているので「機」の第2バイトの位置で一致してしまいます。(「機(全角スペース)」は 0xb5, 0xa1, 0xa1, 0xa1 になっているため)。

ということで、正確に扱いたい場合は wchar_t 型に変換してから切り分けた方がいいと思います。

例) gcc の場合

#include <stdio.h>

#include <string.h>

#include <locale.h>

#include <stdlib.h>

#include <wchar.h>

int main()

{

char words[] = "飛行機 電車 train ";

wchar_t wc_words[20], *wp1, *wp2;

int i;

setlocale(LC_ALL, "");

mbstowcs(wc_words, words, 20);

wp1 = wc_words;

for (i = 0; i < 3; i++) {

if ((wp2 = wcschr(wp1, L' ')) != NULL) {

*wp2 = L'\0';

printf("%ls\n", wp1);

wp1 = wp2 + 1;

}

}

return 0;

}

◎質問者からの返答

wchar_t型というのは知りませんでした。

試してみます。

ありがとうございました。


1-5件表示/8件
4.前の5件|次5件6.
関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ