文字数を考える
>vから始まる単語が2つある為、2とカウントされています。
vbTabやvbCrLfは制御文字と呼ばれるものですが、どうもこの制御文字の解釈で混乱してしまっているようですね。
まずはそこから整理しましょう。
全角が混ざると説明がちょっとややこしくなるので、半角で説明しますね。
例えばDBからの取得値"abc 123ABC"
という文字列がstrValueという変数に入っているとします。
この文字列は、改行の表現できない状態で見ると"abc 123ABC"
と見えますが、間にはタブ文字や改行文字が入っており、VB上では"abc" & vbTab & "123" & vbCrLf & "ABC"
で作成される文字列と同じだとします。
ここまでは全角の文字が半角になっている以外はご質問の内容と同じですよね。
※ここからはShiftJISベースで話を進めさせてもらいます。
さてこの時、strValueは何バイトでしょうか?
正解は
"abc" :3バイト
vbTab:1バイト
"123" :3バイト
vbCrLf:2バイト
"ABC" :3バイト
の合計12バイトです。
通常の文字について
まず、"abc"や"123"の部分が3バイトなのは問題ないですよね。
"abc"とは"a"(文字コード:97番)、"b"(98番)、"c"(99番)という1バイト文字が3つ集まって3バイトというわけです。
"abc" = Char(97) & Char(98) & Char(99)
vbTabについて
次に制御文字の部分に着目すると、vbTabは1バイトとなっています。
タブ文字というは、1バイトの文字(文字コード:9番)なのです。vbTab = Char(9)
"vbTab"という5文字で5バイトというわけではないんですね。
1バイトの文字に特別な機能(タブ文字ならインデントする機能)を持たせているのが制御文字なんです。
vbCrLfについて
ではvbTabと同様、制御文字であるvbCrLfはなぜ2バイトなのでしょう?
実は改行コードvbCrLfとは、CR(キャリッジリターン)とLF(ラインフィード)からなる2つの制御文字の組み合わせなんです。vbCrLf = Char(13) & Char(10)
ちなみにvbCr(文字コード:13番)とvbLf(10番)も用意されているので、分けることもできます。
余談ですが、なぜ改行がCRとLFの2文字になっているのかというと、大昔のタイプライターの原理に由来するようです。
タイプライターでは1行文章を打ち終えて改行する際、まず印字ヘッドを左端に戻して(CR)、次に紙を1行分ずらす(LF)という2段階の操作が必要で、これを機械で制御するようになったのでCRとLFがわかれているのだとか。
CountChar関数の返す値について
>一文字しか比較対象として認識してくれないのでvbCrLfのvだけしか見てくれません
この関数の動きについても誤解されているところがあるようですので解説させていただきます。
関数の戻り値となる
s.Length - s.Replace(c.ToString(), "").Length
を分解して考えてみます。
まずs.Length
は、引数sの文字長です。
引数sにはDB取得値を渡していますので、先ほどのstrValueであれば12文字、つまり12となります。
次に、s.Replace(c.ToString(), "").Length
のなかのs.Replace(c.ToString(), "")
の部分。
ここでは、引数sの中に含まれる引数cの文字列を空文字列""に置換した文字列を作っています。
つまりsの文字列からcの文字列を除去した文字列を作り出しています。
その置換後の文字列に対して.Length
で文字長を調べています。
先ほどのstrValueからvbCrLfを削ると、2バイト減って10バイトになるので、10という値になります。
戻り値は最初のsの長さから置換後の長さを引いたものとなるので、12-10で 2 になるわけです。
1バイト文字の検索であれば、置換して減った文字数が変換した数になるので正しいのですが、今回は2バイトの文字列を検索したために意図しない結果となってしまったようです。
対策
案①
簡単な対策としては、vbCrLf
ではなくvbCr
で検索するという方法です。
先にも書いた通りvbCrLfにはvbCr(13)とvbLf(10)の2文字が含まれています。
単純に含まれている数を数えたいだけであれば、1バイト文字であるvbCrだけを検索すれば、思った結果が得られると思います。
案②
「1バイト以外の文字列でも正しくカウントを取りたい」という場合は、CountChar関数を修正する必要があります。
置換した結果は削った文字数
となっているため、これをcの文字長
で割ってあげれば置換した個数にできそうです。
Return (s.Length - s.Replace(c.ToString(), "").Length) / c.Length
長文になってしまいましたが、参考になれば幸いです。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/12/15 00:27