在Lua中修改字符串中的字符

时间:2011-03-09 17:21:32

标签: string lua gsub lua-patterns

有没有办法替换Lua中字符串中N位的字符。

这是我到目前为止所提出的:

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处的捕获。

3 个答案:

答案 0 :(得分:12)

Lua中的字符串是不可变的。这意味着,任何替换字符串中的文本的解决方案都必须最终构造一个包含所需内容的新字符串。对于用一些其他内容替换单个字符的特定情况,您需要将原始字符串拆分为前缀部分和后缀部分,并将它们连接在一起围绕新内容。

您的代码的这种变体:

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

是对直截了当的Lua的最直接的翻译。对于大多数用途来说,它可能足够快。我修复了前缀应该是第一个pos-1字符的错误,并利用了如果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 :(得分:5)

你应该在你的函数中使用pos而不是文字13,但除此之外看起来还不错。由于Lua字符串是不可变的,所以你不能做得比这更好。

也许

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

..运算符效率更高,但我对此表示怀疑 - 如果结果是瓶颈,请测量它(然后决定在C中实现此替换函数)。

答案 2 :(得分:0)

使用luajit,您可以使用FFI库将字符串转换为未签名图表的列表:

local ffi = require 'ffi'
txt = 'test'
ptr = ffi.cast('uint8_t*', txt)
ptr[1] = string.byte('o')