8

有什么方法可以替换 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 的捕获。

4

3 回答 3

14

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它等于字符串的结尾。

但请注意,它会创建一些临时字符串,这些字符串将在字符串存储中徘徊,直到垃圾收集吃掉它们。在任何解决方案中都无法避免前缀和后缀的临时性。但这也必须为第一个操作员创建一个临时..操作员以供第二个操作员使用。

两种替代方法中的一种可能会更快。第一个是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的任何字符都可能存在问题。具体来说,由于它是根据标准 C 的函数实现的,因此期望它在第一次出现. (用户妄想逻辑在评论中指出。)\0%ssprintf()\0

想到的第三种选择是:

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

table.concat有效地将字符串列表连接成最终结果。它有一个可选的第二个参数,它是要在字符串之间插入的文本,默认情况下""适合我们这里的目的。

我的猜测是,除非您的字符串很大并且您经常执行此替换,否则您不会看到这些方法之间的任何实际性能差异。但是,我之前曾感到惊讶,因此请分析您的应用程序以验证是否存在瓶颈,并仔细对潜在解决方案进行基准测试。

于 2011-03-10T20:10:25.190 回答
5

您应该pos在函数内部使用而不是文字1and 3,但除此之外它看起来不错。因为 Lua 字符串是不可变的,所以你真的不能做得比这更好。

也许

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

..操作员更有效,但我对此表示怀疑 - 如果结果证明它是一个瓶颈,请测量它(然后决定在 C 中实现这个替换函数)。

于 2011-03-09T18:16:25.093 回答
-1

使用 luajit,您可以使用 FFI 库将字符串转换为无符号图表列表:

local ffi = require 'ffi'
txt = 'test'
ptr = ffi.cast('uint8_t*', txt)
ptr[1] = string.byte('o')
于 2018-09-18T06:17:02.353 回答