You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
164 lines
3.5 KiB
C++
164 lines
3.5 KiB
C++
#include "stdafx.h"
|
|
#include "TsvParser.h"
|
|
|
|
//=============================================================================
|
|
// TableData 成员函数实现
|
|
//=============================================================================
|
|
|
|
int TsvParser::TableData::GetColumnIndex(const CString& columnName) const
|
|
{
|
|
CString key = columnName;
|
|
key.MakeUpper();
|
|
key.Trim();
|
|
|
|
auto it = columnIndexMap.find(key);
|
|
if (it != columnIndexMap.end())
|
|
return it->second;
|
|
|
|
return -1;
|
|
}
|
|
|
|
CString TsvParser::TableData::GetValue(const std::vector<CString>& row, const CString& columnName) const
|
|
{
|
|
int index = GetColumnIndex(columnName);
|
|
return GetValue(row, index);
|
|
}
|
|
|
|
CString TsvParser::TableData::GetValue(const std::vector<CString>& row, int columnIndex) const
|
|
{
|
|
if (columnIndex >= 0 && columnIndex < (int)row.size())
|
|
{
|
|
CString value = row[columnIndex];
|
|
value.Trim();
|
|
return value;
|
|
}
|
|
return _T("");
|
|
}
|
|
|
|
double TsvParser::TableData::GetDoubleValue(const std::vector<CString>& row, const CString& columnName, double defaultValue) const
|
|
{
|
|
CString strValue = GetValue(row, columnName);
|
|
if (strValue.IsEmpty())
|
|
return defaultValue;
|
|
|
|
return _tstof(strValue);
|
|
}
|
|
|
|
//=============================================================================
|
|
// TsvParser 实现
|
|
//=============================================================================
|
|
|
|
bool TsvParser::Parse(const CString& tsvData, TableData& outTableData)
|
|
{
|
|
outTableData.headers.clear();
|
|
outTableData.rows.clear();
|
|
outTableData.columnIndexMap.clear();
|
|
|
|
if (tsvData.IsEmpty())
|
|
{
|
|
TRACE("TsvParser::Parse - 数据为空\n");
|
|
return false;
|
|
}
|
|
|
|
// 分割数据为行
|
|
std::vector<CString> lines;
|
|
SplitLines(tsvData, lines);
|
|
|
|
if (lines.size() < 2)
|
|
{
|
|
TRACE("TsvParser::Parse - 数据至少需要列头和一行数据\n");
|
|
return false;
|
|
}
|
|
|
|
// 解析列头
|
|
if (!ParseLine(lines[0], outTableData.headers))
|
|
{
|
|
TRACE("TsvParser::Parse - 列头解析失败\n");
|
|
return false;
|
|
}
|
|
|
|
// 构建列名索引映射
|
|
BuildColumnIndexMap(outTableData.headers, outTableData.columnIndexMap);
|
|
|
|
// 解析数据行
|
|
for (size_t i = 1; i < lines.size(); i++)
|
|
{
|
|
std::vector<CString> fields;
|
|
if (ParseLine(lines[i], fields))
|
|
{
|
|
outTableData.rows.push_back(fields);
|
|
}
|
|
}
|
|
|
|
if (outTableData.rows.empty())
|
|
{
|
|
TRACE("TsvParser::Parse - 没有有效的数据行\n");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void TsvParser::SplitLines(const CString& data, std::vector<CString>& outLines)
|
|
{
|
|
outLines.clear();
|
|
CString line;
|
|
int pos = 0;
|
|
|
|
while (pos < data.GetLength())
|
|
{
|
|
int newlinePos = data.Find('\n', pos);
|
|
if (newlinePos == -1)
|
|
{
|
|
line = data.Mid(pos);
|
|
line.Trim();
|
|
if (!line.IsEmpty())
|
|
outLines.push_back(line);
|
|
break;
|
|
}
|
|
|
|
line = data.Mid(pos, newlinePos - pos);
|
|
line.Trim();
|
|
if (!line.IsEmpty())
|
|
outLines.push_back(line);
|
|
pos = newlinePos + 1;
|
|
}
|
|
}
|
|
|
|
bool TsvParser::ParseLine(const CString& line, std::vector<CString>& outFields)
|
|
{
|
|
outFields.clear();
|
|
if (line.IsEmpty())
|
|
return false;
|
|
|
|
CString field;
|
|
for (int i = 0; i < line.GetLength(); i++)
|
|
{
|
|
if (line[i] == '\t')
|
|
{
|
|
outFields.push_back(field);
|
|
field.Empty();
|
|
}
|
|
else
|
|
{
|
|
field += line[i];
|
|
}
|
|
}
|
|
outFields.push_back(field); // 添加最后一个字段
|
|
|
|
return !outFields.empty();
|
|
}
|
|
|
|
void TsvParser::BuildColumnIndexMap(const std::vector<CString>& headers,
|
|
std::map<CString, int>& outIndexMap)
|
|
{
|
|
outIndexMap.clear();
|
|
for (size_t i = 0; i < headers.size(); i++)
|
|
{
|
|
CString key = headers[i];
|
|
key.MakeUpper();
|
|
key.Trim();
|
|
outIndexMap[key] = (int)i;
|
|
}
|
|
}
|