Comment implémenter un remplacement efficace de chaîne de mot entier en C ++ sans expressions régulières?

J’ai peut-être oublié quelque chose d’évident, mais je me demandais quel serait le moyen le plus rapide d’implémenter le remplacement de chaîne de mot entier en C ++. Au début, j’ai envisagé de concaténer simplement des espaces avec le mot recherché, mais cela ne prend pas en compte les limites des chaînes ni la ponctuation.

Ceci est mon abstraction actuelle pour le remplacement (mot non complet):

void Replace(wssortingng& input, wssortingng find, wssortingng replace_with) { if (find.empty() || find == replace_with || input.length() < find.length()) { return; } for (size_t pos = input.find(find); pos != wstring::npos; pos = input.find(find, pos)) { input.replace(pos, find.length(), replace_with); pos += replace_with.length(); } } 

Si je ne considère que les espaces comme une limite de mot, je pourrais probablement le mettre en œuvre en comparant le début et la fin de la chaîne de recherche à la chaîne de recherche pour couvrir les limites de la chaîne, puis en effectuant un remplacement (L ” + recherche + L ‘). ‘) …. mais je me demandais s’il existait une solution plus élégante qui inclurait efficacement la ponctuation.

Considérons un mot comme une collection de caractères séparés par des espaces ou des signes de ponctuation (pour simplifier, disons! “# $% & ‘() * +, -. / Au minimum – ce qui correspond à (c > 31 && c < 48) ).

Dans mon application, je dois appeler cette fonction sur un assez grand nombre de chaînes courtes pouvant inclure divers caractères Unicode pour lesquels je ne souhaite pas scinder de nouveaux mots. J’aimerais également éviter d’inclure des bibliothèques externes, mais STL convient.

Le fait de ne pas utiliser d’expressions régulières permet de réduire les frais généraux et de créer une fonction rapide adaptée à cette tâche particulière sur un dataset volumineux.

Je pense que vous pouvez le faire, à la fois en faisant correspondre le mot entier et en le faisant efficacement. La clé est de:

  • détectez les limites du “mot entier” en utilisant ‘std :: isalpha’, ce qui devrait fonctionner avec Unicode et toutes les locales.
  • remplacez “hors de place” en créant une chaîne “sortie” distincte que vous permuterez avec “entrée” à la fin du traitement, au lieu d’effectuer le travail “en place” sur la chaîne “d’entrée” elle-même.

Voici mon avis sur votre fonction:

 #include  // isalpha #include  // or, not #include  // wssortingng using std::size_t; using std::wssortingng; /// @brief Do a "find and replace" on a ssortingng. /// @note This function does "whole-word" matching. /// @param[in,out] input_ssortingng The ssortingng to operate on. /// @param[in] find_ssortingng The ssortingng to find in the input. /// @param[in] replace_ssortingng The ssortingng to replace 'find_ssortingng' /// with in the input. void find_and_replace( wssortingng& input_ssortingng, const wssortingng& find_ssortingng, const wssortingng& replace_ssortingng ) { if( find_ssortingng.empty() or find_ssortingng == replace_ssortingng or input_ssortingng.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 ); } 

PS Je ne savais pas ce que 'replace_all' essayait d'accomplir dans votre exemple initial. Je l'ai donc supprimé de ma solution pour plus de clarté.

PPS Ce code serait beaucoup plus propre avec Regex-es. Pouvez-vous compter sur les fonctionnalités C ++ TR1 ou C ++ 2011? Ils fournissent une bibliothèque standard 'regex'.

C’est ma réponse rapide, mais je ne sais pas à quel point la solution est rapide… Il existe peu de solutions à ce problème:
1. En utilisant des iterators, comparez chaque mot (délimité par un espace), en recréant une chaîne pour chaque occurrence:

 ssortingng& remove_all_occurences(ssortingng& s, const ssortingng& str_to_remove, const ssortingng& str_to_put){ typedef ssortingng::size_type ssortingng_size; ssortingng_size i = 0; ssortingng cur_ssortingng; cur_ssortingng.reserve(s.size()); // invariant: we have processed characters [original value of i, i) while (i != s.size()) { // ignore leading blanks // invariant: characters in range [original i, current i) are all spaces while (i != s.size() && isspace(s[i])) ++i; // find end of next word ssortingng_size j = i; // invariant: none of the characters in range [original j, current j)is a space while (j != s.size() && !isspace(s[j])) j++; // if we found some nonwhitespace characters if (i != j) { // copy from s starting at the beginning to i, placing str to replace, and finishing with j to the end of s cur_ssortingng = s.substr(i,ji); if(cur_ssortingng == str_to_remove){ s = s.substr(0,i) + str_to_put + s.substr(j,s.size() - j); } i = j; } } return s; } 

Tester le programme:

 void call_remove_all_occurences(){ ssortingng my_str = "The quick brown fox jumps over sleepy dog fox fox fox"; cout << remove_all_occurences(my_str,"fox","godzilla") << endl; } 

Sortie:

 The quick brown godzilla jumps over sleepy dog godzilla godzilla godzilla 
  1. En scindant chaîne en vecteur puis en parcourant vecteur et en remplaçant chaque occurrence - simple ... vous n'avez pas le code, mais vous avez l'idée ...