[英]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位,“臟號碼” /“干凈號碼”
64位,“臟號碼” /“干凈號碼”
這是兩個肯定比您擁有的示例快的示例(從字符串中刪除字符相對較慢):
通過預先分配一個最大可能長度的字符串,然后在源字符串中遇到這些數字時,用數字填充該數字,可以完成這一工作。 沒有為每個不受支持的字符刪除,也沒有為每個受支持的字符擴展目標字符串。
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.