使用 C++ 从文本行中提取字段和值

Posted

技术标签:

【中文标题】使用 C++ 从文本行中提取字段和值【英文标题】:Extract fields and values from text line using C++ 【发布时间】:2017-06-07 13:56:16 【问题描述】:

我正在阅读具有以下格式行的文本文件:

date    =20170422,line    =10,index   =3,field   =partType,lock    =productCode1,bookmark=2/19/56,

我需要将字段的名称(日期、行、索引等)及其对应的值提取到char field[]char value[]变量中。如有必要,我可以修改行的格式。

我最初的想法是使用 while 循环并检查 =, 字符,但它变得一团糟,似乎可能有更清洁的方法。

【问题讨论】:

使用strchrgetline() 和字符串代替指向字符数组的指针 “干净”的方法是使用适当的解析器,如 Boost.Spirit。否则对于这样一个简单的格式,在“=”上拆分,然后在“,”上拆分片段,然后迭代就可以了。 换句话说:如何标记字符串?问和回答了无数次。由于缺乏研究而被否决。 【参考方案1】:

您可以执行以下示例。使用文件中的 getline 以逗号分割字符串,然后使用 istringstream 和 getline 以等号再次分割。

#include<iostream>
#include<fstream>
#include<string>
#include<sstream>
int main()

        std::ifstream file("test.txt");
        std::string wholeLine, partOfLine;
        while(std::getline(file, wholeLine, ',')) 
                std::istringstream wholeLineSS(wholeLine);
                while(std::getline(wholeLineSS, partOfLine, '=')) 
                        std::cout<<partOfLine<<std::endl;
                
        
        return 0;

【讨论】:

【参考方案2】:

我在此处发布的程序从一个或多个按您需要格式化的字符串中提取参数。函数extract 提取字符串(您指定的格式)中包含的所有参数,并将它们的名称和值插入到结构(struct sParms)数组中。

您可以将程序编译为提取并在系统提示符下执行它:

用户名:./extract "date =20170422,line =10,index =3,field =partType,lock =productCode1,bookmark=2/19/56,"

输出如下:

[date]=[20170422]
[line]=[10]
[index]=[3]
[field]=[partType]
[lock]=[productCode1]
[bookmark]=[2/19/56]

您可以使用多个字符串执行程序:

用户名:./extract "date =20170422,line =10,index =3,field =partType,lock =productCode1,bookmark=2/19/56," "yes=1, no=0"

输出如下:

[date]=[20170422]
[line]=[10]
[index]=[3]
[field]=[partType]
[lock]=[productCode1]
[bookmark]=[2/19/56]

[yes]=[1]
[no]=[0]

下面一行是代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>

//Parameters: date    =20170422,line    =10,index   =3,field   =partType,lock    =productCode1,bookmark=2/19/56,
#define SEPARATOR       ','
#define ASSIGNEMENT     '='

typedef struct sParms 
    char * fieldName;
    char * fieldValue;
 tsParms;

int loadString(char *to, const char *from);

int extract(tsParms **oparms, const char *inb);

// Retrieve buffer length
int loadString(char *to, const char *from)

    int len=0;

    while(*from<=32 && *from!=SEPARATOR && *from!=ASSIGNEMENT)
        from++;

    // Get the string value
    while(*from>32 && *from!=SEPARATOR && *from!=ASSIGNEMENT) 
        *(to+len++)=*from;
        ++from;
    

    *(to+len++)=0;

    return len;


int extract(tsParms ** oparms, const char *inb)

    int cnt=0,j;
    const char * end, *equ, *start;
    char * buff;
    tsParms * parms;

    if (inb == NULL || strlen(inb) == 0 || oparms == NULL)
        return 0;

    // It counts the number of parms
    end=strchr(inb,ASSIGNEMENT);
    while(end) 
        cnt++;
        end=strchr(end+1,ASSIGNEMENT);
    

    if (!cnt)
        return 0;

    /* Doing some considerations we may assume that the memory to use to store
     * fields name and values is the same of the input string (inb)
     *
     * The space to store the pointers is cnt * sizeof(tsParms *).
     */

    j=cnt * sizeof(tsParms) + strlen(inb);
    parms = malloc(j+1);
    memset(parms,0,j+1);

    buff = (char *)(parms+cnt); // The memory area where we can save data!

    start=inb;end=start;cnt=0;
    do 
        end=strchr(start,SEPARATOR);
        equ=strchr(start,ASSIGNEMENT);

        if (equ) 
            //Get the field name
            parms[cnt].fieldName=buff;
            buff+=loadString(buff,start);

            //Get the field value
            start=equ+1;
            parms[cnt].fieldValue=buff;
            buff+=loadString(buff,start);

            cnt++;
        

        if (end)
            start=end+1;
     while(end);

    *oparms = parms;

    return cnt;


int main(int argc, char *argv[])

    int i,j,cnt=0,retval=0;
    tsParms * parms=NULL;

    if (argc<2) 
        printf("Usage: %s \"string-1\" [\"string-2\" ...\"string-n\"]\n",basename(argv[0]));
        return 1;
    

    for(i=1; i<argc; i++) 
        cnt=extract(&parms, argv[i]);

        if (cnt!=0 && parms!=NULL) 
            for(j=0;j<cnt;j++) 
                printf("[%s]=[%s]\n",parms[j].fieldName,parms[j].fieldValue);
            
            puts("");

            free((void *)parms);
         else 
            retval=1;
            break;
        
    

    return retval;

【讨论】:

以上是关于使用 C++ 从文本行中提取字段和值的主要内容,如果未能解决你的问题,请参考以下文章

如何使用正则表达式从文本行中捕获 3 个不同的部分

在 C++ 中拆分点上的字符串并从中提取所有字段?

动态调整文本大小以使整个文本行适合文本字段

当它们包含在现有字段的值内时读取键和值

如何从具有由“|”分隔的字段的行中提取数据C++中的字符?

在 PySpark 中使用 regexp_extract 提取多个单词