2011-03-09 69 views
6

是否有任何方法可以用Lua中的字符串替換位置N處的字符。在Lua中修改字符串中的字符

這是我想出迄今:

function replace_char(pos, str, r) 
    return str:sub(pos, pos - 1) .. r .. str:sub(pos + 1, str:len()) 
end 

str = replace_char(2, "aaaaaa", "X") 
print(str) 

我不能使用GSUB無論是作爲將取代每次捕捉,而不僅僅是捕捉在位置N.

回答

12

Lua中的字符串是不可變的。這意味着,任何替換字符串中文本的解決方案必須最終構建一個具有所需內容的新字符串。對於使用其他內容替換單個字符的特定情況,您需要將原始字符串拆分爲前綴部分和後綴部分,然後將這些字符串連接在新內容周圍。

您的代碼這種變化:

function replace_char(pos, str, r) 
    return str:sub(1, pos-1) .. r .. str:sub(pos+1) 
end 

是最直接的翻譯直白的Lua。對於大多數目的而言,這可能足夠快。我已經修復了前綴應該是第一個字符的錯誤,並利用了這樣的事實:如果缺少string.sub的最後一個參數,則假定爲-1,這相當於字符串的末尾。

但請注意,它會創建一些臨時字符串,這些字符串將在字符串存儲中四處停留,直到垃圾收集吃掉它們。任何解決方案都無法避免前綴和後綴的臨時對象。但是這也必須爲第一個運營商的第一個運營商創建一個臨時性的服務。

有可能兩種替代方法中的一種可能會更快。首先是solution offered by Paŭlo Ebermann,但有一個小的調整:

function replace_char2(pos, str, r) 
    return ("%s%s%s"):format(str:sub(1,pos-1), r, str:sub(pos+1)) 
end 

這使用string.format做結果的組件,它可以猜到最後的緩衝區大小,而不需要額外的臨時對象的希望。

但要小心string.format很可能與任何字符串中的任何\0字符有關,它會通過它的%s格式。具體而言,因爲它是以標準C的sprintf()函數的形式實現的,所以期望它在第一次出現\0時終止替換字符串是合理的。 (用戶在註釋中註明用戶Delusional Logic。)

想到的第三種選擇是這樣的:

function replace_char3(pos, str, r) 
    return table.concat{str:sub(1,pos-1), r, str:sub(pos+1)} 
end 

table.concat有效連接字符串列表到最終的結果。它有一個可選的第二個參數,它是在字符串之間插入的文本,默認爲"",這適合我們的目的。

我的猜測是,除非你的字符串很大,並且經常進行這種替換,否則這些方法之間不會有任何實際的性能差異。不過,我之前感到很驚訝,因此請通過簡要介紹您的應用程序來驗證是否存在瓶頸,並仔細地對潛在解決方案進行基準測試

+1

感謝您的深入解釋 – dotminic

+1

這是舊的。但我剛完成解決了我寫的一些代碼中的一個小錯誤。原來''replace_char2''方法不會插入空(''\ 0'')字符。 –

+0

@DelusionalLogic好點。 'string.format'基於標準C的'sprintf()'函數,可能會遇到嵌入式NUL字節的問題。 – RBerteig

5

你應該在你的功能中使用pos而不是文字13,但除此之外它看起來不錯。由於Lua字符串是不可變的,所以你不可能比這更好。

也許

"%s%s%s":format(str:sub(1,pos-1), r, str:sub(pos+1, str:len()) 

..運營商更有效,但我對此表示懷疑 - 如果它原來是一個瓶頸,衡量它(再決定裏用C實現這個替換功能)。

+1

是的,'..'運算符是連接字符串最慢的方法,因爲每個'..'都會創建一個新的字符串。更快的方法包括'string.format'和'table.concat'。這應該不會引起任何明顯的影響,除非您正在處理非常大的字符串或許多級聯操作。例如,我有一個使用超過500MB內存的腳本,通過在每行輸入中使用大約5'..'來處理少於1MB的文件,同時對輸入進行排序並重建爲輸出。將它改爲在表中存儲字符串,並在末尾存儲'table.concat'使其變得如此之快,我甚至不會去衡量。 – Arrowmaster

+1

@Arrowmaster:你知道在'a .. b .. c'中創建了兩個(而不是隻有一個)新字符串,還是你簡單地假設這個?原則上這可以通過編譯器/解釋器來優化,只創建一個新的字符串,就像在Java中爲'+'操作符所做的那樣。你的例子是另一種情況,因爲你真的必須用每個語句創建新的字符串。 –

+0

@PaŭloEbermann是的,我剛剛複製了代碼,忘記刪除文字。 @Arrowmaster @PaŭloEbermann我會將..運算符與format方法進行比較。感謝您的洞察力。 – dotminic