C++自学篇 以类似结构体数组的形式生成与解析数据流

前言:
实际工程面临 进程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"

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值