【问题标题】:std::regex_replace bug when string contains \0当字符串包含 \0 时出现 std::regex_replace 错误
【发布时间】:2022-01-15 20:54:38
【问题描述】:

我可能在std::regex_replace 中发现了一个错误。

下面的代码应该写成长度为 5 的 "1a b2",但写成长度为 3 的 "1a2"

我说的对吗?如果没有,为什么不呢?

#include <iostream>
#include <regex>

using namespace std;
int main()
{
    string a = regex_replace("1<sn>2", std::regex("<sn>"), string("a\0b", 3));

    cout << "a: " << a << "\n";
    cout << a.length();

    return 0;
}

【问题讨论】:

  • 恕我直言,这是 C++ 正则表达式库中的一个错误,它使用了 C 正则表达式库。
  • 没关系,因为你写的“a\0b”是一个char*,而我只打印一个字符串!
  • 这是一个错误,我在哪里可以报告?
  • @Chris "a\0b" 与打印无关。 std::string("a\0b", 3) 有效,长度为 3。
  • 错了,因为我设置了长度!无论如何,正则表达式得到的字符串不是 char*!

标签: c++ string std


【解决方案1】:

这似乎是 libstdc++ 中的一个错误。我使用调试器进入regex_replace,直到进入这一部分:

 // std [28.11.4] Function template regex_replace
  /**
   * @brief Search for a regular expression within a range for multiple times,
   and replace the matched parts through filling a format string.
   * @param __out   [OUT] The output iterator.
   * @param __first [IN]  The start of the string to search.
   * @param __last  [IN]  One-past-the-end of the string to search.
   * @param __e     [IN]  The regular expression to search for.
   * @param __fmt   [IN]  The format string.
   * @param __flags [IN]  Search and replace policy flags.
   *
   * @returns __out
   * @throws an exception of type regex_error.
   */
  template<typename _Out_iter, typename _Bi_iter,
       typename _Rx_traits, typename _Ch_type,
       typename _St, typename _Sa>
    inline _Out_iter
    regex_replace(_Out_iter __out, _Bi_iter __first, _Bi_iter __last,
          const basic_regex<_Ch_type, _Rx_traits>& __e,
          const basic_string<_Ch_type, _St, _Sa>& __fmt,
          regex_constants::match_flag_type __flags
          = regex_constants::match_default)
    {
      return regex_replace(__out, __first, __last, __e, __fmt.c_str(), __flags);
    }

引用this write-up at cppreference.com,这似乎是在实现第一个重载,即采用std::string 替换字符串的重载,方法是调用其c_str(),然后调用第二个重载,即采用@987654326 的重载@参数,用于实际实现。这就解释了观察到的行为。我找不到任何需要这种方法的东西。

进一步深入实际实现:

          auto __len = char_traits<_Ch_type>::length(__fmt);

              __out = __i->format(__out, __fmt, __fmt + __len, __flags);

因此,它确定替换字符串的长度并将替换字符串作为开始和结束迭代器传递给format()

这似乎应该反过来,将__fmt 保留为std::basic_string,并将直接派生自它的迭代器传递给format()

【讨论】:

    猜你喜欢
    • 2012-07-26
    • 1970-01-01
    • 1970-01-01
    • 2021-11-21
    • 2017-03-13
    • 2019-10-17
    • 2012-06-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多