2013-05-02 68 views
1

最后一个字后,我读了下面的行使用与fgets文件:退出While循环立即在一条线上

#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; 
} 
} 

此代码给我的NcoI = 11,而正常工作(注意,是在该行我读的最后一个空格)

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

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

回答

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,那么你有另一个字符串,所以increement ncol中的if。 [您可能会发现,如果输入的文件是不是“简洁(wellformed)”的if (strlen(keep))需要更彻底的,但我假设你的输入是“好”]

0

你可以只检查标记设置:

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

NULL和\ 0有什么区别? @Philip – detraveller 2013-05-02 15:05:32

+1

@detraveller:'NULL'是一个指针值,''\ 0''是一个字符。实际上,你的编译器使得两者都为int,所以这只是为了澄清。 '* pch =='\ 0''是检查字符串长度为0的最快方法。 – Philip 2013-05-02 15:09:42

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; 
} 
0

你有和没有在最后空间越来越不同的计数,因为函数fgets包括它从文件中读取换行符。

因此,当行尾有空格时,换行符会被视为单独的令牌。

为了解决这个问题,您应该在提供给strtok功能的令牌中包含换行符'\ r'&'\ n',并且远程应用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; 
    } 
}