前言:
实际工程面临 进程A需要将发送类似结构体数组给进程B,即发送的数据流需要分为多组数据,每组可包含不同类型的数据,但每一组数据的类型必须一致。
因此开发数据流生成与数据流解析的demo。
结构体数组 数据流demo
代码分为2个文件:test.hpp、test.cpp
demo备注:
demo展示的数据流主要用于 进程到进程 / 核到核 / 端到端 之间的通信。
demo展示的数据流主要用于传输 类似 结构体数组(数据流的格式)的数据,一次可传输多组数据,每组数据可包含不同类型的数据。
数据流的格式为:
property1,property2,property3,property4;INT,ULONG,FLOAT,STRING;-1,1,1.100000,Aa1
string类型的数据不允许包含字符:“,”(组内数据分隔符)、“;”(组间数据分隔符),没有对其余字符做限制。
demo除了main函数、makeDataSteam1函数需要根据实际场景做修改,其他函数基本不需要修改。
demo:
test.hpp文件:
#pragma once
#include <vector>
#include <string>
enum PropertyDataTypeIndex {
E_DATA_TYPE_INT = 0,
E_DATA_TYPE_ULONG,
E_DATA_TYPE_FLOAT,
E_DATA_TYPE_STRING,
E_DATA_TYPE_NUM,
E_DATA_TYPE_NONE,
};
typedef struct {
int dataType;
int intItemData;
unsigned long ulongItemData;
float floatItemData;
std::string stringItemData;
} ItemProperty_t;
typedef struct {
int dataTypeIndex;
std::string dataType;
} DataType_t;
typedef struct {
std::string property;
int dataTypeIndex;
} PropertyType_t;
std::string GetDataType(unsigned int index);
unsigned int GetDataTypeIndex(std::string dataType);
std::string makePropertyDataSteam(const PropertyType_t *propertyTypeList,
int propertyTypeListSize,
const std::string &segmentSeparatorSymbol,
const std::string &teamSeparatorSymbol);
std::string makeTypeDataSteam(const PropertyType_t *propertyTypeList,
int propertyTypeListSize,
const std::string &segmentSeparatorSymbol,
const std::string &teamSeparatorSymbol);
int CalcGroupNum(const std::string &dataSteam,
const std::string &segmentSeparatorSymbol,
const std::string &teamSeparatorSymbol);
std::vector<int> GetPropertyType(const std::string &dataSteam,
const std::string &segmentSeparatorSymbol,
const std::string &teamSeparatorSymbol);
std::vector<std::vector<ItemProperty_t>> GetPropertyData(const std::string &dataSteam,
const std::vector<int> &propertyType,
const std::string &dataSteamHeader,
const std::string &segmentSeparatorSymbol,
const std::string &teamSeparatorSymbol);
std::string makeDataSteam1(const PropertyType_t *propertyTypeList,
int propertyTypeListSize,
const std::string &segmentSeparatorSymbol,
const std::string &teamSeparatorSymbol);
std::vector<std::vector<ItemProperty_t>> ParseData(const std::string &input,
const PropertyType_t *propertyTypeList,
int propertyTypeListSize,
const std::string &segmentSeparatorSymbol,
const std::string &teamSeparatorSymbol);
test.cpp文件:
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include "test_01.hpp"
const DataType_t g_dataTypeList[] = {
{E_DATA_TYPE_INT, "INT"},
{E_DATA_TYPE_ULONG, "ULONG"},
{E_DATA_TYPE_FLOAT, "FLOAT"},
{E_DATA_TYPE_STRING, "STRING"},
};
std::string GetDataType(unsigned int index)
{
std::string ret = "";
if (index >= E_DATA_TYPE_NUM) {
return ret;
}
for (int i = 0; i < (sizeof(g_dataTypeList) / sizeof(g_dataTypeList[0])); i++) {
if (g_dataTypeList[i].dataTypeIndex == index) {
ret = g_dataTypeList[i].dataType;
break;
}
}
return ret;
}
unsigned int GetDataTypeIndex(std::string dataType)
{
unsigned int ret = E_DATA_TYPE_NONE;
for (int i = 0; i < (sizeof(g_dataTypeList) / sizeof(g_dataTypeList[0])); i++) {
if (g_dataTypeList[i].dataType == dataType) {
ret = g_dataTypeList[i].dataTypeIndex;
break;
}
}
return ret;
}
std::string makePropertyDataSteam(const PropertyType_t *propertyTypeList,
int propertyTypeListSize,
const std::string &segmentSeparatorSymbol,
const std::string &teamSeparatorSymbol)
{
std::string dataSteam = "";
if ((propertyTypeList == nullptr) || (propertyTypeListSize == 0)) {
return dataSteam;
}
for (int i = 0; i < propertyTypeListSize; i++) {
dataSteam += propertyTypeList[i].property;
dataSteam += segmentSeparatorSymbol;
}
dataSteam.pop_back();
dataSteam += teamSeparatorSymbol;
return dataSteam;
}
std::string makeTypeDataSteam(const PropertyType_t *propertyTypeList,
int propertyTypeListSize,
const std::string &segmentSeparatorSymbol,
const std::string &teamSeparatorSymbol)
{
std::string dataSteam = "";
if ((propertyTypeList == nullptr) || (propertyTypeListSize == 0)) {
return dataSteam;
}
for (int i = 0; i < propertyTypeListSize; i++) {
dataSteam += GetDataType(propertyTypeList[i].dataTypeIndex);
dataSteam += segmentSeparatorSymbol;
}
dataSteam.pop_back();
dataSteam += teamSeparatorSymbol;
return dataSteam;
}
int CalcGroupNum(const std::string &dataSteam,
const std::string &segmentSeparatorSymbol,
const std::string &teamSeparatorSymbol)
{
int dataItemCnt = 0;
std::string token;
std::istringstream iss(dataSteam.substr());
while (std::getline(iss, token, *segmentSeparatorSymbol.c_str())) {
std::istringstream tokenStream(token);
std::string propertyName = "";
if (std::getline(tokenStream, propertyName, *segmentSeparatorSymbol.c_str())) {
if (propertyName == "") {
std::cout << "The property string format Abnormal." << std::endl;
break;
}
dataItemCnt++;
}
}
return dataItemCnt;
}
std::vector<int> GetPropertyType(const std::string &dataSteam,
const std::string &segmentSeparatorSymbol,
const std::string &teamSeparatorSymbol)
{
std::vector<int> propertyType;
std::string dataSteamType = dataSteam;
dataSteamType.pop_back();
std::string token;
std::istringstream iss(dataSteamType.substr());
while (std::getline(iss, token, *segmentSeparatorSymbol.c_str())) {
std::istringstream tokenStream(token);
std::string propertyName = "";
if (std::getline(tokenStream, propertyName, *segmentSeparatorSymbol.c_str())) {
if (propertyName == "") {
std::cout << "The property string format Abnormal." << std::endl;
break;
}
propertyType.push_back(GetDataTypeIndex(propertyName));
}
}
return propertyType;
}
std::vector<std::vector<ItemProperty_t>> GetPropertyData(const std::string &dataSteam,
const std::vector<int> &propertyType,
const std::string &dataSteamHeader,
const std::string &segmentSeparatorSymbol,
const std::string &teamSeparatorSymbol)
{
std::vector<std::vector<ItemProperty_t>> propertyData;
std::istringstream propertyIss(dataSteam.substr(dataSteamHeader.length()));
std::string propertyToken;
for (int i = 0; (std::getline(propertyIss, propertyToken, *teamSeparatorSymbol.c_str())); i++) { // 遍历每一组
std::istringstream groupIss(propertyToken);
std::string groupToken;
std::vector<ItemProperty_t> groupData;
for (int j = 0; (std::getline(groupIss, groupToken, *segmentSeparatorSymbol.c_str())); j++) { // 遍历每个属性
std::istringstream itemIss(groupToken);
std::string itemString;
ItemProperty_t itemProperty;
if (std::getline(itemIss, itemString, *segmentSeparatorSymbol.c_str())) {
if (itemString == "") {
std::cout << "The property string format Abnormal." << std::endl;
break;
}
switch (propertyType[j]) {
case E_DATA_TYPE_INT:
itemProperty.intItemData = std::stoi(itemString);
itemProperty.dataType = propertyType[j];
break;
case E_DATA_TYPE_ULONG:
itemProperty.ulongItemData = std::stoul(itemString);
itemProperty.dataType = propertyType[j];
break;
case E_DATA_TYPE_FLOAT:
itemProperty.floatItemData = std::stof(itemString);
itemProperty.dataType = propertyType[j];
break;
case E_DATA_TYPE_STRING:
itemProperty.stringItemData = (itemString);
itemProperty.dataType = propertyType[j];
break;
default:
itemProperty.dataType = E_DATA_TYPE_NONE;
break;
}
groupData.push_back(itemProperty);
}
}
propertyData.push_back(groupData);
}
return propertyData;
}
std::vector<std::vector<ItemProperty_t>> ParseData(const std::string &input,
const PropertyType_t *propertyTypeList,
int propertyTypeListSize,
const std::string &segmentSeparatorSymbol,
const std::string &teamSeparatorSymbol)
{
std::vector<std::vector<ItemProperty_t>> result;
std::vector<int> propertyType;
std::string dataSteamHeader = "";
std::string dataSteamProperty = makePropertyDataSteam(propertyTypeList, propertyTypeListSize, segmentSeparatorSymbol, teamSeparatorSymbol);
std::string dataSteamType = makeTypeDataSteam(propertyTypeList, propertyTypeListSize, segmentSeparatorSymbol, teamSeparatorSymbol);
dataSteamHeader += dataSteamProperty;
dataSteamHeader += dataSteamType;
// 1. calc group data num
int dataItemNum = CalcGroupNum(dataSteamProperty, segmentSeparatorSymbol, teamSeparatorSymbol);
if (dataItemNum == 0) {
return result;
}
// 2. check header data
if (input.substr(0, dataSteamHeader.length()) != dataSteamHeader) {
std::cout << "The input string format Abnormal." << std::endl;
return result;
}
// 3. get data type
propertyType = GetPropertyType(dataSteamType, segmentSeparatorSymbol, teamSeparatorSymbol);
if (propertyType.size() != dataItemNum) {
std::cout << "The property type num Abnormal." << propertyType.size() << dataItemNum << std::endl;
return result;
}
// 4. get data
result = GetPropertyData(input, propertyType, dataSteamHeader, segmentSeparatorSymbol, teamSeparatorSymbol);
return result;
}
std::string makeDataSteam1(const PropertyType_t *propertyTypeList,
int propertyTypeListSize,
const std::string &segmentSeparatorSymbol,
const std::string &teamSeparatorSymbol)
{
std::string dataSteam = "";
std::string dataSteamProperty = makePropertyDataSteam(propertyTypeList, propertyTypeListSize, segmentSeparatorSymbol, teamSeparatorSymbol);
std::string dataSteamType = makeTypeDataSteam(propertyTypeList, propertyTypeListSize, segmentSeparatorSymbol, teamSeparatorSymbol);
dataSteam += dataSteamProperty;
dataSteam += dataSteamType;
struct DataSteamStruct {
int property1;
unsigned int property2;
float property3;
std::string property4;
};
DataSteamStruct dataSteamList[] = {
{-1, 1, 1.1, "Aa1"},
{-2, 2, 2.2, "2000 / 2 / 2"},
{-3, 3, 3.3, "13 : 30"},
{-4, 4, 4.4, "4 - 4"},
{-5, 5, 5.5, "5 # 5"},
{-6, 6, 6.6, "6 % 6"},
{-7, 7, 7.7, "7 [] 7"},
{-8, 8, 8.8, "8 () 8"},
{-9, 9, 9.9, "9 <> 9"},
};
int dataSteamListSize = sizeof(dataSteamList) / sizeof(dataSteamList[0]);
for (int i = 0; i < dataSteamListSize; i++) {
dataSteam += std::to_string(dataSteamList[i].property1);
dataSteam += segmentSeparatorSymbol;
dataSteam += std::to_string(dataSteamList[i].property2);
dataSteam += segmentSeparatorSymbol;
dataSteam += std::to_string(dataSteamList[i].property3);
dataSteam += segmentSeparatorSymbol;
dataSteam += (dataSteamList[i].property4);
dataSteam += teamSeparatorSymbol;
}
dataSteam.pop_back();
return dataSteam;
}
int main(int argc, char *argv[])
{
// 数据流主要用于 进程到进程 / 核到核 / 端到端 之间的通信
// 数据流主要用于传输 类似 结构体数组(数据流的格式)的数据,一次可传输多组数据,每组数据可包含不同类型的数据
// 数据流的格式为:
// "^property1,property2,property3,property4;INT,ULONG,FLOAT,STRING;-1,1,1.100000,Aa1$"
// 注:
// string类型的数据不允许包含字符:“,”(组内数据分隔符)、“;”(组间数据分隔符),没有对其余字符做限制
const std::string segmentSeparatorSymbol = ",";
const std::string teamSeparatorSymbol = ";";
const PropertyType_t propertyTypeList[] = {
{"property1", E_DATA_TYPE_INT},
{"property2", E_DATA_TYPE_ULONG},
{"property3", E_DATA_TYPE_FLOAT},
{"property4", E_DATA_TYPE_STRING},
};
const int propertyTypeListSize = sizeof(propertyTypeList) / sizeof(propertyTypeList[0]);
std::string testInputDataSteam_1 = makeDataSteam1(propertyTypeList,
propertyTypeListSize,
segmentSeparatorSymbol,
teamSeparatorSymbol);
printf("DataSteam:\n");
printf("\"%s\"\n", testInputDataSteam_1.c_str());
std::vector<std::vector<ItemProperty_t>> parsedData_1 = ParseData(testInputDataSteam_1,
propertyTypeList,
propertyTypeListSize,
segmentSeparatorSymbol,
teamSeparatorSymbol);
printf("DataParse:\n");
for (int i = 0; i < parsedData_1.size(); i++) {
printf("[%d]\n", i);
for (int j = 0; j < parsedData_1[i].size(); j++) {
switch (parsedData_1[i][j].dataType) {
case E_DATA_TYPE_INT: printf("\t[%d]: %d\n", j, parsedData_1[i][j].intItemData); break;
case E_DATA_TYPE_ULONG: printf("\t[%d]: %u\n", j, parsedData_1[i][j].ulongItemData); break;
case E_DATA_TYPE_FLOAT: printf("\t[%d]: %.2f\n", j, parsedData_1[i][j].floatItemData); break;
case E_DATA_TYPE_STRING: printf("\t[%d]: \"%s\"\n", j, parsedData_1[i][j].stringItemData.c_str()); break;
default: printf("\t[%d]: None\n", j); break;
}
}
}
return 0;
}
运行结果如下:
DataSteam:
"property1,property2,property3,property4;INT,ULONG,FLOAT,STRING;-1,1,1.100000,Aa1;-2,2,2.200000,2000 / 2 / 2;-3,3,3.300000,13 : 30;-4,4,4.400000,4 - 4;-5,5,5.500000,5 # 5;-6,6,6.600000,6 % 6;-7,7,7.700000,7 [] 7;-8,8,8.800000,8 () 8;-9,9,9.900000,9 <> 9"
DataParse:
[0]
[0]: -1
[1]: 1
[2]: 1.10
[3]: "Aa1"
[1]
[0]: -2
[1]: 2
[2]: 2.20
[3]: "2000 / 2 / 2"
[2]
[0]: -3
[1]: 3
[2]: 3.30
[3]: "13 : 30"
[3]
[0]: -4
[1]: 4
[2]: 4.40
[3]: "4 - 4"
[4]
[0]: -5
[1]: 5
[2]: 5.50
[3]: "5 # 5"
[5]
[0]: -6
[1]: 6
[2]: 6.60
[3]: "6 % 6"
[6]
[0]: -7
[1]: 7
[2]: 7.70
[3]: "7 [] 7"
[7]
[0]: -8
[1]: 8
[2]: 8.80
[3]: "8 () 8"
[8]
[0]: -9
[1]: 9
[2]: 9.90
[3]: "9 <> 9"