#pragma twice

KAB-studio > プログラミング > #pragma twice > 207 Version 11.07 1バイト文字と2バイト文字

#pragma twice 207 Version 11.07 1バイト文字と2バイト文字

前のページへ 表紙・目次へ 次のページへ

 Version 11.07
1バイト文字と2バイト文字

前回紹介した Unicode は、英数文字も日本語もすべて2バイトの変数に
入れて処理するものでした
でも使っちゃいけないんでしょ?
いけないってことはないけど、とりあえず使わない方がいいかな。でもそ
うなると問題が出てきます
問題?
たとえば Version 11.02 ( No.202 ) とかでやった〈文字の検索〉。あれ
は \ を探したけど、もし Shift-JIS の2バイト文字を検索するとしたら

        if( ch[iIndex] == '\\' )

ってできないでしょ
そっか、これだとリードバイトかトレイルバイトかのどっちかになっちゃ
うんだ
普通の人にとっては〈\〉も〈¥〉も違いがないように見えても
コードも違えば、片方は1バイトでもう片方は2バイト、全然違うよ
ね……
だから、まず次の点を考えなきゃいけません

・扱う文字は、1バイト文字のみか、2バイト文字も含むのか。

って、ほとんど2バイト文字じゃないの?
もちろん普通に使う場合には2バイト文字が普通だろうけど、たとえばダ
イアログで入力してもらうときに、1バイト文字だけにしてもらうことはで
きるから
お願いするってこと?
えーっとそういうことじゃなくて……2バイト文字が入ってたら警告を出
すとか
あ、そういうことか
ダイアログみたいに手で入力するものの他に、ファイルだったら最初に文
字をチェックするとか
質問!
はい火美ちゃん
1バイト文字か2バイト文字かってどうやって調べるの?
 Version 11.04 ( No.204 ) で紹介した _mbsbtype() を使います
そっか、あれってリードバイトかトレイルバイトか、ってのを調べるだけ
じゃないんだったね
1バイト文字かっていうのもわかるからね。で、このどちらかに決めるこ
とで次のことが決まります

・1バイト文字のみ>楽。
・2バイト文字も含む>大変。

まぁそうだろうけど……
1バイト文字の方は、特に難しいことを考えずに操作できるから簡単。
2バイト文字の方は、ものすごく大変になるか、できないことが増えるかの
どちらかになります
できないこと?
1バイト文字と2バイト文字が混在すると、ざっと次のような問題が出て
きます

・1バイトずつの文字の比較はできない。
・文字タイプのチェックをするか、専用の関数を使う必要がある。
・1バイト文字と2バイト文字で同じ文字を比較できない。
固定長処理ができない。

う、4つも
他にもたぶん色々……

ひとつずつ見ていくと

・1バイトずつの文字の比較はできない。

これはさっき言ったこと
でもこれって、文字列でチェックすればいいんじゃないの?
それはそうなんだけど、そうなると次の問題が出てきます

・文字タイプのチェックをするか、専用の関数を使う必要がある。

リードバイトかトレイルバイトかのチェックとかが必要ってことよね。専
用の関数って _mbsbtype() のこと?
ううん、それだけじゃないよ。実は、 _mbsbtype() みたいに最初に _m 
が付いている関数は、たいがい2バイト文字に対応してます。たとえば

// 上の方……
#include "stdafx.h"
#include "StringTest.h"
#include "StringTestDlg.h"

#include <mbstring.h> // <これ追加。

// 略……。

void Reverse()
{
    char pch[128];
    strcpy( pch, "あAいうえお" );
    TRACE( "%s\n", _mbsrev( (unsigned char *)pch ) );
    // おえういAあ
}

この _mbsrev() ってランタイムは文字列を逆にします
妙な関数ね……あ、ちゃんと2バイト文字が逆順になってる!
そう、もし普通に頭と後ろを入れ替えていったら
トレイルバイトの後にリードバイトが来ちゃうからおかしくなっちゃう、
はずだけどそうなってない
実際に中でリードバイトかトレイルバイトかのチェックはしてるから
なるほど
ただ、_mbsbtype() もそうだったけど、これは VC でしか使えないから
他だと使えないってことねー。まぁ他があるのかよくわかんないけ
ど……
仕事でプログラミングしてるとそういうのは避けられないから

次の

・1バイト文字と2バイト文字で同じ文字を比較できない。

だけど、これはさっき言った〈\〉も〈¥〉のこと
似てるけど、文字コード的には別物ってわけね
でも、その別物っていうのをユーザーに説明するのは大変だから
だったら、1バイト文字に制限するのも難しくない?
確かにそうなんだけどね……。あ、あともうひとつ、辞書順の問題があり
ます
辞書順?
アルファベット順とかに並べる時には、 A は B の前、とかっていう並び
方の順番があるでしょ。それが辞書順。そういう、どっちが前かっていうの
を調べる時には strcmp() ってランタイムを使います

void Compare1to1()
{
    TRACE( "%d\n", strcmp( "A", "B" ) );
    // -1
}

 -1 って出た
 strcmp() は、左の方が小さい、つまり辞書順と同じだとマイナスを返し
ます。逆、たとえば "B", "A" だとプラスを返します。同じだと 0 
つまりマイナスなら適切な並び順ってことね
ところが、2バイト文字だとこうはいきません

void Compare2to1()
{
    TRACE( "%d\n", strcmp( "A", "B" ) );
    // 1
}

げ、1? プラスじゃん!
こんなふうに、2バイト文字と比較すると文字コードの関係でうまくいき
ません
あ、じゃあこれの2バイト文字用のは? 最初に _m が付いてるの
それは _mbscmp() なんだけど、それでも同じ結果
う”……
この問題の困る所は、エクスプローラーはちゃんと比較できちゃうんだよ

へ?
〈A.txt〉ってファイルと〈B.txt〉ってファイルがあると
うわ、ちゃんと〈A.txt〉が上に来てる……
エクスプローラーにできるのに、って言われるとちょっときついかもね
やり方はないの?
もちろんあるけど、ランタイムや API で簡単に、っていうのはないん
じゃないかな、たぶん
うー……
最後の

固定長処理ができない。

だけど、これはお仕事関係じゃないと使わないかも
こていちょう、ってことは長さが固定ってことよね……どういうこ
と?
ほら、 Version 10.22 ( No.200 ) でちょっとやったでしょ

AAA1524,300,Z
0123F,100,Z
LLF33,200,F

げ、あれね
たとえばこの

AAA1524,300,Z

の最初の AAA みたいに〈最初にアルファベット3文字〉みたいに長さが
決まってる部分のこと
2行目違うじゃん
この例は、そういうイレギュラーなデータが入ってるってことだったか

ってことは2行目は無視していいんだね。だとすると

AAA1524,300,Z
LLF33,200,F

って、頭3文字がアルファベットってなるわけだ
たとえばこの3文字が特定のものだけ抜き出すとか、それは関係なく後ろ
の数字でソートするとか
そういう時に2バイト文字が入ってると、普通に char 3個分で切れない
からうまくいかないってこと?
そういうこと
質問!
はい火美ちゃん
ってゆーか、アルファベットとか数字なら、2バイト文字を1バイト文字
に変換しちゃえばいいんじゃないの?
うん、それもひとつの手。ただ、必ずしもそれがいいとは限らないから
どういうこと?
まずひとつは、そういう関数がランタイムや API にないから、自分で作
らなきゃいけない

まぁ作ることはないけど、ネットとかで探してきた後、ちゃんと使えるか
チェックが必要かな
それはそれで大変そうね
あと、わざと2バイト文字で書いてあった場合にそれを1バイト文字に変
換しちゃうとまずい、ってこともあるかな
そんなことあるの?
もちろん時と場合によるけど、少なくともファイルパスの場合に¥を \ 
に変換したらまずいでしょ
大変なことになりそう……
もちろん変換するのもひとつの手だし、1バイト文字しか受け付けないの
もあり。そのあたりは使い勝手とか作る手間とかと相談だね

/*
    Preview Next Story!
*/
よーするに、日本語が入ると難しいことが増えるってことね
そういうこと
でもさ、そういうのって説明書に書けばいいんじゃないの?
それは難しいんだよね
なんで?
ほとんどの人は、全角と半角の区別ってできないと思うよ
そ、そうなの?
というわけで次回
< Version 11.08 文字列クラスふたたび >
につづく!
そういう、ユーザー頼みな方法はたぶん失敗するから
経験者は語る?
うん……
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。