在一行中的最后一个单词之后立即退出While循环

时间:2013-05-02 14:42:24

标签: c++ strtok

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

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

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

我的目标是将这一行划分为每个单词的标记。另外,我需要指出有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 个答案:

答案 0 :(得分: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++;
}

因此,如果字符串中还剩下某些内容,当pch为NULL时,则您有另一个字符串,因此if中包含ncol。 [你可能会发现,如果输入文件没有“格式良好”,if (strlen(keep))需要更加彻底,但我假设你的输入是“很好”]

答案 1 :(得分:0)

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

if (pch == NULL || *pch == '\0') break;

答案 2 :(得分: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;
}

答案 3 :(得分:0)

您最终会获得带有和不带空格的不同计数,因为函数fgets包含从文件中读取的换行符。

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

要解决此问题,您应该添加换行符'\ r'&amp; '\ 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;
    }
}