项目中需要按行读取文本文件,并对每一行内容进行解析。每一行都是固定的字段数,字段之间用空格隔开。
#include <stdint.h>
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include<stdio.h>
/*****************************************************************************
函 数 名 : strtrim
功能描述 : 删除行首、行尾空白符号
输入参数 : char *is
输出参数 : 无
返 回 值 : char *
*****************************************************************************/
char * strtrim(char *s) {
char *p = s;
char *q = s;
//去掉行首的空格
while (*p==' ' || *p=='\t')
++p;
//赋值
while ((p != NULL)&&(q != NULL)&&(*p != '\0')&&(*p != '\0'))
{
*q++ = *p++;
};
//删除'\0'字符 注意是 -2 上面q++是先操作再自加
q -= 2;
//去掉行末的空格
while (*q==' ' || *q=='\t')
--q;
//给字符串添加字符结束标志
*(q+1) ='\0';
//这里的return s要注意看好
//因为p q经过一系列操作后,已经不是原来的位置,越界了 ,s还在原来位置,所以return s才是正确的。
return s;
}
/*****************************************************************************
函 数 名 : strtrimc
功能描述 : 删除字符串中全部的空白符,包括行首和行尾
输入参数 : char * s
输出参数 : 无
返 回 值 : char *
*****************************************************************************/
char * strtrimc( char * s )
{
char * p1 = s;
char * p2 = s;
while(*p1 != '\0')
{
while(*p1 == ' ' || *p1 == '\t')
{
p1 ++;
}
* p2 ++ = *p1 ++;
}
*p2 = '\0';
return (s);
}
//将一行内容line中用空格分隔的字段提取出,存在fields vector集合中
void LinetoVector(const std::string& line, std::vector<std::string>& fields)
{
fields.clear();
std::istringstream ss(line);
std::string tmp;
while(ss >> tmp)
{
fields.push_back(tmp);
}
}
//加载并逐行分析文本。每一行解析出一个TableLineInfo结构
int LoadCanFile(FILE *fp, std::vector<TableLineInfo>& infoVec)
{
infoVec.clear();
if(fp == nullptr)
{
return -1;
}
char line[1024];
std::vector<std::string> fieldsInLineVec;
TableLineInfo itemDesc;
int ret = 0;
bool ignoreFirstLine = false;//是否已经忽略第一行
//下面开始逐行读取该描述文件
while(fgets(line, 1023, fp))
{
char *p = strtrim(line);
int len = strlen(p);
if(len <= 0)
{
continue;//读取下一行
}
fieldsInLineVec.clear();
LinetoVector(std::string(line), fieldsInLineVec);
//忽略"#"开头的注释行
if (fieldsInLineVec[0].find("#") == 0)
{
continue;
}
if (!ignoreFirstLine)//忽略第一行,第一行不参与解析
{
ignoreFirstLine = true;
continue;
}
//强制性要求每一个有效行必须解析出6个字段,否则报错.
//fieldsInLineVec中每一个元素均为十六进制字符串。比如“aa”、"fe"
if(fieldsInLineVec.size() != 6)
{
ret = -2;
break;
}
//取出目标位置
unsigned char dst = (unsigned char)std::stoi(fieldsInLineVec[1],nullptr,16);
itemDesc.dst = dst;
//取出源位置
// ......... ........其他字段
infoVec.push_back(itemDesc);
}//end while
//fclose(fp);//在这个函数内部不关闭描述符,不影响外部使用,注意在外部关闭
return ret;
}
//
当字段之间并非空格隔开时,可使用下面这个函数,用指定字符分割字符串:
/**
* @brief 用指定的字符分割字符串。
* @param str: 准备进行分割的字符串。
* @param delimit: 分割所用的字符(串)。
* @param result: 分割的结果。
* @return void.
* -<em> null </em> fail
* -<em> null </em> succeed
*/
void split(std::string str, std::string delimit, std::vector<std::string>& result)
{
size_t pos = str.find(delimit);
str += delimit;//将分隔符加入到最后一个位置,方便分割最后一位
while (pos != std::string::npos)
{
result.push_back(str.substr(0, pos));
str = str.substr(pos + 1);//substr的第一个参数为起始位置,第二个参数为复制长度,默认为string::npos到最后一个位置
pos = str.find(delimit);
}
}