1

我正在使用 fgets 从文件中读取以下行:

#C one two three four five six seven eight nine ten eleven

每个单词(#C 除外)都是一个列标题。所以我的文件中有十一列。

我的目标是将这条线分成每个单词的标记。另外,我需要计算一下有 11 个列标题。(列标题可以多于或少于 11 个)

我的问题是这一行末尾的空格。这是我正在使用的代码:

while(1){
fgets(buffer,1024,filename);
if (buffer[1] == 'C'){
    char* str = buffer+2;
    char* pch;
    pch = strtok(str," ");
    while(pch != NULL){
        pch = strtok (NULL, " ");
        if (pch == NULL)break; //without this, ncol contains +1 the 
                               //amount of columns.
            ncol++;
    }
    break;
}
}

这段代码给了我 ncol = 11。并且工作正常。(请注意,我正在阅读的行尾有一个空格)

但是,如果我在行尾没有空格,那么它会给出 ncol = 10 并且不会读取最后一列。

我的目标是让 ncol =11 不管结尾是否有空格。我只想读最后一个单词,检查是否还有单词,如果没有,则退出。

4

4 回答 4

0

如果你改变这个循环:

while(pch != NULL){
    pch = strtok (NULL, " ");
    if (pch == NULL)break; //without this, ncol contains +1 the 
                           //amount of columns.
        ncol++;
}

至:

while(pch != NULL){
    char *keep = pch;
    pch = strtok (NULL, " ");
    if (pch == NULL)
    {
       if (strlen(keep)) 
       {
           ncol++;
       }
       break; //without this, ncol contains +1 the 
    }
    //amount of columns.
    ncol++;
}

所以,如果字符串中还有一些东西,whenpch是 NULL,那么你还有另一个字符串,所以ncol在 if 中增加。[您可能会发现,如果输入文件不是“格式正确”,则if (strlen(keep))需要更彻底,但我假设您的输入是“不错”]

于 2013-05-02T14:48:07.450 回答
0

您可以检查是否设置了令牌:

if (pch == NULL || *pch == '\0') break;
于 2013-05-02T14:51:12.967 回答
0

另一种方案,更灵活,需要c++11支持

#include <iostream>
#include <string>
#include <vector>

template <typename Result, typename StringType>
void split(StringType const& contents, Result &result, StringType const& delimiters = "\n")
{
    typedef typename Result::value_type value_type;

    static_assert(std::is_same<value_type, StringType>::value, "std::is_same<value_type, StringType>::value == false,\n"
                  "The value_type of Result should be the same as StringType");

    typename StringType::size_type pos, last_pos = 0;
    while(true)
    {
        pos = contents.find_first_of(delimiters, last_pos);
        if(pos == StringType::npos)
        {
            pos = contents.length();

            if(pos != last_pos)
                result.emplace_back(contents.data() + last_pos, pos - last_pos);

            break;
        }
        else
        {
            if(pos != last_pos)
                result.emplace_back(contents.data() + last_pos, pos - last_pos );
        }

        last_pos = pos + 1;
    }
}

int main()
{             
    std::string const input = "#C one two three four five six seven eight nine ten eleven";
    std::vector<std::string> results;
    split(input, results, std::string(" "));
    for(auto const &data : results){
        std::cout<<data<<std::endl;
    }    

    return 0;
}
于 2013-05-02T14:59:35.157 回答
0

fgets由于该函数包含它从文件中读取的换行符,因此您在结尾处得到了不同的计数(有空格和没有空格) 。

因此,当行尾有空格时,换行符被视为单独的标记。

为了克服这个问题,您应该在提供给功能的标记中包含换行符 '\r' 和 '\n' strtok,并远程控制该 if (pch == NULL)break;行。

所以代码将是;

while(1){
    fgets(buffer,1024,filename);
    if (buffer[1] == 'C'){
        char* str = buffer+2;
        char* pch;
        pch = strtok(str," \r\n");
        while(pch != NULL){
            pch = strtok (NULL, " \r\n");
            //amount of columns.
            ncol++;
        }
        break;
    }
}
于 2013-05-02T15:30:31.427 回答