How can I implement an efficient whole-word string replacement in C++ without regular expressions?

前端 未结 2 1846
耶瑟儿~
耶瑟儿~ 2020-12-19 11:44

Perhaps I\'m overlooking something obvious but I was wondering what the fastest way to implement whole-word string replacement in C++ might be. At first I considered simply

2条回答
  •  时光说笑
    2020-12-19 12:14

    I think you can do this, both doing whole-word matching and doing it efficiently. The key is to:

    • detect "whole-word" boundaries using 'std::isalpha', which should work with Unicode & any locale.
    • do the replace "out of place" by creating a separate 'output' string that you swap with 'input' at the end of processing, instead of doing the work "in place" on the 'input' string itself.

    Here's my take on your function:

    #include  // isalpha
    #include  // or, not
    #include  // wstring
    
    using std::size_t;
    using std::wstring;
    
    /// @brief Do a "find and replace" on a string.
    /// @note This function does "whole-word" matching.
    /// @param[in,out] input_string The string to operate on.
    /// @param[in] find_string The string to find in the input.
    /// @param[in] replace_string The string to replace 'find_string'
    ///            with in the input.
    void find_and_replace( wstring& input_string,
                           const wstring& find_string,
                           const wstring& replace_string )
    {
      if( find_string.empty()
          or find_string == replace_string
          or input_string.length() < find_string.length() )
      {
        return;
      }
    
      wstring output_string;
      output_string.reserve( input_string.length() );
      size_t last_pos = 0u;
      for( size_t new_pos = input_string.find( find_string );
           new_pos != wstring::npos;
           new_pos = input_string.find( find_string, new_pos ) )
      {
        bool did_replace = false;
        if( ( new_pos == 0u
              or not std::isalpha( input_string.at( new_pos - 1u ) ) )
            and ( new_pos + find_string.length() == input_string.length()
                  or not std::isalpha( input_string.at( new_pos + find_string.length() ) ) ) )
        {
          output_string.append( input_string, last_pos, new_pos - last_pos );
          output_string.append( replace_string );
          did_replace = true;
        }
        new_pos += find_string.length();
        if( did_replace )
        {
          last_pos = new_pos;
        }
      }
      output_string.append( input_string, last_pos,
                            input_string.length() - last_pos );
    
      input_string.swap( output_string );
    }
    

    P.S. I was unsure what 'replace_all' was trying to accomplish in your initial example, so I removed it from my solution for clarity.

    P.P.S. This code would be much cleaner with Regex-es. Can you rely on C++ TR1 or C++ 2011 functionality? They provide a standard 'regex' library.

提交回复
热议问题