मैं मानक स्ट्रिंग में खोज / पता और प्रतिस्थापन कैसे करूँ?


94

वहाँ एक स्ट्रिंग में एक और स्ट्रिंग के साथ घटनेवाला के सभी घटनाओं को बदलने के लिए एक रास्ता है std::string?

उदाहरण के लिए:

void SomeFunction(std::string& str)
{
   str = str.replace("hello", "world"); //< I'm looking for something nice like this
}

जवाबों:


74

अपनी खुद की जगह लागू क्यों नहीं?

void myReplace(std::string& str,
               const std::string& oldStr,
               const std::string& newStr)
{
  std::string::size_type pos = 0u;
  while((pos = str.find(oldStr, pos)) != std::string::npos){
     str.replace(pos, oldStr.length(), newStr);
     pos += newStr.length();
  }
}

3
आप यहाँ "कॉल" को "कॉल" करने के लिए मेमोरी के साथ थोड़ा गड़बड़ कर रहे हैं: यदि आप "ooooooo ... o" से "o" हटाते हैं तो जटिलता n² होगी। मुझे लगता है कि कोई बेहतर कर सकता है, लेकिन इस समाधान को समझने में आसान होने का गुण है।
जोंको

1
यह लूप के लिए एक वास्तविक नहीं है, बल्कि लूप के लिए एक ओब्सेस्ड क्यों नहीं है?
शिरिक

मुझे 'कम से कम आश्चर्य' सिद्धांत को लागू करने के लिए उपयोग किया जाता है। छोरों के लिए सरल सूचकांक वृद्धि का उपयोग होता है, ज्यादातर समय। यहाँ, मेरे अनुसार, एक समय लूप स्पष्ट है।
ब्यूम्स

1
@aldo एक सामान्य नियम के रूप में, जटिलता से बचना बेहतर है और, उदाहरण के लिए, अन्य उत्तरों में बताए अनुसार रेगेक्स का उपयोग करें। लेकिन अपनी जरूरत के आधार पर आप अपनी परियोजना निर्भरता को नियंत्रित करना चाह सकते हैं। एक छोटा सा कोड स्निपेट जो वही करता है जिसकी आपको आवश्यकता है, अधिक नहीं, कभी-कभी बेहतर होता है।
ब्यूम्स

158
#include <boost/algorithm/string.hpp> // include Boost, a C++ library
...
std::string target("Would you like a foo of chocolate. Two foos of chocolate?");
boost::replace_all(target, "foo", "bar");

यहाँ रिप्लेसमेंट_ऑल पर आधिकारिक दस्तावेज है।


1
ध्यान दें कि आपको स्पष्ट रूप से एसटीडी बनाने की जरूरत नहीं है: पैटर्न और प्रतिस्थापन के लिए स्ट्रिंग: बढ़ावा :: रिप्लेसमेंट_ऑल (लक्ष्य, "फू", "बार");
एलेक्सिस विलके

4
+1, एक चेतावनी के साथ: replace_allबढ़ावा देने के संस्करणों के लिए सेगफॉल्ट होगा> 1.43 किसी भी संस्करण के लिए सूर्य स्टूडियो पर <12.3
ब्रायन वैंडेनबर्ग

3
boostसंकलित उपकरणों पर काफी समय बढ़ जाता है। यहां तक ​​कि ARMv7 क्वाड कोर। कोड की 100 लाइनें 2 मिनट में, बिना किसी सेकंड के, 2 सेकंड में संकलित होती हैं।
पिओटर कुला

4
@ppumkin: इसका मतलब है कि आपका कंपाइलर (या सेटअप सेटअप, या जो भी हो) बेकार है, न कि टार्गेट आर्किटेक्चर, जिसका इससे कोई लेना-देना नहीं है।
डैनियल कामिल कोजार

यदि आपका कंपाइलर पूर्व-संकलित हेडर का समर्थन करता है तो इसे बढ़ावा देने के दौरान इसका उपयोग करने की अत्यधिक अनुशंसा की जाती है। यह वास्तव में समय बचाता है।
एलेक्सी ओमेलेन्चो

33

C ++ 11 में, आप इसे एक लाइनर के रूप में कॉल के साथ कर सकते हैं regex_replace:

#include <string>
#include <regex>

using std::string;

string do_replace( string const & in, string const & from, string const & to )
{
  return std::regex_replace( in, std::regex(from), to );
}

string test = "Remove all spaces";
std::cout << do_replace(test, " ", "") << std::endl;

उत्पादन:

Removeallspaces

धन्यवाद, उपयोग करना और याद रखना बहुत आसान है!
जूलियन डेक्लेर्क

ध्यान दें कि fromएक नियमित अभिव्यक्ति हो सकती है - इसलिए यदि आपको आवश्यकता हो तो आप अधिक परिष्कृत मिलान मानदंडों का उपयोग कर सकते हैं। मैं जो नहीं देखता, वह यह है कि नियमित अभिव्यक्ति पार्सिंग के कुछ रूप को लागू किए बिना ऐसा कैसे किया जाए - इसके बजाय केवल fromपात्रों की प्रत्यक्ष व्याख्या का उपयोग करें ।
ब्रेंट बर्नबर्न

इसके लिए अप-टू-डेट कंपाइलर की आवश्यकता हो सकती है। यह gcc 5.0 के साथ काम करता है, लेकिन मुझे gcc 4.8.4 के साथ कुछ परेशानी थी।
ब्रेंट बर्नबर्न

@nobar, हाँ, अगर मुझे ठीक से याद है कि 4.8.x में regex सपोर्ट पूरा नहीं हुआ था। इसके अलावा, आपके पास अधिक परिष्कृत खोजें हो सकती हैं, लेकिन आपको दंडित समय वार मिलता है ... यह अन्य अधिक सीधे आगे की खोज की तुलना में धीमी गति से होने वाली है और कार्यों को प्रतिस्थापित करती है।
एलेक्सिस विल्के

2
कृपया ध्यान दें कि यह केवल बहुत ही मूल अल्फ़ान्यूमेरिक वर्णों के लिए काम करेगा और स्ट्रिंग के प्रकार के आधार पर बहुत अधिक प्रीप्रोसेसिंग किए बिना और कुछ नहीं। मैं एक सामान्य उद्देश्य regex आधारित स्ट्रिंग अभी तक नहीं मिला है।
पीयूष सोनी

17

संशोधित स्ट्रिंग क्यों नहीं लौटाते?

std::string ReplaceString(std::string subject, const std::string& search,
                          const std::string& replace) {
    size_t pos = 0;
    while((pos = subject.find(search, pos)) != std::string::npos) {
         subject.replace(pos, search.length(), replace);
         pos += replace.length();
    }
    return subject;
}

यदि आपको प्रदर्शन की आवश्यकता है, तो यहां एक अनुकूलित फ़ंक्शन है जो इनपुट स्ट्रिंग को संशोधित करता है, यह स्ट्रिंग की प्रतिलिपि नहीं बनाता है:

void ReplaceStringInPlace(std::string& subject, const std::string& search,
                          const std::string& replace) {
    size_t pos = 0;
    while((pos = subject.find(search, pos)) != std::string::npos) {
         subject.replace(pos, search.length(), replace);
         pos += replace.length();
    }
}

टेस्ट:

std::string input = "abc abc def";
std::cout << "Input string: " << input << std::endl;

std::cout << "ReplaceString() return value: " 
          << ReplaceString(input, "bc", "!!") << std::endl;
std::cout << "ReplaceString() input string not changed: " 
          << input << std::endl;

ReplaceStringInPlace(input, "bc", "??");
std::cout << "ReplaceStringInPlace() input string modified: " 
          << input << std::endl;

आउटपुट:

Input string: abc abc def
ReplaceString() return value: a!! a!! def
ReplaceString() input string not modified: abc abc def
ReplaceStringInPlace() input string modified: a?? a?? def

6

मेरे टेम्प-इन-इन-प्लेस खोज-इन-प्लेस:

template<class T>
int inline findAndReplace(T& source, const T& find, const T& replace)
{
    int num=0;
    typename T::size_t fLen = find.size();
    typename T::size_t rLen = replace.size();
    for (T::size_t pos=0; (pos=source.find(find, pos))!=T::npos; pos+=rLen)
    {
        num++;
        source.replace(pos, fLen, replace);
    }
    return num;
}

यह प्रतिस्थापित वस्तुओं की संख्या की गणना करता है (यदि आप इसे सफलतापूर्वक चलाना चाहते हैं, तो उपयोग के लिए आदि)। इसके प्रयेाग के लिए:

std::string str = "one two three";
int n = findAndReplace(str, "one", "1");

4
मैंने जीसीसी के तहत इस नमूने की कोशिश की, लेकिन यह संकलन नहीं करेगा - यह टी :: size_t का उपयोग पसंद नहीं आया। T :: size_t को टाइपनेम के साथ बदलकर T :: size_type समस्या को हल करता है।
एंड्रयू व्याट

3

सबसे आसान तरीका है (जो कुछ आपने लिखा है उसके पास की पेशकश) Boost.Regex , विशेष रूप से regex_replace का उपयोग करना है

std :: string को ढूँढने () और प्रतिस्थापित () विधियों में बनाया गया है, लेकिन वे काम करने के लिए अधिक बोझिल हैं क्योंकि उन्हें सूचकांक और स्ट्रिंग लंबाई से निपटने की आवश्यकता होती है।


3
बूस्ट स्ट्रिंग एल्गोरिदम भी हैं, जिसमें रिप्लेस_ल (ऐसे सरल प्रतिस्थापन के लिए रेगेक्स थोड़ा भारी हो सकता है) भी शामिल है।
अंकलबेन्स

3

मुझे विश्वास है कि यह काम करेगा। यह एक पैरामीटर के रूप में const char * लेता है।

//params find and replace cannot be NULL
void FindAndReplace( std::string& source, const char* find, const char* replace )
{
   //ASSERT(find != NULL);
   //ASSERT(replace != NULL);
   size_t findLen = strlen(find);
   size_t replaceLen = strlen(replace);
   size_t pos = 0;

   //search for the next occurrence of find within source
   while ((pos = source.find(find, pos)) != std::string::npos)
   {
      //replace the found string with the replacement
      source.replace( pos, findLen, replace );

      //the next line keeps you from searching your replace string, 
      //so your could replace "hello" with "hello world" 
      //and not have it blow chunks.
      pos += replaceLen; 
   }
}

यह देखते हुए कि size_typeएक स्ट्रिंग के लिए unsigned, >=लूप की स्थिति में आपका चेक हमेशा रहेगा true। आपको std::string::nposवहां उपयोग करना होगा।
पावेल मिनेव

size_type अहस्ताक्षरित नहीं है। यह कई प्लेटफार्मों पर अहस्ताक्षरित है, लेकिन सभी नहीं।
एलन

12
दुनिया में यह std :: string का हिस्सा क्यों नहीं है? क्या प्रोग्रामिंग की दुनिया में कोई अन्य गंभीर स्ट्रिंग वर्ग है जो ऑपरेशन को 'खोजने और बदलने' की पेशकश नहीं करता है? निश्चित रूप से यह दो पुनरावृत्तियों की तुलना में अधिक आम है और उनके बीच पाठ को बदलना चाहते हैं ?? कभी-कभी std :: string एक कार की तरह लगती है, जिसमें एक ट्यून करने योग्य स्पेक्ट्रम विंडशील्ड होती है, लेकिन ड्राइवर की खिड़की को लुढ़काने का कोई तरीका नहीं है।
स्पाइक एक्सएक्सएक्स

@ Spike0xff बूस्ट हैroll_down_window
ta.speot.is

1
@gustafr: मेरी गलती है। मैंने उन प्रणालियों पर काम किया है जहां पुराने कंपाइलरों ने size_t को अनुचित तरीके से परिभाषित किया है।
एलन

1
// Replace all occurrences of searchStr in str with replacer
// Each match is replaced only once to prevent an infinite loop
// The algorithm iterates once over the input and only concatenates 
// to the output, so it should be reasonably efficient
std::string replace(const std::string& str, const std::string& searchStr, 
    const std::string& replacer)
{
    // Prevent an infinite loop if the input is empty
    if (searchStr == "") {
        return str;
    }

    std::string result = "";
    size_t pos = 0;
    size_t pos2 = str.find(searchStr, pos);

    while (pos2 != std::string::npos) {
        result += str.substr(pos, pos2-pos) + replacer;
        pos = pos2 + searchStr.length();
        pos2 = str.find(searchStr, pos);
    }

    result += str.substr(pos, str.length()-pos);
    return result;
}

1
हमें केवल पिछले मैचों से नए मैचों की खोज करने की आवश्यकता है, यही कारण है कि एल्गोरिथ्म पॉज़ में अंतिम मैच को ध्यान से देखता है। पॉस 2 हमेशा अगले मैच को स्टोर करता है, इसलिए हम पीओएस और पॉज़ 2 के बीच के रिजल्ट को स्ट्रिंग करते हैं, फिर पॉज़ और पॉज़ 2 को एडवांस करते हैं। यदि कोई अन्य मैच नहीं मिल सकता है, तो हम परिणाम के लिए स्ट्रिंग के शेष भाग को संक्षिप्त करते हैं।
ब्योर्न गैंस्टर

1
#include <string>

using std::string;

void myReplace(string& str,
               const string& oldStr,
               const string& newStr) {
  if (oldStr.empty()) {
    return;
  }

  for (size_t pos = 0; (pos = str.find(oldStr, pos)) != string::npos;) {
    str.replace(pos, oldStr.length(), newStr);
    pos += newStr.length();
  }
}

OldStr खाली होने की जाँच महत्वपूर्ण है। यदि उस कारण से जो पैरामीटर खाली है, तो आप अनंत लूप में फंस जाएंगे।

लेकिन हाँ अगर आप कर सकते हैं की कोशिश की और परीक्षण C ++ 11 या बूस्ट समाधान का उपयोग करें।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.