字符串洗牌和解密(Lua)

我有一个函数可以从另一篇文章中洗牌字符串,该函数使用预定义数字的表来重新排序字符。它完美地工作,因此我也需要一个使用数字表解密该字符串的函数,但是我不知道怎么做,尤其是在尝试并多次失败之后。

洗牌函数:

randomValues = {}
for i = 1, 60 do
   table.insert(randomValues, 1, math.random())
end
function shuffle(str)
   math.randomseed(4)
   local letters = {}
   local idx = 0
   for letter in str:gmatch'.[\128-\191]*' do
      idx = idx + 1
      table.insert(letters, {letter = letter, rnd = randomValues[idx]})
   end
   table.sort(letters, function(a, b) return a.rnd < b.rnd end)
   for i, v in ipairs(letters) do
      letters[i] = v.letter
   end
   return table.concat(letters)
end

有什么技巧吗?

点赞
用户6924740
用户6924740

我假设你的目标是:

  1. 将字符串拆分为 Unicode 字符。
  2. 洗牌这些字符。
  3. 将字符恢复到它们原来的位置。

我已经将拆分 Unicode 字符和进行实际洗牌分开了,以使其更易于跟进。

1. 拆分字符

从拆分字符开始:

-- 将字符串拆分为 Unicode 字符的表。
local function splitLetters(str)
  local letters = {}
  for letter in str:gmatch'.[\128-\191]*' do
     table.insert(letters, letter)
  end
  return letters
end

这主要是从你的函数的第一部分复制过来的。

2. 洗牌字符表

现在我们有了一个好的字符表,可以进行洗牌。可以通过逐个字符地遍历并与任意一个尚未洗牌的项目进行交换来对列表进行洗牌。在这样做的同时,我们还保持了所有被交换的索引的表,我在这里称之为 swapTable

-- 原地洗牌并返回可用于取消混洗的表。
local function shuffle(items)
  local swapTable = {}
  for i = 1, #items - 1 do
    -- 将第一个条目与随机条目(包括它本身)交换。
    local j = math.random(i, #items)
    items[i], items[j] = items[j], items[i]
    -- 跟踪每个交换,以便我们可以撤消它。
    table.insert(swapTable, j)
    -- 现在的每一项都是随机的。
    -- 最后一次迭代可以跳过,因为它总是会与自己交换。
    -- 请参阅循环顶部的#项-1。
  end
  return swapTable
end

3. 将字符恢复到原来的位置

现在使用这个 swapTable,反转整个洗牌过程就非常简单了。

-- 原地还原以前的洗牌。
local function unshuffle(items, swapTable)
  -- 向后遍历交换表,因为我们需要反向执行所有操作。
  for i = #swapTable, 1, -1 do
    -- 与之前相同,但是使用交换表。
    local j = swapTable[i]
    items[i], items[j] = items[j], items[i]
  end
end

使用所有这些功能的完整示例

使用这些函数(和 table.concat 将字母列表构建回字符串)我们可以做到你想要的一切:

-- 让我们的输出可重现
math.randomseed(42)

-- 将测试字符串拆分为 Unicode 字符表
local letters = splitLetters("Hellö Wörld! Höw are yoü?")

-- 洗牌它们,在此同时获取 swapTable。
local swapTable = shuffle(letters)

-- 打印洗牌后的字符串
print(table.concat(letters)) --> " rH?doröWüle Hl lwa eyöö!"

-- 使用 swapTable 原地取消混洗。
unshuffle(letters, swapTable)

-- 我们又回到了原来的字符串。
print(table.concat(letters)) --> "Hellö Wörld! Höw are yoü?"

预先创建 swapTable

在你的示例中,你提前生成了 swapTable(它还略有不同)。当然,你可以将该部分拆分出来,并使 shuffle 函数的工作方式类似于当前实现的 unshuffle。如果需要,告诉我我详细说明。

2021-08-20 07:50:53