Delphi中的System.Pos有缺陷吗?

时间:2010-08-13 15:43:22

标签: delphi delphi-2009

问题

如果TRichEdit中的文字是这样的话;

'hello, world'#$D#$A

然后以下例程显示TRUE。但是当RichEdit有

'test'#$D#$A#$D#$A'test'#$D#$A#$D#$A'test'#$D#$A

然后例程显示FALSE。在我看来它是有缺陷的,因为它找到了逗号,但不是新行/换行。我创建了一个解决方法来代替字符串并找到我正在寻找的内容,但我仍然很好奇为什么Delphi函数不起作用。有什么想法吗?

procedure TForm1.Button1Click(Sender: TObject);
var
   sTmp : String;
begin
   sTmp := RichEdit1.Lines.GetText;
   if ( ( Pos( ',', sTmp )  <> 0 ) or
        ( Pos( '"', sTmp )  <> 0 ) or
        ( Pos( '\n', sTmp ) <> 0 ) or
        ( Pos( '\r', sTmp ) <> 0 ) ) then
      Label1.Caption := 'TRUE'
   else
      Label1.Caption := 'FALSE';
end;

解决方法 - 安德烈亚斯的版本(根据输入更快)

function CheckChars( const sData: String ): Boolean;
var
   pCur : PChar;
begin
   pCur := PChar( sData );

   // Exit at NULL terminator
   while ( pCur^ <> #0 ) do
   begin
      case pCur^ of
         #13, #10, #34, #44 : Exit(true);
      end;
      Inc( pCur );
   end;
end;

正确用法

function CheckChars( const sData: String ): Boolean
begin
   if ( ( Pos( #44, sData ) <> 0 ) or
        ( Pos( #34, sData ) <> 0 ) or
        ( Pos( #13, sData ) <> 0 ) or
        ( Pos( #10, sData ) <> 0 ) ) then
      Result := true
   else
      Result := false;
end;

适用于所有测试的字符,我决定不混合引用的字符和十进制字符以提高可读性。现在唯一的问题是哪个更快?我认为我的解决方法会更快,因为我正在检查所有我正在寻找的char,而当我使用System.Pos函数时,我运行相同的解析例程4次。

解决方案

经过一些测试,这取决于您要寻找的是哪种角色。使用逗号(#44)对其进行测试,将294k字符放入589k长度的字符串中。使用System.Pos的函数具有~390微秒的性能,case语句运行约700微秒。

无论其<!/ em>的

如果将字符串中的字符更改为换行符(#10),则由于重复调用,System.Pos(~2700微秒)需要更长的时间。 case语句仍然运行约700微秒。

所以我想如果你在寻找一个特定的角色,那么System.Pos肯定是要走的路,但如果你正在寻找多个(我的应用程序所做的那样),那么当你只需要扫描时就不需要重复调​​用它并使用案例陈述。

2 个答案:

答案 0 :(得分:6)

我不认为Delphi认为\ n是一个新行,Pos认为你实际上是在搜索字符“\”和“n”。

尝试搜索#13#10(回车和换行)(或者您可以使用#$D#$A,这将是十六进制等效。)< / p>

e.g。

if ( ( Pos( ',', sTmp )  <> 0 ) or
     ( Pos( '"', sTmp )  <> 0 ) or
     ( Pos( #10, sTmp )  <> 0 ) or
     ( Pos( #13, sTmp )  <> 0 ) ) then

此外,Delphi字符串也会被计算,但它们总是以#0结尾。无法保证字符串不包含空字符,这意味着您的while循环可能会提前终止。

所以或者你可以循环通过i:= 1到Length(sTmp)(从1开始,因为sTmp [0]是计数器)。

或者您可以将while循环构造为

指数:= 1;

While Index < Length(sTmp) do
begin
    case sTmp[Index] of
    etc...

答案 1 :(得分:2)

(这实际上是一个评论,但它看起来很恐怖。)

请注意您的整个块

case pCur^ of
 #13 :   // CR
    begin
       Result := true;
       break;
    end;
 #10 :   // LF
    begin
       Result := true;
       break;
   end;
  #34 :   // Quote 
   begin
        Result := true;
       break;
    end;
 #44 :   // Comma
    begin
       Result := true;
       break;
    end;
 end;
通过注意

可以更紧凑地编写

    在这种情况下,
  • Result := true; break;Result := true; Exit;相同,总是可以写成Exit(true)

  • 如果行动相同,可以将几种情况合并为一个案例。

因此你可以写

case pCur^ of
  #13, #10, #34, #44: Exit(true);
end;

但更好的是,可以编写整个函数

function CheckChars(const Str: string): boolean;
const
  INTERESTING_CHARS = [#13, #10, #34, #44];
var
  i: integer;
begin
  result := false;
  for i := 1 to length(Str) do
    if Str[i] in INTERESTING_CHARS then
      Exit(true);
end;