我如何循环遍历字符串中的每个 string.gmatch 然后用字节码版本替换匹配项?

How'd i loop through every string.gmatch in a string then replacing the matches with a bytecoded version of that?

如何在不更改不匹配项的情况下更改字符串中匹配的所有内容?

local a = "\" Hello World! I want to replace this with a bytecoded version of this!\" but not this!"

for i in string.gmatch(a, "\".*\"") do
    print(i)
end

例如我想要[["Hello World!" Don't Replace this!]][["18811480" Don't Replace this!]]

你需要string.gsub.

local a = "\"Hello World!\" Don't Replace this!"
local function convert(str)
  local byte_str = ""
  for i = 1, #str do
    byte_str = byte_str .. "\" .. tostring(string.byte(str, i))
  end
  return byte_str
end
a = string.gsub(a, "\"(.*)\"", function(matched_str)
  return "\"" .. convert(matched_str) .. "\""
end)
print(a)


你的问题有点棘手,因为它可能涉及:

首先,如果您需要实现 Lua 模式,请知道有一个非常方便的 Lua 语法,它非常适合处理 引用的字符串。使用此语法,您可以使用字符 [[]] 代替 opening/closing 带双引号的字符串。关键区别在于,在这些标记之间,您不必再转义引用的字符串!

String = [["Hello World!" Don't Replace this!]]

然后,我们需要构建正确的 Lua 模式,可能是匹配双引号 (") 然后匹配所有 的字符不是 双引号 ("),这给了我们以下模式:

[["([^"]+)"]]
  | ****  |
  |   \-> the expression to match
  |       |
 quote   quote

那么如果我们研究函数string.gsub,我们可以知道该函数可以在匹配模式时调用callback,匹配的字符串将替换为 return 回调值.

function ConvertToByteString (MatchedString)
  local ByteStrings = {}
  local Len         = #MatchedString
  
  ByteStrings[#ByteStrings+1] = [[\"]]
  
  for Index = 1, Len do
    local Byte = MatchedString:byte(Index)
    ByteStrings[#ByteStrings+1] = string.format([[\%d]], Byte)
  end
  
  ByteStrings[#ByteStrings+1] = [[\"]]
  
  return table.concat(ByteStrings)
end

在这个function中,我们遍历匹配字符串的所有字符。然后对于每个字符,我们使用函数 string.byte 提取其字节值,并使用 string.format 函数将其转换为字符串。我们将这个字符串放在一个临时数组中,我们将在函数末尾连接该数组。

将子字符串连接成更大字符串的函数是table.concat。这是一个非常方便的功能,可以按如下方式使用:

> table.concat({ [[]], [[]], [[]] })

我们剩下要做的就是测试这个出色的功能:

> String = [["Hello World!" Don't Replace this!]]
> NewString = String:gsub([["([^"]+)"]], ConvertToByteString)
> NewString
\"18811480\" Don't Replace this!

编辑:我收到了一些关于代码性能的评论,我个人不太关注性能,我专注于让代码正确和简单。为了解决性能问题,我写了一个微基准来比较版本:

function SOLUTION_DarkWiiPlayer (String)
  local result = String:gsub('"[^"]*"', function(str)
                          return str:gsub('[^"]', function(char)
                                            return "\" .. char:byte()
                          end)
  end)
  return result
end

function SOLUTION_Robert (String)
  local function ConvertToByteString (MatchedString)
    local ByteStrings = {}
    local Len         = #MatchedString
    
    ByteStrings[#ByteStrings+1] = [[\"]]
    
    for Index = 1, Len do
      local Byte = MatchedString:byte(Index)
      ByteStrings[#ByteStrings+1] = string.format([[\%d]], Byte)
    end
    
    ByteStrings[#ByteStrings+1] = [[\"]]
    
    return table.concat(ByteStrings)
  end
  local Result = String:gsub([["([^"]+)"]], ConvertToByteString)
  return Result
end

function SOLUTION_Piglet (String)
  return String:gsub('%b""' , function (match)
                       local ret = ""
                       for _,v in ipairs{match:byte(1, -1)} do
                         ret = ret .. string.format("\%d", v)
                       end
                       return ret
  end)
end

function SOLUTION_Renshaw (String)
  local function convert(str)
    local byte_str = ""
    for i = 1, #str do
      byte_str = byte_str .. "\" .. tostring(string.byte(str, i))
    end
    return byte_str
  end
  local Result = string.gsub(String, "\"(.*)\"", function(matched_str)
                               return "\"" .. convert(matched_str) .. "\""
  end)
  return Result
end

String = "\"Hello World!\" Don't Replace this!"

print("INITIAL REQUIREMENT FROM OP ", [[\"18811480\" Don't Replace this!]])
print("TEST SOLUTION_Robert:       ", SOLUTION_Robert(String))
print("TEST SOLUTION_DarkWiiPlayer:", SOLUTION_DarkWiiPlayer(String))
print("TEST SOLUTION_Piglet:       ", SOLUTION_Piglet(String))
print("TEST SOLUTION_Renshaw:      ", SOLUTION_Renshaw(String))

结果表明,只有一个答案可以 100% 满足 OP 的要求。其他答案没有正确处理第一个和结束双引号 "

INITIAL REQUIREMENT FROM OP     \"18811480\" Don't Replace this!
TEST SOLUTION_Robert:           \"18811480\" Don't Replace this!
TEST SOLUTION_DarkWiiPlayer:    "18811480" Don't Replace this!
TEST SOLUTION_Piglet:           18811480 Don't Replace this!  1
TEST SOLUTION_Renshaw:          "18811480" Don't Replace this!

要完成此 post,可以更深入地研究并使用微基准检查代码性能,该基准可能 copy/paste 直接在 Lua 解释器中。

function SOLUTION_DarkWiiPlayer (String)
  local result = String:gsub('"[^"]*"', function(str)
                          return str:gsub('[^"]', function(char)
                                            return "\" .. char:byte()
                          end)
  end)
  return result
end

function SOLUTION_Robert (String)
  local function ConvertToByteString (MatchedString)
    local ByteStrings = {}
    local Len         = #MatchedString
    
    ByteStrings[#ByteStrings+1] = [[\"]]
    
    for Index = 1, Len do
      local Byte = MatchedString:byte(Index)
      ByteStrings[#ByteStrings+1] = string.format([[\%d]], Byte)
    end
    
    ByteStrings[#ByteStrings+1] = [[\"]]
    
    return table.concat(ByteStrings)
  end
  local Result = String:gsub([["([^"]+)"]], ConvertToByteString)
  return Result
end

function SOLUTION_Piglet (String)
  return String:gsub('%b""' , function (match)
                       local ret = ""
                       for _,v in ipairs{match:byte(1, -1)} do
                         ret = ret .. string.format("\%d", v)
                       end
                       return ret
  end)
end

function SOLUTION_Renshaw (String)
  local function convert(str)
    local byte_str = ""
    for i = 1, #str do
      byte_str = byte_str .. "\" .. tostring(string.byte(str, i))
    end
    return byte_str
  end
  local Result = string.gsub(String, "\"(.*)\"", function(matched_str)
                               return "\"" .. convert(matched_str) .. "\""
  end)
  return Result
end

---
--- Micro-benchmark environment
---

COUNT = 600000

function TEST_Function (Name, Function, String, Count)
  local TimerStart = os.clock()
  for Index = 1, Count do
    Function(String)
  end
  local ElapsedSeconds = (os.clock() - TimerStart)
  print(string.format("[%25.25s] %f sec", Name, ElapsedSeconds))
end

String = "\"Hello World!\" Don't Replace this!"

TEST_Function("SOLUTION_DarkWiiPlayer", SOLUTION_DarkWiiPlayer, String, COUNT)
TEST_Function("SOLUTION_Robert",        SOLUTION_Robert,        String, COUNT)
TEST_Function("SOLUTION_Piglet",        SOLUTION_Piglet,        String, COUNT)
TEST_Function("SOLUTION_Renshaw",       SOLUTION_Renshaw,       String, COUNT)

结果显示@DarkWiiPlayer的回答是最快的

[   SOLUTION_DarkWiiPlayer] 6.363000 sec
[          SOLUTION_Robert] 9.605000 sec
[          SOLUTION_Piglet] 7.943000 sec
[         SOLUTION_Renshaw] 8.875000 sec
local a = "\"Hello World!\" but not this!"

print(a:gsub('"[^"]*"', function(str)
  return str:gsub('[^"]', function(char)
    return "\" .. char:byte()
  end)
end))
local a = "\" Hello World! I want to replace this with a bytecoded version of this!\" but not this!"

print((a:gsub('%b""' , function (match)
  local ret = ""
  for _,v in ipairs{match:byte(1, -1)} do
    ret = ret .. string.format("\%d", v)
  end
  return ret
end)))