Delphiメモ

No001:複数行の文字数カウント

文字数カウントはテキストエディタなら殆どのソフトが搭載している機能の1つ。
学生がレポート書いたり論文書いたりするにはかなり便利な機能ですなぁ。
文字数のカウント自体は実装方法がいろいろなサイトに書いてあるわけなんですが、
どうしてか複数行に対応したコードを見かけることがありません。
よくあるコードを示してみます。

var
  S: String;
begin
  S:= 'Totonicapan.NETは3周年です!';
  ShowMessage(IntToStr(Length(WideString(S))+'文字');
end;

とりあえず処理の基本的な流れは、
文字数を知りたいんだから対象となる文字列の長さを調べればいい。
つまりLength関数を使う。引数はもちろん調べる文字列。
ここで問題になるのがマルチバイト文字。
マルチバイト文字っていうのは日本語みたいな文字で
1文字が2バイトである物を指す(テキトーな定義)
ただ単にLength関数を使っても半角英数と全角の日本語が入り交じった文章だと激しく文字数がおかしいことになる。
ここで勘のいい人ならWideString使えばいいんじゃね?って思いつくはず。
WideStringはUnicode文字列を使う型なので、全てが2バイト文字扱いになる。
そのため入り交じっていてもちゃんと文字数が正確にでる。
サンプルのコードはString型の変数Sに文字列を突っ込んで、それをShowMessageで表示してます。

一見このコードでうまくいきそうな気がしますが、これが複数行になると文字数が乱れます。
なぜなら、実際のエディタ上では見えませんが改行文字という存在があるからです。
そのため、改行文字を除いた数をカウントしなきゃならんわけです。
そこでtotonicaが便利なテクニックを伝授。
お師匠様から授かった複数行文字数カウントでごわす(結局他作かよ)
とりあえずコードを示します。

var
  crlfPos: Integer;
  sLine: String;
begin
  sLine:= Memo1.Lines.Text;
  crlfPos:= Pos(#13#10,sLine);
  while crlfPos > 0 do
  begin
    Delete(sLine,crlfPos,Length(#13#10));
    crlfPos:= Pos(#13#10,sLine);
  end;
  ShowMessage(IntToStr(Length(WideString(sLine)))+'文字');
end;

とりあえずさっきの物より格段にゴチャゴチャしてますね。
まずInteger型とString型の変数をそれぞれ1つずつ宣言します。
別にString型の変数はWideStringでも結構です。
宣言したら、調べたい複数文字列をsLineに代入します。
ここでは便宜的にMemo1のテキストを突っ込むことにしてます。
(この時Memo1.Textってやっちゃうと、ワードラップ分も加味されちゃうぞ)
以前のコードであればここで文字数をカウントしてましたが、今回はなにやらWhile文が書かれてますね。
このコード部分が改行文字を取り除くコードです。
Pos関数は第1引数の文字列の位置を第2引数の文字列の中から探し出します。
この例だと#13#10をsLineから探し出すわけです。
ちなみに#13#10っていうのは改行文字です。(Windowsの改行コードは基本的にCR+LFです)
Pos関数は第1引数の文字列が見つからなかった場合は0を返します。
つまりCR+LFがある限り0より大きい数を返すので、
・Delete手続きでCR+LFを削除
・またCR+LFの位置を検索
を繰り返すわけです。
で、全部削除されるとループを抜けるので、そしたらLength関数使って文字数を調べるわけです。
この処理の欠点は前から順番に検索していくので、行数が多くなったりするとかなり遅くなるという欠点があります。
(3000行とか超えるとだんだん遅くなります。totonicaのマシンでの話ですが)
まぁ通常の文章をカウントするレベルでは問題はまず起こらないですけどね。

トップに戻る

関連ページ