有些字符数两次

时间:2016-05-23 21:44:33

标签: string counter pascal

现在我正试图在文本中找到最长的句子并打印出包含空格和类似内容的字符数。问题是当我遇到像'š'或'á'这样的字符时,它会计算两次。我尝试在这些情况下减去一个,但这似乎也不起作用,因为它也减去了两次。知道如何解决这个问题吗?这是计数器的代码。

for i:=1 to length(text) do
      case text[i] of 
        '.','!','?': begin
                        if len>p2 then p2:=len;
                        len:=0
                     end;
         else inc(len);
       end;

p2是最长句子的计数器,len是当前句子。

3 个答案:

答案 0 :(得分:2)

这适用于ANSI字符,包括带有变音符号的字符。由于您没有提到任何特定字符集,并且您的问题只是标记为,因此它也适用于您。如果您正在处理其他字符集,那么您需要指出您正在使用的特定Pascal编译器,因为对多字节字符的支持因Pascal方言而异。

function LongestSentenceCharCount(const Text: string): Integer;
var
  Len: Integer;
  LongLen: Integer;
  i, CurrLen: Integer;
begin
  Len := Length(Text);
  CurrLen := 0;
  LongLen := 0;
  for I := 1 to Len do
  begin
    if Text[i] in ['.', '!', '?'] then
    begin
      if CurrLen > LongLen then
        LongLen := CurrLen;
      CurrLen := 0;
    end
    else
      Inc(CurrLen);

  end;
  Result := LongLen;
end;

处理多字节字符集,如UTF-8和Unicode -

基于一些代码捐赠给Cary Jensen的白皮书(PDF)Delphi Unicode Migration for Mere Mortals: Stories and Advice from the Front Lines由Seppy Bloom(当时Embarcadero的RTL / VCL团队负责人),您可以使用一些可用的规范化功能自Vista及更高版本以来的Windows。我已经调整了上面的函数来使用Seppy中的代码(包含在下面),以及一个示例应用程序来演示如何使用它。代码是在Delphi 10.1 Berlin中开发,编译和测试的,所以如果你使用不同的编译器,你必须调整它,如果你没有在Windows Vista或更高版本下运行,它显然不会起作用。 / p>

program Project1;

{$APPTYPE CONSOLE}

uses
  System.SysUtils, WinAPI.Windows;

const
  NormalizationOther = 0;
  NormalizationC     = 1;
  NormalizationD     = 2;
  NormalizationKC    = 5;
  NormalizationKD    = 6;

function IsNormalizedString(NormForm: Integer; lpString: LPCWSTR;
  cwLength: Integer): BOOL; stdcall; external 'Normaliz.dll';

function NormalizeString(NormForm: Integer; lpSrcString: LPCWSTR;
  cwSrcLength: Integer; lpDstString: LPWSTR;
  cwDstLength: Integer): Integer; stdcall; external 'Normaliz.dll';

function NormalizedStringLength(const Str: string): Integer;
var
  Buf: string;
begin
  if not IsNormalizedString(NormalizationC, PChar(Str), -1) then
  begin
    SetLength(Buf, NormalizeString(NormalizationC, PChar(Str),
                                   Length(Str), nil, 0));
    Result := NormalizeString(NormalizationC, PChar(Str),
                                   Length(Str), PChar(Buf), Length(Buf));
  end
  else
    Result := Length(Str);
end;

function LongestSentenceLen(const Text: string): Integer;
var
  Len: Integer;
  i, CurrLen: Integer;
begin
  Len := Length(Text);
  CurrLen := 0;
  Result := 0;
  for i := 1 to Len do
  begin
    // Replaces 'if Text[i] in ['.', '!', '?']', which will work
    // but generates a compiler warning.
    if CharInSet(Text[i], ['.', '!', '?']) then 
    begin
      if CurrLen > Result then
        Result := CurrLen;
      CurrLen := 0;
    end
    else
      Inc(CurrLen, NormalizedStringLength(Text[i]));
  end;
end;

var
  Test: string;

begin
  Test := 'Ahoj, jak se máš? Hello World.';
  WriteLn(Test);
  WriteLn(Format('Longest: %d', [LongestSentenceLen(Test)]));
  ReadLn;
end.

以上的输出是

Ahoj, jak se más? Hello World.
Longest: 16

答案 1 :(得分:1)

您尚未说明输入文本的表示方式,但您看到的症状与UTF-8输入一致。

ASCII是一个7位字符集,不包含任何带重音的字母。您的变量text可能是一个字符数组。对于像Ahoj, jak se mas?这样的字符串,每个字符占用数组中的一个插槽。对于像Ahoj, jak se máš?这样的字符串,'á''š'字符在ASCII范围之外,每个字符表示为2个字节,因此数组中有2个插槽。

Wikipedia article on UTF-8解释了UTF-8编码的工作原理。

我建议暂时添加以下内容:

writeln('text[', i, '] = ''', text[i], ''' = ', ord(s[i]));

begin循环的for后,您可以看到每个字符的值。

这解释了你所看到的问题,但不是如何解决它。这取决于您的Pascal实现对非ASCII文本的支持。据我所知,Pascal语言本身没有这样的支持,但是有些特定的实现是直接的。

答案 2 :(得分:0)

最近我只是在我提到的在线编译器中工作。我试过的其他任何地方(免费帕斯卡和涡轮帕斯卡)它运作得很好。

感谢您的帮助,我并不认为不同的编译器会有所作为。