【问题标题】:Fixing wrong JSON data修复错误的 JSON 数据
【发布时间】:2017-08-25 22:52:12
【问题描述】:

我正在处理从网络下载的 JSON 数据。这个 JSON 的问题是它的内容不正确。为了显示这里的问题是一个简化的预览:

[
  {
    "id": 0,
    "name": "adsad"
  },
  {
    "id": "123",
    "name": "aawew"
  }
]

所以有一个由这些项目组成的数组,其中“id”的某个值是字符串,而某个值是整数。这是我得到的数据,我无法让源解决这个问题。

我想出的解决方案是在序列化之前修复这些数据,这是我的幼稚算法,其中Defaults::intTypes() 是所有键的向量,应该是整数,但有时是字符串:

void fixJSONData(QString& data) {
    qDebug() << "Fixing JSON data ( thread: " << QThread::currentThreadId() << ")";
    QElapsedTimer timer;
    timer.start();

    for (int i = 0; i < data.size(); ++i) {
        for (const auto& key : Defaults::intTypes()) {
            if (data.mid(i, key.size() + 3) == "\"" + key + "\":") {
                int newLine = i + key.size() + 3;

                while (data[newLine] != ',' && data[newLine] != '}') {
                    if (data[newLine] == '"') {
                        data.remove(newLine, 1);
                    } else {
                        ++newLine;
                    }
                }

                i = newLine;
                break;
            }
        }
    }
    qDebug() << "Fixing done in " << timer.elapsed() << " ms.";
}

它确实解决了问题,但算法太慢而且太慢(在 390 秒内处理了 450 万个字符)。怎样才能更快地做到这一点?

P.S.:对于 JSON 序列化,我使用 nlohmann::json 库。

编辑:在深入阅读 JSON 规则之后,看起来上面的示例是绝对有效的 JSON 文件。这应该是与 C++ 强类型依赖相关的问题,因此它无法将不同元素的数组序列化为 C++ 类吗?

Edit2:我想从该 json 字符串创建的是 QVector&lt;Model&gt;,其中:

class Model {
    unsigned id;
    QString name;
}

【问题讨论】:

  • 那个 JSON 文件到底有什么问题? nlohmann::json::parse 似乎正确处理了您的示例。
  • 对于Defaults::intTypes() 中的每个条目,您的算法不必要地查看几乎每一行的几乎每个字符一次。如果您要假设一行中不超过一个字段名称,则应处理每一行一次以提取字段名称(如果有),并查看它是否在整数类型集中。跨度>

标签: c++ json algorithm qt serialization


【解决方案1】:

虽然必须有几种方法来改进这种转换,但也许有更有效的解决方案。

大多数 JSON 库允许最终用户为对象定义自定义序列化器/反序列化器。如果您创建自定义反序列化器,那么它可以解析原始数据,您无需修改​​流或文件。

它不仅更快,而且更优雅。

(如果给定的 JSON 库不支持自定义反序列化,我会考虑选择另一个。)

【讨论】:

  • 我已经有自定义序列化/反序列化功能。问题在于,当尝试从 nlohmann::json 创建模型类时,我不知道如何处理一个键的值可以是 2 种不同的类型
  • @MarošBeťko 您可以使用json::get&lt;int&gt;() 以整数形式检索节点的值。无论如何,它应该在反序列化期间完成,而不是在解析之前。
  • 我不能,因为当它到达 "id": "123" 时会抛出错误,即预期为整数。
  • 我不知道这个特定的JSON库,但通常有一个函数可以检查节点是否为String/number/object/array。首先检查类型,然后将其作为 String 读取,并在需要时转换为 int。最坏的情况:处理错误并作为字符串再次读取。
  • 我找到了is_string() 方法,它可以将std::stoi 字符串转换为int,或者只是将自定义反序列化函数中的int 读取到我的类型。感谢您的建议。
猜你喜欢
  • 2013-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多