VC++ MFC SDI アプリです。
「UNICODE文字セットを使用する」でコンパイルしています。
文字列の総バイト数を求めたいのです。
例えば、
CString str = _T(12345あいうえお);
の場合、総バイト数は15なので、これを求めたいのですが、
int nLen = str.GetLength() * sizeof(TCHAR);
とすると、nLen には20が返ってきます。
ネット上で調べると、GetLength() * sizeof(TCHAR) でいいように書いてありますが、
どうやっても 文字数X2 の値が返ってきます。
バイト数を正しく取得する関数はないでしょうか?
よろしくお願いいたします。
文字セットとエンコーディングとは別物であることは理解している?
Windows 上で UNICODE というと、実際には UTF16 で BMP のみ利用、ということで
L12345あいうえお のバイト数は20になるよ。
12345あいうえお が15バイトになるのは MBCS の場合だ。
上記記述では \0 の分が入っていないので注意な
文字列の総バイト数だと UNICODE(UTF16) では 22 MBCS では 16 になるよ
terapadさん、素早い応答で有り難うございます。
「バイト数」といったのがまずかったようです。文字列の「長さ」または「サイズ」と
いうべきでしょうか。
とにかく、12345あいうえお が15になるように求めたいのです。
よろしくお願いいたします。
UTF-16 エンコーディング配下では L12345あいうえお の
文字数は10 (GetLength の返す値)
バイト数(オクテット数)は20 (GetLength * sizeof(wchar_t))
なのであって、どこからどうやっても15などという数値は出てこない。
(\0 の分を含まず)
> 「長さ」または「サイズ」
とはなんのこと?それを定義しておくんなまし。
例題ですが、
あいうえおかきくけこを TextOut で画面に書いたとき、その長さが20cmだとしま
す。(等幅フォント)
12345あいうえおを TextOut で書けば、約15cmになります。
では、123あいうは何cmになるでしょう?
9cmという答えが欲しいのです。
本当に表示上の長さがほしいのですか?
「半角を1、全角を2として、カウントしたい」ではなくて?
欲しいのは「画面上の大きさ」であるとして
いまどき「半角・全角」という用語にはほとんど意味がない。
(特に UNICODE を使うという状況下においては)
等幅フォントに限定すると後から困ること必至。
というわけで、多分やりたいことは GetTextExtent で出来る(と思う)
# GetOutputTextExtent とか GetTextExtentPoint32 とか
# 必要に応じて自分で調べて欲しい
済みません。こっちの方です。
↓
「半角を1、全角を2として、カウントしたい」
なぜ、そのようなカウントがしたいのでしょう?
実際の画面上のサイズが知りたいのであれば、
まだわかるのですが、
「半角を1、全角を2として、カウントしたい」
とする用途が思い浮かびません。
MBCSでバイト数がほしいと言うのであれば話は別ですけれど。
使用するフォントによって画面上のサイズは変わるので
画面上のサイズがほしいのであれば、どのフォントを使った
時にこのサイズになるという言い方しか出来ません。
ちなみに画面上で半角文字が全角文字の半分のサイズになる
とは限りません。
何をしたくてそのようなカウントをしようとしているのかを
提示できれば、より適切なアドバイスがもらえるかもしれません。
単純にASCIIコードの領域を1とカウントしたいだけなのであれば、
文字コードのここからこの範囲は1で、それ以外は2と一文字ずつ
チェックしてカウントすれば良いだけだと思います。
関数一発でそれが取得できるというような事は無いと思います。
> 「半角を1、全角を2として、カウントしたい」
GetStringTypeExでC3_HALFWIDTHになるのが半角です。
やりたいことを述べます。
用紙上に横書きで10cmの幅に、12345あいうえおを印刷したいです。
また、文字列があいうえおかきくけこと変わっても、同じ10cmの幅に印刷したい
です。
そのため、フォントのサイズを計算で求めたいのです。
GetOutputTextExtent で文字列の長さを得るには、フォントを先に設定しなければなら
ないので、堂々巡りになっちゃいます。
> GetOutputTextExtent で文字列の長さを得るには、フォントを先に設定しなければな
ら
> ないので、堂々巡りになっちゃいます。
どうして?
仮のフォントサイズを決めて長さを算出、その値でサイズを修正すればいいんじゃない
の?
まぁ、正確に10センチの幅に印刷できるかどうかは不明ですが。
>GetOutputTextExtent で文字列の長さを得るには、フォントを先に設定しなければなら
>ないので、堂々巡りになっちゃいます。
一般に、フォントが決まっていない状態では
「文字数とそれを描画したときのピクセル数とは無関係」
なので、文字数を求めてもあまり意味はありません。
つまり、その「堂々巡り」で解決する以外に方法はないわけです。
画面上の固定幅内に単一行で文字列の描画を行う場合のフォントの求め方は
1.GetDCでhDCを取得
2.仮のフォントを作成(CreateFontIndirect使用)
3.仮のフォントをHDCに選択
4.フォントメトリックスを取得(GetTextMetrics使用)
5.GetTextExtent()で描画時の幅を取得
6.固定幅との比較によりLOGFONTのlfHeightを調整
7.HDCのフォントの選択を解除
8.フォントを破棄
9.2.に戻る
てな感じです。頭悪そうな方法ですが、これ以外の
「画期的な方法」は見つかりませんでした(vv;)。
> 用紙上に横書きで10cmの幅に、12345あいうえおを印刷したいです。
12345あいうえおから15が欲しいのなら前述の通りGetStringTypeExで行けますが、
印刷幅の計算が目的なら、「半角を1、全角を2」は全く関係ありませんよ。
実際のフォントを使って調べないとわかりません。