【问题标题】:Serialize Lua Table from C++ (via JSON)从 C++ 序列化 Lua 表(通过 JSON)
【发布时间】:2014-01-07 17:27:34
【问题描述】:

我想将复杂数据从 C++ 服务传送到 Lua 应用程序。这种通信通过网络进行。为了 Lua 应用程序的简单性和速度,我更喜欢发送文字 Lua 表文字(不需要单独的解析器)而不是 XML、JSON 或 YAML 等。

虽然存在编写 JSON 的 C++ 库之类的东西,但我找不到用于创建序列化 Lua 的现有 C++ 库。那么,我的想法是使用现有的 C++ JSON 库,然后将字符串转换为 Lua。

所以,例如,我想转换这个字符串:

{
  "hello":42,
  "array":[1,2,{"more":false},null,true],
  "worst":"still [null]: got it?"
}

进入这个字符串:

{
  ["hello"]=42,
  ["array"]={1,2,{["more"]=false},nil,true},
  ["worst"]="still [null]: got it?"
}

一个天真的replace_all 转换为:=[]{},和nullnil 将破坏字符串内的内容。如何执行此转换?

为了避免XY problem 的问题,我在顶部和标题中包含了我的最终动机,以防 JSON->Lua 字符串转换是错误的选择。

【问题讨论】:

  • 嗯,不转换字符串内的内容?这不是很简单,但如果你能做到那个,那么它应该正是你所描述的,不是吗?实际上从 Lua 恕我直言解析 JSON 也不是特别难。带有 LPEG 的 LuaJSON 的快速版本不一定比解析实际的 Lua 代码慢,所以如果你可以让它在脚本中运行,我认为这是一个更简单的选择。我个人对此没有任何问题(在我的情况下,我使用的不仅仅是 C++ 数据源,因此 JSON 是一个合乎逻辑的选择)。
  • 然而,我忘记的一点是,在使用 Lua 表时,您实际上可以使用自动转换为字节码,这应该会明显加快速度。这可以通过使用 BSON 或其他压缩 JSON 格式绕过 OTOH。
  • @BartekBanachewicz 也许我过早地优化了,但我很难相信 LPEG LuaJSON 的速度接近local t = loadstring('return '..json)()
  • 为什么? LPEG 是一个 C 库,实际上是由编写 Lua 本身的同一个人编写的(因此受益于本机代码优化和执行)。即使存在一些速度差异,我也非常怀疑它会相差那么。实际上,对两者进行基准测试并没有什么坏处,对吧? :)
  • @BartekBanachewicz 挑战已接受。 :) LuaJSON 是 ~5x slower than 本地 Lua 加载。

标签: c++ regex json lua


【解决方案1】:

我会自己编写 Lua-format serializing 库。您可以选择一个free software Json C++ 库(例如jsoncpplibjson)并轻松调整其代码(适应您的 Lua 格式)。

当然你应该遵守那个库的许可,我强烈建议你把你的 Lua 格式序列化库本身变成一个免费软件,例如在github 和/或freecode 和/或sourceforge...

关键是JSON(希望是你的 Lua 格式)足够简单,可以很容易地解析或打印它... 使现有库适应你的格式可能比“后处理”更简单,而且肯定更快它的输出...

【讨论】:

    【解决方案2】:

    虽然我今天没有很容易找到它,但我记得大约一年前在 Lua 列表中讨论了定义类似于 JSON 的有限 Lua 表文字子集的优点,称为“LSON”为了讨论。 IIRC,一致认为仅使用 JSON 等已建立的标准轻量级格式并没有足够的好处,但我知道进行了一些实验。

    This Github Gist for lson.lua 在纯 Lua 中演示了一个简单的 LSON 编写器和读取器。编写者只需根据该代码进行适度的努力即可将其转换为 C 或 C++。该代码的一个关键特性是它提供了一些针对循环引用的保护,以及针对可以存储在表中但没有合理的源代码编写机制的数据类型(userdatathread 都是非常有问题的以任何形式序列化)。当然,对于源自 C 中只有轻量级结构的普通旧数据的数据,无论如何您都不会有任何有问题的数据类型。它还可以防止循环引用。如果从 C 中序列化列表或树,循环引用可能通过构造是不可能的。如果没有,您将需要自己处理。

    请注意,使用 Lua 自己的解析器可能会引入安全问题。最明显的问题是只写assert(loadstring('return '..Input))() 就可以让导入的文本访问你当前的整个环境。虽然在输入文本之外应用 return 关键字会产生一些保护,但这仍然不会阻止巧妙地使用可以从表达式调用的任何函数。为了获得最佳安全性,您可能需要阅读 sandboxes 的相关信息,甚至可能会在盲目执行之前应用一些巧妙的技巧来限制已编译的字节码。

    安全问题可能是支持限定和使用 JSON 解析器的有力论据。甚至 javascipt 应用程序也经常更喜欢使用 JSON 解析器,而不仅仅是让 javascript 引擎执行不受信任的内容。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-02
      • 1970-01-01
      相关资源
      最近更新 更多