簡體   English   中英

Dephi:將“臟”字符串轉換為數字的更快方法

[英]Dephi: faster way to convert a “dirty” string to a number

如何使此代碼更快? 該字符串可以包含諸如“,。?#”之類的字符,也可能包含其他字符。

Const Nums = ['0'..'9'];

function CleanNumber(s: String): Int64;
Var z: Cardinal;
begin
  for z := length(s) downto 1 do
   if not (s[z] in Nums) then Delete(s,z,1);
  if s = '' then
    Result := 0 else
    Result := StrToInt64(s);
end;

結果(長循環):CL2,CL3 = HeartWare的

32位,“臟號碼” /“干凈號碼”

  • 地雷:270ms,165ms
  • CL2:220ms,210ms
  • CL3: 100ms ,110ms
  • DirtyStrToNum:215ms, 90ms

64位,“臟號碼” /“干凈號碼”

  • 地雷:2280ms,75ms
  • CL2:1320ms,130ms
  • CL3: 280ms25ms
  • DirtyStrToNum:1390ms,125ms

這是兩個肯定比您擁有的示例快的示例(從字符串中刪除字符相對較慢):

通過預先分配一個最大可能長度的字符串,然后在源字符串中遇到這些數字時,用數字填充該數字,可以完成這一工作。 沒有為每個不受支持的字符刪除,也沒有為每個受支持的字符擴展目標字符串。

FUNCTION CleanNumber(CONST S : STRING) : Int64;
  VAR
    I,J : Cardinal;
    C   : CHAR;
    T   : STRING;

   BEGIN
     SetLength(T,LENGTH(S));
     J:=LOW(T);
     FOR I:=LOW(S) TO HIGH(S) DO BEGIN
       C:=S[I];
       IF (C>='0') AND (C<='9') THEN BEGIN
         T[J]:=C;
         INC(J)
       END
     END;
     IF J=LOW(T) THEN
       Result:=0
     ELSE BEGIN
       SetLength(T,J-LOW(T));  // or T[J]:=#0 [implementation-specific]
       Result:=StrToInt64(T)
     END
   END;

這是通過將最終結果與10進行簡單乘法並加上相應的數字值來實現的。

 {$IFOPT Q+}
   {$DEFINE OverflowEnabled }
 {$ELSE }
   {$Q+ If you want overflow checking }
 {$ENDIF }
 FUNCTION CleanNumber(CONST S : STRING) : Int64;
   VAR
     I  : Cardinal;
     C  : CHAR;

   BEGIN
     Result:=0;
     FOR I:=LOW(S) TO HIGH(S) DO BEGIN
       C:=S[I];
       IF (C>='0') AND (C<='9') THEN Result:=Result*10+(ORD(C)-ORD('0'))
     END
   END;
 {$IFNDEF OverflowEnabled } {$Q-} {$ENDIF }
 {$UNDEF OverflowEnabled }

另請注意,我不使用IN或CharInSet,因為它們比簡單的內聯> =和<=比較要慢得多。

我可以提出的另一條評論是在字符串變量上使用LOW和HIGH。 這使其與基於0的字符串(移動編譯器)和基於1的字符串(桌面編譯器)兼容。

您的功能緩慢主要是因為使用Delete方法。 每次調用Delete需要移動很多字符。

更快的方法是這樣的:

function DirtyStrToNum(const S: string): Int64;
var
  tmp: string;
  i, j: Integer;
const
  DIGITS = ['0'..'9'];
begin
  SetLength(tmp, S.Length);
  j := 0;
  for i := 1 to S.Length do
    if CharInSet(S[i], DIGITS) then
    begin
      Inc(j);
      tmp[j] := S[i];
    end;
  SetLength(tmp, j);
  if tmp.IsEmpty then
    Result := 0
  else
    Result := StrToInt64(tmp);
  // Or, but not equivalent: Result := StrToInt64Def(tmp, 0);
end;

請注意,我為新字符串進行了一次分配,然后僅將最少數量的字符復制到其中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM