2

想象一下,您在 CSV 文件中有一个具有这种布局的表格:

名称,property1 [unit1],property2 [unit2]
名称1,4.5,2.3
名称2,3.2,7.4
名称3,5.5,6.1

我需要将每一行转换为这种 JSON 结构(即,对于第 1 行):

{
    "name1": [
        {
            "properties": [
                {
                    "property_1": "_value_",
                    "unit": "unit1"
                },
                {
                    "property_2": "_value_",
                    "unit": "unit2"
                }
            ]
        }
    ]
}

最重要的是,我必须解释我使用的是 Qt 4.7 并且无法更新;另外,我无法安装 Qxt,所以我依赖qt-json进行 JSON 解析/编码。此外,CSV 文件不是由我创建/维护的,所以我也无法真正更改它。

所以有了这一切,我意识到我需要一些东西,所以这是一个多重问题:

  • 我应该如何编写正则表达式来读取每列标题中的单位?请注意,单位括在右括号中。
  • 想象一下,我将标题行和其他行都提取到 aQList<QString>中,将每一列分隔为一个字符串。我如何设法同步所有数据位以便在 QString 上创建我需要的 JSON 结构?(我想我需要它在 QString 中,所以我可以将每一行转储到不同的文件中,但我也对其他选项持开放态度)

最后一点 - 我还需要它具有一定的可扩展性。将应用它的 CSV 文件的列数非常不同:有些有 8 列,有些有 20 列。

我知道发布“多问题”不是一个好习惯,但问题是我对这一切感到不知所措,而且因为我几乎没有使用 Qt 的经验,我什至无法定义一个计划来解决这个问题. 希望有人可以分享一些指针。谢谢!

编辑 所以,我一直在思考这个问题,我实际上不知道这是否是一个好主意/可行,但这是我的想法:

  • 浏览标题行时,我会检查每个列字符串是否对 RegEx 有影响。如果是这样,我会将列索引和单位字符串存储在一个列表中;
  • 然后,在遍历其他行时,为了将它们解析为 JSON,我将检查每一列是否与上一个列表中的索引匹配,如果是,我会将单元添加到地图中(如 qt- json 文档解释)

这有道理吗?任何人都可以模拟一个我可以为此工作的骨架吗?

编辑2

到目前为止,我已经设法完成了一些工作,但仍然无法正常工作。现在我已经设法从 CSV 文件中正确读取,但输出不正确。任何人都可以分享一些见解吗?

注意:processLineFromCSV函数返回一个获得的 QStringList,如下所示:QStringList cells = line.split(separator_char);

注2:正则表达式是从这个答案中获得的。

注意3:检查下面我得到的输出类型。现在我认为这个问题更多地与qt-jsonlib 的使用有关,而不是与代码的其余部分有关,但欢迎任何帮助!:)

到目前为止的代码:

QFile file(csvfile);

    if (file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        bool first = true;
        QVariantMap map;
        QVariantMap propertyMap;
        QList<QVariant> generalList, propertiesList;

        while (!file.atEnd())
        {
            QString line = file.readLine();
            if(first == true){
                headerList = processLineFromCSV(line, separator_char);
                first = false;
            }else{

            QStringList cellList = processLineFromCSV(line, separator_char);

            int i=0;

            for(i; i<cellList.size(); i++)
            {
                // check the header cell for "[unit]" string
                // returns -1 if does not have the string
                // if it has the string, it's stored in capturedUnits[1]
                int test = exp.indexIn(headerList.at(i));

                // store the captured units in a QStringList
                QStringList capturedUnits = exp.capturedTexts();

                if(test==-1){ // if header does not have a captured unit - general column
                    QString name = headerList.at(i);
                    QString sanitizeName= name.remove(exp.capturedTexts().at(0), Qt::CaseSensitive);
                    map[sanitizeName] = cellList.at(i);
                }
                else{ // if header string has a captured unit - property column

                    QString propertyName = headerList.at(i); // extract string in header
                    QString sanitizedPropertyName = propertyName.remove(exp); //remove the unit regex from the string
                    sanitizedPropertyName.remove(QChar('\n'), Qt::CaseSensitive); // clear newlines

                    if(sanitizedPropertyName.startsWith('"') && sanitizedPropertyName.endsWith('"'))
                    {
                        sanitizedPropertyName.remove(0,1);
                        sanitizedPropertyName.remove(sanitizedPropertyName.length(),1);
                    }

                    QString value =cellList.at(i); // extract string in value
                    QString sanitizedValue = value.remove(QChar('\n'), Qt::CaseSensitive); // clear newlines

                    if(sanitizedValue.startsWith('"') && sanitizedValue.endsWith('"'))
                    {
                        sanitizedValue.remove(0,1);
                        sanitizedValue.remove(sanitizedValue.length(),1);
                    }

                    propertyMap[sanitizedPropertyName]= sanitizedValue; // map the property: value pair
                    propertyMap["unit"] = capturedUnits.at(1); // map the unit: [unit] value pair

                    QByteArray general = QtJson::serialize(map); // serialize the pair for general column
                    QByteArray properties = QtJson::serialize(propertyMap); // serialize the pair for property column

                    QVariant genVar(general);
                    QVariant propVar(properties);

                    generalList.append(genVar);
                    propertiesList.append(propVar);
                }
            }
        }}
        QByteArray finalGeneral = QtJson::serialize(generalList);
        QByteArray finalProperties = QtJson::serialize(propertiesList);

        qDebug() << finalGeneral;
        qDebug() << finalProperties;


        file.close();
    }

输出:

"[
    "{ \"name\" : \"name1\" }",
    "{ \"name\" : \"name1\" }",
    "{ \"name\" : \"name2\" }",
    "{ \"name\" : \"name2\" }",
    "{ \"name\" : \"name3\" }",
    "{ \"name\" : \"name3\" }"
]" 
"[
    "{ \"property1 \" : \"4.5\", \"unit\" : \"unit1\" }",
    "{ \"property1 \" : \"4.5\", \"property2 \" : \"2.3\", \"unit\" : \"unit2\" }",
    "{ \"property1 \" : \"3.2\", \"property2 \" : \"2.3\", \"unit\" : \"unit1\" }",
    "{ \"property1 \" : \"3.2\", \"property2 \" : \"7.4\", \"unit\" : \"unit2\" }",
    "{ \"property1 \" : \"5.5\", \"property2 \" : \"7.4\", \"unit\" : \"unit1\" }",
    "{ \"property1 \" : \"5.5\", \"property2 \" : \"6.1\", \"unit\" : \"unit2\" }"
]"
4

3 回答 3

1

杂志。

刚刚看到你对我评论的回复。我对 QT 也没有太多经验,但有一个快速的概述......

一次提取一行数据,并将其“拆分”为一个数组。如果您使用的是 CSV,则需要确保其中没有包含逗号的数据点,否则拆分将导致真正的混乱。与提取数据的人核实他们是否可以使用另一个“不太常见”的分隔符(例如,“|”很好)。如果您的数据都是很好的数字,但要小心使用逗号作为小数分隔符的位置:(

我希望每个文件有 1 个“表格”,如果没有,您需要能够“识别”新表格何时以某种方式开始,这可能很有趣/有趣 - 取决于您的前景;)。

最后,您将拥有一组“字符串数组”(某种表格),希望第一个是您的标题信息。如果您有多个表,您将一次处理一个

您现在应该能够以良好的 JSON 格式“输出”每个表。

从标题行中获取“单位”:如果您事先知道它们的位置(即数组中的索引),您可以计划在正确的索引位置提取信息(如果您愿意,可以使用正则表达式)。

最后一点。如果您的 csv 文件很长(数百行),只需将前几行抓取到一个新的测试文件中以便更快地调试,然后一旦您满意,将其放大一点并检查输出格式......然后再一次很高兴没有其他错误...对于整个文件同样,如果您的文件中有多个表,请仅从第一个表开始,然后添加第二个的第一部分...测试....添加第三个.... 测试等等等等,直到你满意为止

大卫。

在阅读您关于想要某种形式的“同步”的评论后,一个可能更好的解决方案。注意:这可能看起来有点复杂,但我认为最终它会是一个更灵活的解决方案。此外,这些数据是否不存在于某处的数据库中(谁给你的?),它们可以让你直接读取底层数据库和表吗?如果是这样,您可以直接跳到“将每个表输出到 JSON”步骤。

使用嵌入式数据库(即 SQLite)。提取第一个“标题”行,并在数据库中创建一个遵循那里信息的表(您应该能够将有关单位的信息添加到“元数据”,即描述)。如果您的所有文件都相同,您甚至可以将所有数据导入同一个表中,或者使用相同的 create table 语句为每个新文件自动创建一个新表(假设格式相同)。

我确定 SQLite 中有一个“csvimport”(我还没有检查文档,并且有一段时间没有这样做)或者有人编写了一个可以执行此操作的库。

将每个表输出为 JSON 格式,我确信有人为此编写了一个库。

于 2013-06-11T08:34:19.423 回答
1

这对你来说应该是一个好的开始:

QString csv = "name,property1 [unit1],property2 [unit2],property3 [unit3]\n"
              "name1,4.5,2.3\n"
              "name2,3.2,7.4\n"
              "name3,5.5,6.1,4.3\n";

QStringList csvRows = csv.split('\n', QString::SkipEmptyParts);
QStringList csvHeader = csvRows.takeFirst().split(',');
csvHeader.removeFirst();

foreach(QString row, csvRows) {
    QStringList values = row.split(',');
    QString rowName = values.takeFirst();

    QVariantList properties;
    for(int i = 0; i < values.size(); i++) {
        QString value = values[i];
        QStringList propParts = csvHeader[i].split(' ');
        QString propName = propParts[0];
        QString propType = propParts[1].mid(1, propParts[1].size() - 2);

        QVariantMap property;
        property[propName] = value;
        property["unit"] = propType;

        properties.append(property);
    }

    QVariantMap propertyObj;
    propertyObj["properties"] = properties;
    QVariantList propList;
    propList.append(propertyObj);

    QVariantMap root;
    root[rowName] = propList;

    QByteArray json = QtJson::serialize(root);
    qDebug() << json;

    // Now you can save json to a file
}
于 2013-06-12T15:11:01.630 回答
1

使用 ExplodingRat 的答案,这是最终代码:(最后没有创建文件)

QString csvfile = ui->lineEditCSVfile->text();
    QString separator_char = ui->lineEditSeparator->text();
    QRegExp exp("\\[([^\\]]+)\\]");

    QFile file(csvfile);
     if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
         return;

    QString csv = file.readAll();

    QStringList csvRows = csv.split('\n', QString::SkipEmptyParts);

    QStringList csvHeader = csvRows.takeFirst().split(separator_char);

    csvHeader.removeFirst();

    foreach(QString row, csvRows) {
        QStringList values = row.split(separator_char);

        QString rowName = values.takeFirst();

        QVariantList general;
        QVariantList properties;
        for(int i = 0; i < values.size(); i++) {
            QString value = values[i];

            int test = exp.indexIn(csvHeader[i]);
            //qDebug() << test;

            //qDebug() << csvHeader;
            QStringList capturedUnits = exp.capturedTexts();
            QString propName = csvHeader[i];


            if(test==-1){
                //QString propName = csvHeader[i].remove(exp);
                //qDebug() <<"property name" << propName;

                QVariantMap property;
                property[propName] = value;
                general.append(property);
            }else{
                propName.remove(exp);
                //QStringList propParts = csvHeader[i].split(' ');
                //QString propName = csvHeader[i].remove(exp);
                QString propType = capturedUnits[1];

                QVariantMap property;
                property[propName] = value;
                property["unit"] = propType;

                properties.append(property);
            }
        }

        QVariantMap propertyObj;
        propertyObj["properties"] = properties;
        QVariantList propList;
        propList.append(propertyObj);

        QVariantMap generalObj;
        generalObj["general"] = general;
        QVariantList generalList;
        generalList.append(generalObj);

        QVariantList fullList;
        fullList.append(generalObj);
        fullList.append(propertyObj);

        QVariantMap root;
        root[rowName] = fullList;

        QByteArray json = QtJson::serialize(root);

        json.prepend('[');
        json.append(']');

        qDebug() << json;

        // Now you can save json to a file
于 2013-06-13T10:07:18.100 回答