修剪输入文件中的空间

时间:2018-09-15 21:09:34

标签: c++ c++11 file-io trim

我正在编写的代码遇到麻烦。程序通过将文件作为字符串读取到char结构变量中来从文件中读取,并将其传递给trimField函数以修剪程序。这是我们得到的输入文本文件:

BROWN DANIELLA                 810805748            562431322143323235411221 4213414131344422312122      
DEREK SAMATHA I                               002  10011313243433233344312212321342123  14212224242131121
SIMPSON BRETT                                       3844342323232233 33412342212342113221331132411112132 
TOMATO A LUKE                  811327785 15328003  4214341213331232354112432321532412124211142232213242 

我在文件中读取的此函数看起来像这样,其中数字来自结构变量(即char Name [21];):

void readData(std::ifstream inFileStream, Scantron &inputRecord)  {
std::string incomingData;
getline(inFileStream, incomingData);
if(!inputTestFile.eof)  {
    for(int i = 0; i < incomingData; i++)   {
        std::cin.get(inputRecord[i].Name, 21, ' ');
        std::cin.get(inputRecord[i].Id, 11, ' ');
        std::cin.get(inputRecord[i].CRN, 6, ' ');
        std::cin.get(inputRecord[i].testCode, 3, ' ');
        std::cin.get(inputRecord[i].specialCode, 4, ' ');
        std::cin.get(inputRecord[i].score, 4, ' ');
        std::cin.get(inputRecord[i].answerArray, 61, ' ');
        }
    }
}

我当前调用trimField函数的函数如下:

csvRecord transformDataToCSV(Scantron inputRecord){

   csvRecord outputRecord;
   trimField(inputRecord.Name, outputRecord.Name);
   trimField(inputRecord.Id, outputRecord.Id);
   trimField(inputRecord.score, outputRecord.score);
   for(int i = 0; i < 60; ++i)    {
       outputRecord.answerArray[i] = inputRecord.answerArray[i];
       trimField(inputRecord.answerArray, outputRecord.score);
     }

   return outputRecord;
}

并且trimField的标题必须如下所示:

// remove trailing spaces from fieldIn cstring and place in fieldOut cstring. If entire field is blank place one space followed by \0.
void trimField(char fieldIn[], char &fieldOut[] )   {

}

我不确定在修剪文件时该如何开始,并且有太多不同的在线处理方法,这使我很难理解如何执行此操作。

1 个答案:

答案 0 :(得分:0)

我很困惑为什么您仍然使用cstring。更令人困惑的是,您尝试为输出传递一个引用数组。这不会编译:

error: declaration of ‘fieldOut’ as array of references
void  trimField2(char fieldIn[], char &fieldOut[])   {
                                                ^  

第一个非常基本的版本

尽管如此,这是一个简单的解决方案:先计算空格数,最后计算空格数,然后仅复制剩下的内容:

void trimField(char fieldIn[], char fieldOut[] )   {
    int i=0; 
    // skip left spaces with i 
    while (fieldIn[i] && isspace(fieldIn[i]) )
        i++;
    // skip right spaces starting from end with j (relative to i)
    int j=strlen(fieldIn+i);
    while (j && isspace (fieldIn[j+i-1]) )
        j--;
    strncpy(fieldOut, fieldIn+i, j); 
    fieldOut[j]='\0'; 
}

请注意,此函数是不安全的,因为它没有将输出的最大长度作为参数考虑在内,因此存在缓冲区溢出的风险。另外,由于输入未定义为const,因此容易出错。

构建字符串的更安全版本

我建议您使用一个变体,该变体返回一个真实的C ++字符串并以一个const缓冲区作为输入:

std::string trimField(const char fieldIn[])   {
    const char *p, *q,*r;  
    for (p=fieldIn; *p && isspace(*p); p++ )    // skip left spaces
        ;
    for (q=r=p; *q; q++) // sorry for the tripple assignment ;-)
        if (!isspace (*q))  
            r=q;  // keep trace of last non white
    return std::string (p, r+1);  
}   

为方便起见,我切换到指针。为避免在第一个非空格字符之后读取两次字符,我们同时搜索输入字符串(q)的末尾并跟踪非白色字符(r)。最后,我们基于起点和终点的指针/迭代器构造一个字符串。