想象一下,您在CSV文件中有一个具有这种布局的表格:
name,property1 [unit1],property2 [unit2] name1,4.5,2.3 name2,3.2,7.4 name3,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文件,所以我也无法真正改变它。
所有这一切,我意识到我需要一些东西,所以这是一个多重问题:
QList<QString>
中,将每列分隔为字符串。我如何设法同步所有数据位,以便在QString上创建我需要的JSON结构? (我想我需要在QString中使用它,所以我可以将每一行转储到另一个文件中,但我也可以使用其他选项)最后一个注意事项 - 我还需要这个可扩展性。将在其中显示的CSV文件在列数中非常不同:有些列有8列,有些有20列。
我知道发布“多项目”并不是一个好习惯,但问题是我对这一切感到太不知所措了,因为我几乎没有Qt的经验,所以我甚至无法定义一个计划攻击这个。希望有人可以分享一些指示。谢谢!
修改 所以,我一直在考虑这个问题,我实际上并不知道这是不是一个好主意/可行,但这就是我的想法:
这有什么意义吗?任何人都可以嘲笑我可以为此工作的骨架吗?
EDIT2
到目前为止,我已经成功完成了一些工作,但仍未按预期工作。现在我已经设法从CSV文件正确读取,但输出不正确。谁能分享一些见解?
注意: processLineFromCSV 函数返回如下所示的QStringList:QStringList cells = line.split(separator_char);
注2:RegEx是从this回答中获得的。
注3:检查下面我输出的输出类型。现在我认为问题更多地与qt-json
库的使用相关,而不是其他代码,但欢迎任何帮助! :)
到目前为止的代码:
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\" }"
]"
答案 0 :(得分:1)
Joum。
刚刚看到你对我评论的回应。我对QT也没有多少经验,但是快速概述......
一次提取一行数据,并将其“拆分”为一个数组。如果您使用的是CSV,则需要确保没有包含逗号的数据点,否则拆分将导致真正的混乱。检查提取数据的人是否可以使用另一个“不太常见”的分隔符(例如“|”是好的)。如果您的数据都是很好的数字,但要警惕使用逗号作为小数分隔符的位置:(
我希望你的每个文件都有1个'表',如果不是你需要能够“识别”新表以某种方式启动,这可能很有趣/有趣 - 取决于你的前景;)。
最后你会得到一个'字符串数组'(某种表格)的集合,希望第一个是你的标题信息。如果你有多个表格,你将一次处理一个
您现在应该能够以良好的JSON格式“输出”每个表。
从标题行中获取“单位”:如果您事先知道它们所在的位置(即数组中的索引),您可以计划在正确的索引位置提取信息(如果您愿意,使用正则表达式)
最后一点。 如果您的csv文件非常长(数百行),只需将前几个文件放入一个新的测试文件中以便更快地进行调试,然后一旦您满意,请稍微放大并检查输出格式...然后再次使用很高兴没有其他错误...对于整个文件 同样,如果你的文件中有多个表,只从第一个表开始,然后添加第二个的第一部分......测试....添加第三部分....测试等等,直到你感到高兴
大卫。
在阅读关于想要某种形式的“同步”的评论之后,可能是更好的解决方案。 注意:这可能看起来有点复杂,但我认为最终它将是一个更灵活的解决方案。这个数据也不存在于DB的某个地方(谁给了你?),它们能否直接读取对底层数据库和表的读取权限?如果是这样,你可以直接跳到'将每个表输出到JSON'步骤。
使用嵌入式DB(即SQLite)。 提取第一个“标题”行,并在数据库中创建一个跟随信息的表(您应该能够将有关单位的信息添加到'元数据',即描述)。如果所有文件都相同,您甚至可以将所有数据导入到同一个表中,或者使用相同的create table语句为每个新文件自动创建一个新表(假设格式相同)。
我确信SQLite中有一个'csvimport'(我还没有检查过文档,并且暂时还没有这样做)或者有人编写了一个可以执行此操作的库。
将每个表格输出为JSON格式,我再次确定有人为此编写了一个库。
答案 1 :(得分: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
}
答案 2 :(得分: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