全角文字列取得

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

全角文字列取得

#1

投稿記事 by いけやん » 17年前

初めまして、いけやんと申します。

さっそく質問します。

開発環境
Windows XP sp2
Visual C++6.0
MFC ダイアログベース

----+--------+--------------------
2000|02-00-00|《ああああああ》
2000|02-01-00| いい掛/うう

現在上記の様な、テキストデータを読み込んで、CTreeCtrlに表示させているのですが

今strtok関数を使ってテキストの中の必要のない物をどけて、文字列を摘出しています。

しかしstrtok関数は、半角の物を意識して作ってあるらしく

全角文字列を読み込ませるのは、よろしくないみたいです。

実際に今のプログラムでは、
実行結果
<<ああああああ>>
いい
/うう
「掛」この文字だけなくなり、
こういった表示になります。

原因は、「全角1文字を半角2文字として扱うため、
場合によっては全角文字の一部が区切り文字と誤認識され、ぶった切られます。」

なので、wcstok関数を使えば全角文字列も読み込み

できるみたいなのでwcstok関数を使う事にしました。

リファレンスより
wchar_t *wcstok(
wchar_t *strToken,
const wchar_t *strDelimit
);

wcstokの第一引数をUnsigned shortに変換に変換できません
というエラーがでます。

http://hw001.gate01.com/eggplant/tcf/cp ... _trap.html
この関係なんですかね?

無理やりですが、キャストしたりしてみてもエラーがでます。

使い方に困っています。

なので、wcstok関数の使い方がわかる方

すいませんが、お願いたします。

またwcstok関数以外でも結構ですので

よろしくお願いします。

いけやん

Re:全角文字列取得

#2

投稿記事 by いけやん » 17年前

これがソースです。
CStdioFile fin;//ファイル変数
	CString str;//1行文読込用
	int i = 0,count;



	if ( !fin.Open("部材.txt", CFile::modeRead, NULL ) ) {return -1;}

	while ( fin.ReadString(str) != NULL ) {
       int i = 0;

	reinterpret_cast<unsigned short *>(str);
        for (const char *token = wcstok(str.GetBuffer(str.GetLength()),"+-|0123456789 ");
	     token != NULL;
		 token = wcstok(0,"-+|0123456789 ")){

			m_HndTree[0] = m_tree.InsertItem(token,TVI_ROOT);
	
			m_HndTree[1] = m_tree.InsertItem(token,m_HndTree[0]);
                        省略
         }

box

Re:全角文字列取得

#3

投稿記事 by box » 17年前

第1引数は、ポインターでなければならないはずです。
私はwcstok関数を使ったことがないのでナニですが、

>		 token = wcstok(0,"-+|0123456789 ")){

ここの第1引数は NULL あたりにしなければならないのではないでしょうか。

toyo

Re:全角文字列取得

#4

投稿記事 by toyo » 17年前

部材.txtはシフトJISで書かれているのですよね
掛の0x7Cが'|'とかぶりますね
wcstok( )を使うにはUTF-16にコンバートしないといけません
ファイル自体を変えるか読み込んでから
MultiByteToWideChar( )
で変更するか
でもファイル自体の文字コードを変更できるならEUC-JPにしたら区切り文字とかぶることはなくなりますよ

いけやん

Re:全角文字列取得

#5

投稿記事 by いけやん » 17年前

すいません返信遅れました。

>token = wcstok(0,"-+|0123456789 ")){
直しました。ありがとうございます。

すいません。文字コードの前に

文字列をキャストしているところエラーが出てました。
reinterpret_cast<unsigned short *>(str);
    for (const char *token = wcstok(str.GetBuffer(str.GetLength()),"+-|0123456789 ");//エラー
	     token != NULL;
		 token = wcstok(NULL,"+-|0123456789 ") ) {//エラー
class CString' から 'unsigned short *' に変換することはできません。

すいませんが、CStringからunsgined shortへの変換の仕方

教えて頂けないでしょうか。お願いします。

toyo

Re:全角文字列取得

#6

投稿記事 by toyo » 17年前

単純なキャストだとASCII文字が2文字で1文字として扱われてしまうのでだめですね
wchar_t型にするなら文字コードもユニコードにするのが本来の使い方だと思います
wchar_t buf[256];
MultiByteToWideChar(CP_THREAD_ACP, MB_PRECOMPOSED, str, 256, buf, 256);
でどうでしょう
あとwcstok関数は第2引数もwchar_t型なので
wcstok(NULL, L"+-|0123456789 ")
とLを付けないといけませんね

個人的な意見としてはマルチバイト文字をユニコード用の関数で扱うのはあまりいいやり方ではないような気がします。
自分ならstr.Mid( )で1バイトずつチェックして0x80以上なら2バイト文字なので読み飛ばすようにします。

いけやん

Re:全角文字列取得

#7

投稿記事 by いけやん » 17年前

う~ん、MultiByteToWideCharを使ってみたのですが
やっぱりchar * から unsigned short *変換できません
エラーになりますね。
if ( !fin.Open("部材.txt", CFile::modeRead, NULL ) ) {return -1;}

	while ( fin.ReadString(str) != NULL ) {
    int i = 0;

	MultiByteToWideChar(CP_THREAD_ACP,MB_PRECOMPOSED,str,256,buf,256);
	//const char *str2 = new char[str.GetLength()+1] = strcpy(str2,str);
	//reinterpret_cast<unsigned short *>(str);
    for (const char *token = wcstok(str.GetBuffer(str.GetLength()),L"+-|0123456789 ");
	     token != NULL;
		 token = wcstok(NULL,L"+-|0123456789 ") ) {
>個人的な意見としてはマルチバイト文字をユニコード用の関数で扱うのは
>あまりいいやり方ではないような気がします。

これは、下記の様な無理?に変換して使うのは、
あまりよろしくないという事ですね?
MultiByteToWideChar(CP_THREAD_ACP, MB_PRECOMPOSED, str, 256, buf, 256);


>str.Mid( )で1バイトずつチェックして0x80以上なら2バイト文字なので読み飛ばすようにします。
toyoさんありがとうございます。
上記の件試したいと思います。

あまりC初心者なので、エラー出しながらなので、返信遅くなると思います。

御津凪

Re:全角文字列取得

#8

投稿記事 by 御津凪 » 17年前

Visual C++6.0 で可能かどうか分かりませんが、以下の方法はどうでしょうか。
wchar_t buf[256];
swprintf(buf,L"%S",str);
もし実行時に日本語部分が出なければ、以下の処理を事前に実行しておくと出ると思います。
// ↓をインクルードする
// #include <locale.h>
set_locale(LC_ALL,"jpn");
MultiByteToWideChar でも上記処理は有効だと思います。

いけやん

Re:全角文字列取得

#9

投稿記事 by いけやん » 17年前

返信、遅くなってすいません。

>Visual C++6.0 で可能かどうか分かりませんが、以下の方法はどうでしょうか。
>もし実行時に日本語部分が出なければ、以下の処理を事前に実行しておくと出ると思います。
御津凪さん参考にさして頂きます。


>自分ならstr.Mid( )で1バイトずつチェックして0x80以上なら2バイト文字なので読み飛ばすようにします。
リファレンスを見ながらやってみたのが
下記の警告がでます。
argument 'const int' から 'char' へ切り詰めます

引数で怒られているみたいなのですが、
使い方をご教授頂けないでしょうか?
#define String str2

while ( fin.ReadString(str) != NULL ) {

	//MultiByteToWideChar(CP_THREAD_ACP,MB_PRECOMPOSED,str,256,buf,256);
		if(str.Mid(2) >= 0x80 ){
			str2 = str.Mid(1);

			m_HndTree[0] = m_tree.InsertItem(String,TVI_ROOT);
	
			m_HndTree[1] = m_tree.InsertItem(String,m_HndTree[0]);

toyo

Re:全角文字列取得

#10

投稿記事 by toyo » 17年前

test用のプログラムを作ってみました
参考になりますでしょうか
// 対象文字列
	CString str = "2000|02-01-00| いい掛/うう";
	// 抜き出し用文字列
	CString str2;
	// 対象文字列の長さ(バイト数で文字数ではない)だけ繰り返す
	for (int i = 0; i < str.GetLength(); i++) {
		// 区切り文字でない場所を探す
		if (str == '+' || str == '-' || str == '|' ||
			(str >= '0' && str <= '9') || str == ' ') {
			continue;
		}
		// 文字列抜き出しの開始
		str2.Empty();
		while (i < str.GetLength()) {
			// 区切り文字があればそこで抜き出し終了
			if (str == '+' || str == '-' || str == '|' ||
				(str >= '0' && str[i] <= '9') || str[i] == ' ') {
				break;
			}
			// 抜き出し用の文字列に1バイト追加
			str2 += str[i];
			// 2バイト文字の場合は無条件でもう1バイト追加
			// 0xA1-0xDFは半角カナで1バイトなので除外
			if ((UCHAR)str[i] >= 0x80 && ((UCHAR)str[i] < 0xA1 || (UCHAR)str[i] > 0xDF)) {
				i++;
				str2 += str[i];
			}
			i++;
		}
		// 確認用のメッセージボックス表示
		AfxMessageBox(str2, MB_OK, 0);
	}

toyo

Re:全角文字列取得

#11

投稿記事 by toyo » 17年前

ちなみに2バイト文字判定は超手抜きですので

lbfuvab

Re:全角文字列取得

#12

投稿記事 by lbfuvab » 17年前

2バイト文字を弾いてコピーする関数を作っては駄目ですか?
void Copy1ByteOnly(unsigned char *src,unsigned char *dest){                //オーバフロー対策はしてません。
    while(*src){
            if((*src>=0x81 && *src<=0x9F) || (*src>=0xE0 && *src<=0xFC))   //2byteなら
                src++;                                                     //取り敢えず1byte進める
            else
                *dest++=*src;
        src++;
    }
    *dest='\0';
}

いけやん

Re:全角文字列取得

#13

投稿記事 by いけやん » 17年前

toyoさん、lbfuvabさん
サンプルありがとうございます。

すいませんが、上記のサンプルで解らない部分があり

自分的には、解らない所を解らないまま書くのは

良くないと思っているので、教えて頂けないでしょう?

①str2.Empty();
リファレンスを見ても「空の文字列を表します。このフィールドは読み取り専用です。 」
としか書いてありませんでした。
これはEmpty()関数で、str2を初期化する又は、空にするという解釈で合っていますか?
お願いします。

②0x80が2バイトなら・・・、0xA1-0xDFは半角カナで1バイト、等と書いてあるのですが
どこで、そういった事が解るのですか?
「文字コード」で検索してもありませんでした。
基本的な事なら、すいません。
教えて頂けないでしょうか?
「○○○」で調べて、出直して来いでも結構です。お願いします。

toyo

Re:全角文字列取得

#14

投稿記事 by toyo » 17年前

str2.Empty(); に関してはstr2の初期化(文字列を空にする)であっています。
str2 = "";
でも同じです。

文字コードの件ですが
「shift jis コード表」あたりで検索すると出てくるかもしれません
実際には1バイト目はlbfuvabさんのように
(*src>=0x81 && *src<=0x9F) || (*src>=0xE0 && *src<=0xFC)
のほうがより正確です。
厳密に言うと2バイト目も0x40~0x7E, 0x80~0xFCになるのをチェックしないといけないのでしょうが
今回の例ではASCII文字と半角カナ以外で始まる文字をすべて2バイト文字として扱いました。

いけやん

Re:全角文字列取得

#15

投稿記事 by いけやん » 17年前

toyoさんありがとうございます。
shift jis コード表で調べてみます。

後、本当に勝手なのですが、
これから、ちょっと連休に入るのでサンプル等の返事が
来週の水曜なると思いますので
ご了承下さい。

いけやん

Re:全角文字列取得

#16

投稿記事 by いけやん » 17年前

返信遅くなりました。文字列表示できました。
下記で解決しました。
if ( !fin.Open("部材.txt", CFile::modeRead, NULL ) ) {return -1;}
	while ( fin.ReadString(str) != NULL ) {
              toyoさんのサンプル
       m_HndTree[0] = m_tree.InsertItem(String,TVI_ROOT);
        }
toyoさんのサンプルを殆ど使わして頂きました。

shift jisの件,
調べてみるとあるページに下記の事が書いてありました。  

  制御コード
0x00~0x1F、0x7F
ASCII文字
0x20~0x7E
半角カタカナ
0xA1~0xDF
漢字
0x8140~0x9FFC、0xE040~0xFCFC
(第1バイト: 0x81~0x9F、0xE0~0xFC 第2バイト: 0x40~0x7E、0x80~0xFC)

すいません、もう少し聞きたいのですが

>実際には1バイト目はlbfuvabさんのように
>(*src>=0x81 && *src<=0x9F) || (*src>=0xE0 && *src<=0xFC)

>厳密に言うと2バイト目も0x40~0x7E, 0x80~0xFCになるのをチェックしないといけないのでしょうが

上記の事を自分なりに解釈すると、
もう少し厳密な、2byte漢字処理が必要という事ですか?
またそれは、何のために必要なんでしょうか?
お手数ですが、お願いします。


<!--1

lbfuvab

Flying Fly

#17

投稿記事 by lbfuvab » 17年前

Bugさんのつくっていた「Flying Fly」と言うゲームを
友人に見せようと思ったのですがどこにおいてあるのでしょうか?
「その他のソフト紹介」の中にも見当たりません。<!--23-->

管理人

Re:Flying Fly

#18

投稿記事 by 管理人 » 17年前

バグさんに、ここで紹介してもいいか聞いてみます。
もし許可が出たらダウンロードページに追加しようと思います。

バグ

Re:Flying Fly

#19

投稿記事 by バグ » 17年前

管理人さんへ返信しておきました。
プロジェクトも付けておきましたんで、悪用しなければ(どうやって?(笑))好きに使ってくださって結構ですよ(^-^)

バグ

Re:Flying Fly

#20

投稿記事 by バグ » 17年前

待ちきれない場合は、下記から落とせます。
ここで発表した最新版に少し手を入れています。

http://www7.uploader.jp/dl/123456/12345 ... 1.zip.html

管理人

Re:Flying Fly

#21

投稿記事 by 管理人 » 17年前

バグさん、ありがとうございます^^

その他のソフト紹介欄にFlyingFly追加させてもらいましたm(_ _)m

閉鎖

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