代码之家  ›  专栏  ›  技术社区  ›  wfoster

Delphi中的system.pos有缺陷吗?

  •  -1
  • wfoster  · 技术社区  · 14 年前

    问题

    如果trichedit中的文本是这样的话;

    'hello, world'#$D#$A
    

    然后,以下例程显示为真。但是当richedit

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

    然后该例程显示为假。在我看来这是有缺陷的,因为它找到的是逗号,而不是换行符/换行符。我创建了一个变通方法来遍历字符串并找到我要查找的内容,但是我仍然很好奇为什么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;
    

    解决方法-Andreas版本(根据输入加快速度)

    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;
    

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

    解决方案

    经过一些测试,这取决于您要查找的字符类型。用逗号(44)测试,将294K个字符放入589K长度的字符串中。使用system.pos的函数的性能约为390微秒,case语句运行约700微秒。

    然而!

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

    所以我猜,如果你在寻找一个特定的字符,那么System.pos肯定是一种方式,但是如果你在寻找多个字符(我的应用程序是这样做的),那么当你可以扫描它并使用case语句时,不需要重复调用。

    2 回复  |  直到 14 年前
        1
  •  6
  •   James    14 年前

    我不认为Delphi将\n识别为新行,pos认为您实际上在搜索字符\“和”n。

    尝试搜索 #13 #10 (回车和换行)代替(或者您可以使用 #$D #$A 这是十六进制的等价物。)

    例如

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

    另外,delphi字符串也会被计数,虽然它们总是以0结尾,但不能保证字符串不包含空字符,这意味着您的while循环可能会提前终止。

    因此,您也可以循环访问i:=1 to length(stmp)(从1开始,因为stmp[0]是计数器)。

    或者可以将while循环构造为

    指数:=1;

    While Index < Length(sTmp) do
    begin
        case sTmp[Index] of
        etc...
    
        2
  •  2
  •   Andreas Rejbrand    14 年前

    (这实际上是一个评论,但看起来很可怕。)

    请注意你的整个街区

    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;