【问题标题】:How I can remove every line that starts with "//" on an std::string?如何删除 std::string 上以“//”开头的每一行?
【发布时间】:2021-01-12 17:08:30
【问题描述】:

我有以下模板 std::string

std::string myString = R"svg(
  <svg height={size} width={size}>
    <rect {...rectProps} x={x0h} y={y0h} />
    // <rect {...rectProps} x={x1h} y={y0h} />
    <rect {...rectProps} x={x0h} y={y1h} />
    // <rect {...rectProps} x={x1h} y={y1h} />
  </svg>
)svg";

我想删除以//开头的每一行

所以我想要的结果会是这样的

<svg height={size} width={size}>
  <rect {...rectProps} x={x0h} y={y0h} />
  <rect {...rectProps} x={x0h} y={y1h} />
</svg>

编辑:所以我现在的想法是迭代每一行,修剪它,然后检测它是否以“//”开头

到目前为止,我有这个伪

std::istringstream stream(myString);
std::string line;
std::string myFinalString;
while (std::getline(stream, line)) {
  // TODO: trim line first
  bool isComment = false; // Find here if the line starts with //
  if (!isComment) {
    myFinalString += line + "\n";
  }
}

【问题讨论】:

  • 这里有一个简单的方法来弄清楚如何做到这一点,它永远不会失败。只需拿出一张白纸。用简单的英语用简短的句子写下来,这是一个循序渐进的过程。完成后,call your rubber duck for an appointment。我们不会在 Stackoverflow 上为其他人编写代码。我们总是向您的橡皮鸭提出此类问题。在您的橡皮鸭批准您提出的行动计划后,只需将您写下的内容直接翻译成 C++。任务完成!
  • 您可以使用boost::algorith::trim 删除空格并使用boost::algorith::starts_with 检查"//"
  • " 但没有按我的预期工作" 不是有用的评论。更好的是告诉你得到什么结果以及你期望什么。还包括可能的错误消息。
  • @ThomasSablik 对于 std::string 是这样的吗?
  • “每一行”是包含在文件中还是要直接从源代码中删除行?

标签: c++ stdstring


【解决方案1】:

没有像我预期的那样工作

除了你之外,它肯定不会像它那样工作。 你使用的erase 的重载看起来像

string& erase( size_type index = 0, size_type count = npos);

来自 cppreference 的重载说明:

从 index 开始删除 min(count, size() - index) 个字符。

所以svg.erase(0, svg.find("//") + 1) 真正做的是删除索引 [0] 到 [您找到的最后一个 '/' 的索引] 的所有字符

相反,您应该执行以下操作:

  1. 在您的字符串中搜索"//",将此位置命名为A。
  2. 在您的字符串中搜索'\n',将此位置命名为B。
  3. 擦除间隔 [A; B] 来自字符串或 [A; svg.length()] 如果你没有找到 B
  4. 重复直到没有更多位置 A

附:我建议从末尾而不是从头开始搜索,因为如果它更接近结尾而不是开头,则更容易删除一个片段形式的字符串

P.p.s.如果您想准确删除间隔,请务必使用迭代器,因为删除间隔的 erase 的唯一重载是

iterator erase( const_iterator first, const_iterator last );

【讨论】:

    【解决方案2】:

    您可以做的最简单的事情是使用正则表达式库:

    #include <iostream>
    #include <regex>
    
    int main()
    {
        std::string myString = R"svg(
        <svg height={size} width={size}>
            <rect {...rectProps} x={x0h} y={y0h} />
            // <rect {...rectProps} x={x1h} y={y0h} />
            <rect {...rectProps} x={x0h} y={y1h} />
            // <rect {...rectProps} x={x1h} y={y1h} />
        </svg>
        )svg";
        
        std::cout << myString << std::endl; //before
        std::string new_string = std::regex_replace(myString, std::regex("\n *//.*\n"), "\n");
        std::cout << new_string << std::endl; //after
    }
    

    我们捕获所有以新行 \n 开头的模式,有零个空格 *,两个斜杠 // 和零个或多个任何字符 .* 以另一个新行结尾。我们只用一个新行替换出现的事件(以补偿其中一个)。

    输出:

    <svg height={size} width={size}>
        <rect {...rectProps} x={x0h} y={y0h} />
        // <rect {...rectProps} x={x1h} y={y0h} />
        <rect {...rectProps} x={x0h} y={y1h} />
        // <rect {...rectProps} x={x1h} y={y1h} />
    </svg>
    
    
    <svg height={size} width={size}>
        <rect {...rectProps} x={x0h} y={y0h} />
        <rect {...rectProps} x={x0h} y={y1h} />
    </svg>
    

    【讨论】:

      【解决方案3】:

      为简单起见,根据std::basic_string::find_first_not_of 找到的'/' 的数量使用std::basic_string::erase 很难被击败,例如

          std::string s { "//Some comment" };
          
          if (s.at(0) == '/')
              s.erase (0, s.find_first_not_of ("/"));
      

      您还可以通过将" \t" 添加到拒绝字符来删除"//" 之前的任何前导空格:

          std::string s { "  //Some comment" };
          
          if (s.at(s.find_first_not_of (" \t/") - 1) == '/')
              s.erase (0, s.find_first_not_of (" \t/"));
      

      注意:- 1at() 来说是必需的,因为它需要从零开始的索引,而 erase() 需要删除字符数)

      然后要处理 "//" 周围的前导和尾随空格,您可以使用 #include &lt;cctype&gt; 并使用 isspace(c),如下所示:

          std::string s { "  //  Some comment" };
          char c = s.at(s.find_first_not_of (" \t/") - 1);
          
          if (c == '/' || isspace (c))
              s.erase (0, s.find_first_not_of (" \t/"));
      

      在所有情况下,"Some comment" 都是结果。

      【讨论】:

        【解决方案4】:

        最后这就是我找到的解决方案

        std::string trim(const std::string &str) {
          size_t first = str.find_first_not_of(' ');
          if (std::string::npos == first) {
            return str;
          }
          size_t last = str.find_last_not_of(' ');
          return str.substr(first, (last - first + 1));
        }
        
        bool startsWith(const std::string &input, const std::string &start) {
          return input.find(start) != std::string::npos;
        }
        
        std::string myString = R"svg(
          <svg height={size} width={size}>
            <rect {...rectProps} x={x0h} y={y0h} />
            // <rect {...rectProps} x={x1h} y={y0h} />
            <rect {...rectProps} x={x0h} y={y1h} />
            // <rect {...rectProps} x={x1h} y={y1h} />
          </svg>
        )svg";
        
        std::istringstream stream(myString);
        std::string line;
        std::string myFinalString;
        while (std::getline(stream, trim(line))) {
          if (!startsWith(line, "//")) {
            myFinalString += line + "\n";
          }
        }
        

        【讨论】:

        • 您的startsWith() 不太正确,当字符串中的“//”不在开头时会返回误报。它应该是input.find(start) == 0
        猜你喜欢
        • 1970-01-01
        • 2011-12-25
        • 1970-01-01
        • 2013-06-28
        • 1970-01-01
        • 2015-07-11
        • 2015-05-07
        • 2020-10-31
        • 1970-01-01
        相关资源
        最近更新 更多