2014-10-29 26 views
1

在所涉及接收通過串行鏈路串最近的應用德爾福功能,我發現自己寫的代碼,如:爲了檢查某個特定子是在乞討對於目前測試字符串的位置x的

if (pos('needle', haystack) = 1) then ... 

一個字符串。

我猛然意識到POS機的功能是不理想的這個,因爲它根本不知道我在找哪個位置的子要英寸

是否有一個很好的功能,這是否?

是否有更通用的功能,如IsSubStringAt(needle, haystack, position)

我沒想到用這樣的事情的:

function IsSubstrAt(const needle, haystack: string; position: Integer): Boolean; 
var 
    ii: integer; 
begin 
    result := true; 
    for ii := 1 to length(needle) de begin 
    if (haystack[poition + ii -1] <> needle[ii]) then begin 
     result := false; 
     break; 
    end; 
    end; 
end; 

一些錯誤檢查。

我希望找到一個準備好的滾動答案。

+0

如果針提前到達了鏈接數據的知,你可能會讓自己一點狀態機監聽出來針的陸續到達的人物:我通過修改原德爾福Pos功能使它。 – MartynA 2014-10-29 15:56:13

+0

@Martyn針是已知的,還有99種不同長度的其他針。你會做100個不同的狀態機,還是1個處理全部100個針? – 2014-10-29 16:28:59

+0

好吧,叫我雞先生,但如果只有一根針,我只能真正考慮自己實施一個S-M。 OTOH,肯定會有一些庫代碼在做一個多針,速度優化的代碼。 ISTR早期(我的意思是互聯網前)的站點到站點通信包(可能是串擾)之一就是這樣 - 我在典型的調制解調器固件中找到一個用於識別「At」命令等順便說一句,+1爲非常有趣的q。 – MartynA 2014-10-29 16:42:15

回答

3

既然你只想看一個位置,你可以形成子串並測試它。就像這樣:

function IsSubStringAt(const needle, haystack: string; position: Integer): Boolean; 
var 
    substr: string; 
begin 
    substr := Copy(haystack, position, Length(needle)); 
    Result := substr = needle; 
end; 

如果性能是真正的關鍵,然後再你想不創建副本,並由此進行堆分配執行就地進行比較。你可以使用AnsiStrLComp這個。

function IsSubStringAt(const needle, haystack: string; position: Integer): Boolean; 
begin 
    if Length(haystack) - position + 1 >= Length(needle) then begin 
    Result := AnsiStrLComp(
     PChar(needle), 
     PChar(haystack) + position - 1, 
     Length(needle) 
    ) = 0; 
    end else begin 
    Result := False; 
    end; 
end; 

如果不想敏性檢查到的情況下,在第一個版本SameText替換=,並在第二版用AnsiStrLIComp替換AnsiStrLComp

+0

這看起來不錯,大衛,謝謝。 – 2014-10-29 15:39:33

+0

@KenWhite長度是一個簡單的內存讀取。費用是堆分配。如果需要,可以很容易地刪除。你對Pos的理解是它搜索子串的第一次出現。如果子字符串不在那裏,Pos必須在pos 1,pos 2,pos 3和右邊直到字符串的末尾檢查它。這意味着Pos的運行時間與乾草堆的長度成正比。這是邁克爾想要避免的。 – 2014-10-29 15:47:41

+0

這正是我想要避免的,大衛。你寫得比我更清楚。你的解決方案有一件事是copy()在完成比較之前做了很多工作,但是如果第一個字符不同,那麼代碼不需要再進一步,因爲針不在位置上。 – 2014-10-29 15:55:10

1

由於XE7你可以使用(假設位置基於1):

function IsSubStringAt(const needle, haystack: string; position: Integer): Boolean; 
begin 
    result := string.Compare(hayStack, position-1, needle, 0, needle.Length) = 0; 
end; 
+0

謝謝Uwe。可悲的是我仍然在使用Delphi 6(因爲我們的一些代碼使用Kylix)。當我看到一些新編者具有某些語言特徵時,我會哭泣。例如,我非常想使用未來的變量。 – 2014-10-29 16:05:01

+1

看起來像你有更大的問題,而不僅僅是Pos的性能... – 2014-10-29 16:43:10

+1

我不知道你在感嘆這個代碼中缺乏哪些「新語言特性」。當然不是用於字符串比較的僞對象方法,它僅僅是一個很好的舊式「函數」的句法包裝,它是不支持*頭等函數的OOb(Object Obsessed)語言所必需的。您可以直接使用Windows CompareString()API執行相同的操作,對此,String.Compare()是一個天真的包裝器(在過程中引入了使用基於0的索引的混淆,而不是String類型的基於1的索引裝飾)。 – Deltics 2014-10-29 19:06:47

3

你可以使用CompareMem()來直接比較字符串的內容:

function IsSubStringAt(const aNeedle, aHaystack: String; aPosition: Integer): Boolean; 
    var 
    needleLen: Integer; 
    begin 
    needleLen := Length(aNeedle); 
    result := (needleLen + aPosition - 1) <= Length(aHaystack); 

    if result then 
     result := CompareMem(Pointer(aNeedle), @aHaystack[aPosition], needleLen * sizeof(Char)); 
    end; 

請注意,我們的短期如果幹草堆太短而不能將針頭容納在指定位置,則需要進行比較。

使用CompareMem() API確保實現是便攜,也將與一個Unicode 字符串類型,只要工作(你應該永遠遷移或德爾福的Unicode版本使用此代碼)的大小Char類型被考慮在內,就像這裏所做的那樣。

然而,這種方法假定字符串已經被規範化到所需要的任何程度,使得字符串的字節內容可以直接比較。

+0

這是我回答中的變體2的平臺特定版本,也是Uwe的答案。這兩個都是跨平臺的。在他們實現的窗口上,猜測是什麼,調用CompareString。 – 2014-10-29 20:27:47

+2

非常正確 - 正如你所說,OP在評論中提到Kylix可移植性是一個問題。這很容易通過使用** CompareMem()**來解決,它是可移植的並且最有效的,假設字符串已經被歸一化用於比較目的。這仍然避免使用ANSI包裝程序,它不僅有一定的開銷,而且如果代碼被移植到Unicode,可能會引起混淆(並且絕對令人惱火)。我已經更新了相應的答案,這使得答案和其他答案之間的關係更加清晰。我希望你贊成。 – Deltics 2014-10-29 21:13:03

+0

謝謝你,Deltics – 2014-11-04 13:54:50

2

這是用匯編語言編寫的一個非常快速的方法。

Function PosS (Substr:string; S:string; Position:integer) : integer; 
    Asm 
    TEST EAX,EAX 
    JE  @@NoWork 

    TEST EDX,EDX 
    JE  @@StringEmpty 

    PUSH EBX 
    PUSH ESI 
    PUSH EDI 

    MOV  ESI, EAX       // Pointer to Substr 
    MOV  EDI, EDX       // Pointer to S 
    MOV  EBX, ECX       // Position 
    DEC  EBX 

    MOV  ECX, [EDI-4]      // Length (S) 
    SUB  ECX, EBX 

    PUSH EDI 
    ADD  EDI, EBX 

    MOV  EDX, [ESI-4]      // Length (Substr) 

    DEC  EDX 
    JS  @@Fail 
    MOV  AL, [ESI] 
    INC  ESI 

    SUB  ECX, EDX       // = Length (S) - Length (Substr) + 1 
    JLE  @@Fail 
@@Loop: 
    REPNE SCASB 
    JNE  @@Fail 
    MOV  EBX, ECX 
    PUSH ESI 
    PUSH EDI 

    MOV  ECX, EDX 
    REPE CMPSB 
    POP  EDI 
    POP  ESI 
    JE  @@Found 
    MOV  ECX, EBX 
    JMP  @@Loop 

@@Fail: 
    POP  EDX 
    XOR  EAX, EAX 
    JMP  @@Exit 

@@StringEmpty: 
    XOR  EAX, EAX 
    JMP  @@NoWork 

@@Found: 
    POP  EDX 
    MOV  EAX, EDI 
    SUB  EAX, EDX 
@@Exit: 
    POP  EDI 
    POP  ESI 
    POP  EBX 
@@NoWork: 
    End; 
+0

這肯定是一個非常古老的Pos功能。最新的情況相當複雜和令人費解。 – 2014-10-30 07:59:55

+0

謝謝你,adlabac,我會給它一個。 – 2014-11-04 13:51:27

相關問題