【问题标题】:Counting the lines of code in a file in c++ with skipping lines with only comments or blank lines用c++计算文件中的代码行数,只用注释或空行跳过行
【发布时间】:2017-01-19 08:03:54
【问题描述】:

我目前正在开发一个加载文件然后将行数读回给用户的程序。我只需要一些关于何时让程序计算一行的帮助。目前我有:

getline(file, line);
if(line.empty() || line.find("//") || line.find("**") || line.find("/*") || line.find("*/"))
{ skip line }

唯一的问题是如果程序仍有代码但有注释(以下任何示例),则程序不会计算行数:

code...  //comment
code... /* comment
/* comment */ code... 

任何提示或帮助?

【问题讨论】:

  • std::cout << "//" << std::endl;int** ptr 怎么样
  • 你不能像那样计算行数(你可以,但它会是错误的)。多线/* */cmets呢?您需要一个词法分析器/标记器并记住您所处的状态(评论与否)。
  • 这是一个很好的初学者编程练习。构建一个简单的状态机来跟踪您浏览文本的状态。
  • 如果您不是为 lulz 执行此操作,gcc 可以使用 -fpreprocessed 为您删除 cmets,剩下的就是小菜一碟。
  • 使用已经为此实现解析器的工具(如CLOC)。解析 cmets 看起来可能不是一项非常具有挑战性的任务。然而,确实如此。考虑像@​​987654328@ 这样的代码,它(取决于评估的顺序)可能会被错误地解释为块注释的开始。您还需要排除字符串文字的解析,以及可能的 #include 指令。这确实比看起来更难。

标签: c++ count comments line skip


【解决方案1】:

完成您需要的算法可能如下:
(注:此代码未经测试)

std::vector<std::string> lines;
//collect all the lines in the vector

//iterate through the vector, removing all leading and trailing whitespace characters
for(auto& line : lines)
{
  std::string::size_type pos = line.find_last_not_of("\n\t ");
  if(pos != std::string::npos)
    line.erase(pos + 1)

  pos = line.find_first_not_of("\n\t ");
  if(pos != std::string::npos && pos != 0)
    line.erase(0, pos);
}

//remove all comment-only lines and blank lines
bool comment_block = false;
lines.erase(std::remove_if(lines.begin(), lines.end(), [&comment_block](const std::string& line){
  //if it's empty, remove it
  if(line.empty())
    return true;

  //if it starts with "//" it can't have code after it
  if(line.find("//") == 0)
    return true;

  //if it starts with "/*", it begins a comment block
  //(or if we're already in a comment block from earlier...)
  if(comment_block || line.find("/*") == 0)
  {
    auto pos = line.find("*/");
    if(pos == std::string::npos)
    {
      //if we can't find "*/" in this line, this is a comment block
      //so this line is all comments and it continues to the next line
      comment_block = true;
      return true;
    }
    //if we did find "*/" in this line, we are no longer in a comment block
    //(if we were already)
    comment_block = false;
    //Also, if "*/" is the last thing in this line, it's all comments
    return pos == line.length() - 2;
  }

  return false;
}), lines.end());

【讨论】:

  • 不,抱歉,没那么容易。您的算法会将cout &lt;&lt; "//"; 标记为注释行。没有其他答案那么糟糕,但仍然没有按照要求做。为了上帝的爱,不要试图自己动手。使用为此目的而设计的工具。这方式比你想象的要复杂。
  • @IInspectable 不,它不会将cout &lt;&lt; "//" 标记为注释行,因为在我的算法中// 必须位于行的开头(在删除空格之后)。与/* 相同
  • 这可能是真的。它仍然无法可靠地测试块注释的结尾。 cout &lt;&lt; "*/"; 将错误地终止块注释。如果块注释从行首以外的任何地方开始,它将无法可靠地找到块注释的开头。这当然是不可取的。
  • @IInspectable 这是真的。而且,我现在看到它还有另一个问题......好吧,正如我否认的那样,这段代码未经测试。不过,希望它能让 OP 更多地了解所需的一切。
  • 这仅涵盖最微不足道的情况。我不明白,这怎么可能“让 OP 更多地了解所需的所有。它甚至没有提到字符串文字,更不用说尝试解析它们了。对于琐碎的情况,它也不能可靠地工作(在块注释内,//*/ 也不会被识别为块注释的结尾)。你必须付出更多的努力,才能产生有用的东西,如果你发现你需要发布“未经测试”的代码,你可能会更好,建议一个工具。
猜你喜欢
  • 2017-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-01
  • 2018-02-22
  • 1970-01-01
相关资源
最近更新 更多