如何准确统计备忘录中的字数?

How to accurately count words in a Memo?

我正在尝试制作一个记事本克隆,并在状态栏中增加 运行 字数统计功能。字数统计不准确,重复space或回车return算新词。这是我尝试过的字数统计功能:

procedure TFormMain.Memo1Change(Sender: TObject);
var
  wordSeparatorSet: Set of Char;
  count: integer;
  i: integer;
  s: string;
  inWord: Boolean;
begin
  wordSeparatorSet := [#13, #32]; // CR, space
  count := 0;
  s := Memo1.Text;
  inWord := False;

  for i := 1 to Length(s) do
  begin
    // if the char is a CR or space, you're at the end of a word; increase the count
    if (s[i] in wordSeparatorSet) and (inWord=True) then
    begin
      Inc(count);
      inWord := False;
    end
    else
    // the char is not a delimiter, so you're in a word
    begin
      inWord := True;
    end;
  end;
  // OK, all done counting. If you're still inside a word, don't forget to count it too
  if inWord then
    Inc(count);

  StatusBar1.Panels[0].Text := 'Words: ' + IntToStr(count);
end;

当然,我愿意接受任何替代方案或改进。我真的不明白为什么这段代码会增加每个 space 和回车符 return 的字数 (count)。我认为在用户点击 space 条(递增 count)之后,变量 inWord 现在应该为 False,因此如果用户点击 if (s[i] in wordSeparatorSet) and (inWord=True) 应该解析为 False space 栏或 Enter 键第二次。但事实并非如此。

I really don't understand why this code increases the word count (count) with every space and carriage return.

在单词后的第一个 space,您确实将 inWord 设置为 False。因此,如果下一个字符也是 space,您将(错误地)运行 inWord := True,因此如果下一个(第三个)字符再次是 space,您将(错误地)做 Inc(count).

您还可以注意到 (s[i] in wordSeparatorSet) and (inWord=True) 的否定并不意味着“字符不是定界符”,因为与 inWord 的连词。 (s[i] in wordSeparatorSet) and (inWord=True) 的否定是 De Morgannot (s[i] in wordSeparatorSet) or not (inWord=True),这与 not (s[i] in wordSeparatorSet).

不同

固定版本看起来更像

function WordCount(const AText: string): Integer;
var
  InWord: Boolean;
  i: Integer;
begin
  Result := 0;
  InWord := False;
  for i := 1 to Length(AText) do
    if InWord then
    begin
      if IsWordSep(AText[i]) then
        InWord := False;
    end
    else
    begin
      if not IsWordSep(AText[i]) then
      begin
        InWord := True;
        Inc(Result);
      end;
    end;
end;

其中 IsWordSep(chr) 被定义为类似 chr.IsWhitespace 的东西,但有许多细微之处,我将详细讨论 on my web site.