स्ट्रिंग में एक चरित्र की सभी घटनाओं को कैसे बदला जाए?


480

एक चरित्र के सभी घटनाओं को दूसरे चरित्र के साथ बदलने का प्रभावी तरीका क्या है std::string?

जवाबों:


742

std::stringइस तरह के समारोह में शामिल नहीं है, लेकिन आप हेडर replaceसे स्टैंड-अलोन फ़ंक्शन का उपयोग कर सकते हैं algorithm

#include <algorithm>
#include <string>

void some_func() {
  std::string s = "example string";
  std::replace( s.begin(), s.end(), 'x', 'y'); // replace all 'x' to 'y'
}

6
std::stringहै एक कंटेनर विशेष रूप से वर्णों के क्रम के साथ संचालित करने के लिए बनाया गया है। लिंक
Kirill V. Lyadvinsky

164
दुर्भाग्य से, यह केवल एक चार्ट को दूसरे चार्ट द्वारा बदलने की अनुमति देता है। यह एक चार्ट को अधिक वर्णों से नहीं बदल सकता (जो कि एक स्ट्रिंग द्वारा है)। क्या अधिक चार्ट के साथ खोज-प्रतिस्थापन करने का कोई तरीका है?
सासक्यू

6
अगर मैं सिर्फ एक घटना को दूर करना चाहता हूं तो @Kirill V. Lyadvinsky क्या है।
SIFE

4
@ KirillV.Lyadvinsky: जब मैं y के साथ सभी x को बदलने के लिए इस विधि का उपयोग करता हूं, तो परिणाम एक लंबा y स्ट्रिंग है चाहे मूल स्ट्रिंग कोई भी हो। मैं उत्सुक हूं कि आपको क्या लगता है कि समस्या क्या होगी। (कोड ठीक वैसा ही है जैसा आपने लिखा है)
ट्रांसेंडेंट

6
@ ट्रान्सेंडेंट: यह ठीक std::string::replace()इसके बजाय के साथ क्या होता है std::replace()! 'x' ( char) को अनुमानित रूप से size_t[मूल्य 120] पर रखा गया है, इस प्रकार पूरे स्ट्रिंग या उसके भाग को 'y' की 120 प्रतियों से भरा जाएगा।
IBue

127

मुझे लगा कि मैं बूस्ट सॉल्यूशन में टॉस करूंगा :

#include <boost/algorithm/string/replace.hpp>

// in place
std::string in_place = "blah#blah";
boost::replace_all(in_place, "#", "@");

// copy
const std::string input = "blah#blah";
std::string output = boost::replace_all_copy(input, "#", "@");

तब आप -Iअपने कंपाइलर के लिए कुछ झंडे गायब कर रहे हैं ताकि वह आपके सिस्टम पर बूस्ट लाइब्रेरी को ढूंढ सके। शायद आपको इसे पहले स्थापित करने की भी आवश्यकता है।
मार्टिन उडिंग

उपरोक्त अधिक प्रभावी है क्योंकि यह std lib के साथ आता है। सभी को बढ़ावा देने के पुस्तकालय का उपयोग करने के लिए ;-)
hfrmobile

122

प्रश्न characterप्रतिस्थापन पर केंद्रित है , लेकिन, जैसा कि मैंने इस पृष्ठ को बहुत उपयोगी पाया (विशेष रूप से कोनराड की टिप्पणी), मैं इसे और अधिक सामान्यीकृत कार्यान्वयन साझा करना चाहता हूं, जो इससे निपटने की अनुमति देता है substrings:

std::string ReplaceAll(std::string str, const std::string& from, const std::string& to) {
    size_t start_pos = 0;
    while((start_pos = str.find(from, start_pos)) != std::string::npos) {
        str.replace(start_pos, from.length(), to);
        start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
    }
    return str;
}

उपयोग:

std::cout << ReplaceAll(string("Number Of Beans"), std::string(" "), std::string("_")) << std::endl;
std::cout << ReplaceAll(string("ghghjghugtghty"), std::string("gh"), std::string("X")) << std::endl;
std::cout << ReplaceAll(string("ghghjghugtghty"), std::string("gh"), std::string("h")) << std::endl;

आउटपुट:

Number_Of_Beans

XXjXugtXty

hhjhugthty


संपादित करें:

उपरोक्त कार्य को और अधिक उपयुक्त तरीके से लागू किया जा सकता है, यदि प्रदर्शन में आपकी चिंता है, तो कुछ भी नहीं लौटाकर ( void) strतर्क के रूप में दिए गए स्ट्रिंग पर सीधे परिवर्तन करके, मान के बजाय पते से पारित कर दिया जाता है । यह परिणाम देते समय मूल स्ट्रिंग की बेकार और महंगी प्रतिलिपि से बचता है। आपकी कॉल, तब ...

कोड:

static inline void ReplaceAll2(std::string &str, const std::string& from, const std::string& to)
{
    // Same inner code...
    // No return statement
}

आशा है कि यह कुछ अन्य लोगों के लिए उपयोगी होगा ...


4
यह उन मामलों में एक प्रदर्शन मुद्दा है जहां स्रोत स्ट्रिंग बड़ी है और स्ट्रिंग को प्रतिस्थापित करने की कई घटनाएं हैं। string :: प्रतिस्थापित () कई बार कहा जाता है जो बहुत सारी स्ट्रिंग प्रतियां बनाता है। मेरा समाधान देखें जो उस समस्या को संबोधित करता है।
मिनास्त्रोस

1
नाइट पिकिंग आगे: पते से => संदर्भ द्वारा । यह एक पता है या नहीं यह एक कार्यान्वयन विवरण है।
मैक्स Truxa

1
आपको वास्तव में जांचना चाहिए कि क्या fromस्ट्रिंग खाली है, अन्यथा एक अंतहीन लूप होगा।
नौसिखिया

34

एक बड़े बाइनरी ब्लॉब की कल्पना करें जहां सभी 0x00 बाइट्स को "\ 1 \ x30" से और सभी 0x01 बाइट्स को "\ 1 \ x31" द्वारा बदल दिया जाएगा क्योंकि ट्रांसपोर्ट प्रोटोकॉल नो \ 0-बाइट्स की अनुमति देता है।

ऐसे मामलों में:

  • की जगह और करने के लिए प्रतिस्थापित स्ट्रिंग अलग लंबाई है,
  • स्रोत स्ट्रिंग के भीतर प्रतिस्थापित स्ट्रिंग के कई आवृत्तियों हैं और
  • स्रोत स्ट्रिंग बड़ी है,

प्रदान किए गए समाधानों को लागू नहीं किया जा सकता है (क्योंकि वे केवल एकल वर्णों को प्रतिस्थापित करते हैं) या एक प्रदर्शन समस्या है, क्योंकि वे स्ट्रिंग को कॉल करेंगे :: कई बार बदलें जो बूँद के आकार की प्रतियों को उत्पन्न करता है। (मैं बढ़ावा समाधान नहीं जानता, शायद यह उस दृष्टिकोण से ठीक है)

यह स्रोत स्ट्रिंग में सभी घटनाओं के साथ चलता है और एक बार टुकड़ा द्वारा नया स्ट्रिंग टुकड़ा बनाता है :

void replaceAll(std::string& source, const std::string& from, const std::string& to)
{
    std::string newString;
    newString.reserve(source.length());  // avoids a few memory allocations

    std::string::size_type lastPos = 0;
    std::string::size_type findPos;

    while(std::string::npos != (findPos = source.find(from, lastPos)))
    {
        newString.append(source, lastPos, findPos - lastPos);
        newString += to;
        lastPos = findPos + from.length();
    }

    // Care for the rest after last occurrence
    newString += source.substr(lastPos);

    source.swap(newString);
}

यह अब तक का सबसे अच्छा समाधान है जो अकेले एसटीएल पर बनाया गया है। यदि आप कहीं भी आसान उपयोग के लिए एक कस्टम फ़ंक्शन में छोड़ने जा रहे हैं, तो इसे एक बनाएं।
रोजर सैंडर्स

21

एक एकल चरित्र के लिए एक सरल खोज और प्रतिस्थापन कुछ इस तरह होगा:

s.replace(s.find("x"), 1, "y")

पूरे स्ट्रिंग के लिए ऐसा करने के लिए, जब तक आपकी s.findवापसी शुरू नहीं हो जाती, तब तक काम करना आसान होगा npos। मुझे लगता है कि आप range_errorपाश से बाहर निकलने के लिए भी पकड़ सकते हैं , लेकिन यह थोड़े बदसूरत है।


7
हालांकि यह संभवतः एक उपयुक्त समाधान है जब स्ट्रिंग की लंबाई की तुलना में वर्णों की संख्या छोटी है, यह अच्छी तरह से पैमाने पर नहीं है। मूल स्ट्रिंग में वर्णों के अनुपात को बढ़ने की आवश्यकता होती है, इसलिए यह विधि समय में O (N ^ 2) तक पहुंच जाएगी।
andand

7
सच। मेरा सामान्य दर्शन आसान (लिखना और पढ़ना) है, जब तक कि ऐसी अक्षमताएँ वास्तविक समस्याएँ पैदा नहीं करती हैं। कुछ परिस्थितियाँ ऐसी होती हैं जहाँ आपके पास विनम्र तार हो सकते हैं जहाँ O (N ** 2) मायने रखता है, लेकिन 99% मेरे तार 1K या उससे कम होते हैं।
TED

3
... यह कहा जा रहा है, मुझे किरिल का तरीका बेहतर लगा (और पहले ही इसने वोट दिया था)।
TED

यदि "x" नहीं मिला तो क्या होगा? इसके अलावा, आप डबल ब्रेसेस का उपयोग क्यों कर रहे हैं?
प्रसाद गोविंद

@PrasathGovind - मैं केवल आवश्यक कॉल दिखा रहा था (इसलिए "ऐसा कुछ")। महत्वपूर्ण लेकिन अस्पष्ट विवरण जैसे कि उचित त्रुटि से निपटने को पाठक के लिए एक अभ्यास के रूप में छोड़ दिया गया था। "डबल ब्रेसेस" के रूप में, मुझे यकीन नहीं है कि वे क्या हैं, या आप किस बारे में बात कर रहे हैं। मेरे लिए एक "ब्रेस" {चरित्र है। मुझे नहीं पता कि "डबल ब्रेस" क्या है। शायद आपके पास कुछ प्रकार का फ़ॉन्ट मुद्दा है?
TED

6

यदि आप एक से अधिक वर्णों को प्रतिस्थापित std::stringकरना चाह रहे हैं, और केवल उसी के साथ काम कर रहे हैं , तो यह स्निपेट काम करेगा, sNayle की जगह sHestack में sReplace के साथ, और sNeedle और sReplace को समान आकार की आवश्यकता नहीं है। यह दिनचर्या सभी घटनाओं को प्रतिस्थापित करने के लिए लूप का उपयोग करती है, बजाए बाएं से दाएं पहले पाए गए।

while(sHaystack.find(sNeedle) != std::string::npos) {
  sHaystack.replace(sHaystack.find(sNeedle),sNeedle.size(),sReplace);
}

यह O (n ^) है। आप इसे O (n) समय में कर सकते हैं।
चेंजिंग सन

3
@ChangmingSun जो O (n) समाधान का मतलब है?
हबकूक

2
यह अनंत लूप होगा यदि kNeedle sReplace का विकल्प होगा।
गौरव

इसके अलावा findदो बार एक कॉल है। उस परिणाम को एक अस्थायी चर बनाने पर विचार करें।
ल्यूक ब्लूम

4

जैसा कि किरिल ने सुझाव दिया था, या तो बदले की विधि का उपयोग करें या प्रत्येक स्ट्रिंग को स्वतंत्र रूप से प्रतिस्थापित करने वाले स्ट्रिंग के साथ पुनरावृति करें।

वैकल्पिक रूप से आप findविधि का उपयोग कर सकते हैं या find_first_ofआपको जो करने की आवश्यकता है उसके आधार पर। इनमें से कोई भी समाधान एक बार में काम नहीं करेगा, लेकिन कोड की कुछ अतिरिक्त पंक्तियों के साथ आपको उनके लिए काम करना चाहिए। :-)


3
#include <iostream>
#include <string>
using namespace std;
// Replace function..
string replace(string word, string target, string replacement){
    int len, loop=0;
    string nword="", let;
    len=word.length();
    len--;
    while(loop<=len){
        let=word.substr(loop, 1);
        if(let==target){
            nword=nword+replacement;
        }else{
            nword=nword+let;
        }
        loop++;
    }
    return nword;

}
//Main..
int main() {
  string word;
  cout<<"Enter Word: ";
  cin>>word;
  cout<<replace(word, "x", "y")<<endl;
  return 0;
}

यदि wordलंबा है, तो फ़ंक्शन को कॉल करते समय बहुत अधिक ओवरहेड हो सकता है। आप पारित करके इस अनुकूलन कर सकते हैं word, targetऔर replacementस्थिरांक-संदर्भ के रूप में।
ट्रेब्लेडज

2

Abseil StrReplaceAll के बारे में क्या ? हेडर फ़ाइल से:

// This file defines `absl::StrReplaceAll()`, a general-purpose string
// replacement function designed for large, arbitrary text substitutions,
// especially on strings which you are receiving from some other system for
// further processing (e.g. processing regular expressions, escaping HTML
// entities, etc.). `StrReplaceAll` is designed to be efficient even when only
// one substitution is being performed, or when substitution is rare.
//
// If the string being modified is known at compile-time, and the substitutions
// vary, `absl::Substitute()` may be a better choice.
//
// Example:
//
// std::string html_escaped = absl::StrReplaceAll(user_input, {
//                                                {"&", "&amp;"},
//                                                {"<", "&lt;"},
//                                                {">", "&gt;"},
//                                                {"\"", "&quot;"},
//                                                {"'", "&#39;"}});

1

पुराना स्कूल :-)

std::string str = "H:/recursos/audio/youtube/libre/falta/"; 

for (int i = 0; i < str.size(); i++) {
    if (str[i] == '/') {
        str[i] = '\\';
    }
}

std::cout << str;

परिणाम:

एच: \ RECURSOS \ ऑडियो \ यूट्यूब \ Libre \ Falta \


0

यह काम! मैंने बुकस्टोर ऐप के लिए कुछ इसी तरह का उपयोग किया, जहां इन्वेंट्री को एक सीएसवी (जैसे .dat फ़ाइल) में संग्रहीत किया गया था। लेकिन एकल चार के मामले में, इसका अर्थ यह है कि प्रतिकृति केवल एक ही चार्ट है, जैसे '|' ', यह दोगुना होना चाहिए ""। अमान्य रूपांतरण कॉन्स्ट चर को न फेंकने के लिए।

#include <iostream>
#include <string>

using namespace std;

int main()
{
    int count = 0;  // for the number of occurences.
    // final hold variable of corrected word up to the npos=j
    string holdWord = "";
    // a temp var in order to replace 0 to new npos
    string holdTemp = "";
    // a csv for a an entry in a book store
    string holdLetter = "Big Java 7th Ed,Horstman,978-1118431115,99.85";

    // j = npos
    for (int j = 0; j < holdLetter.length(); j++) {

        if (holdLetter[j] == ',') {

            if ( count == 0 ) 
            {           
                holdWord = holdLetter.replace(j, 1, " | ");      
            }
            else {

                string holdTemp1 = holdLetter.replace(j, 1, " | ");

                // since replacement is three positions in length,
                // must replace new replacement's 0 to npos-3, with
                // the 0 to npos - 3 of the old replacement 
                holdTemp = holdTemp1.replace(0, j-3, holdWord, 0, j-3); 

                holdWord = "";

                holdWord = holdTemp;

            }
            holdTemp = "";
            count++;
        }
    } 
    cout << holdWord << endl;
    return 0;
}

// result:
Big Java 7th Ed | Horstman | 978-1118431115 | 99.85

वर्तमान में मैं अभी CentOS का उपयोग कर रहा हूं, इसलिए मेरा संकलक संस्करण नीचे है। C ++ संस्करण (g ++), C ++ 98 डिफ़ॉल्ट:

g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-4)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

0

यदि आप std::stringएस का उपयोग करने के लिए तैयार हैं , तो आप इस नमूना-ऐप के strsubफ़ंक्शन का उपयोग कर सकते हैं , या इसे अपडेट कर सकते हैं यदि आप चाहते हैं कि यह एक ही लक्ष्य प्राप्त करने के लिए एक अलग प्रकार या मापदंडों का सेट ले। असल में, यह std::stringवर्णों के मिलान सेट को जल्दी से मिटाने के लिए गुणों और कार्यात्मकताओं का उपयोग करता है , और वांछित पात्रों को सीधे भीतर सम्मिलित करता है std::string। हर बार जब वह इस प्रतिस्थापन ऑपरेशन को करता है, तो ऑफ़सेट अपडेट यदि यह अभी भी बदलने के लिए मिलान चार्ट ढूंढ सकता है, और यदि यह बदलने के लिए अधिक कुछ नहीं कर सकता है, तो यह अंतिम अद्यतन से अपने राज्य में स्ट्रिंग लौटाता है।

#include <iostream>
#include <string>

std::string strsub(std::string stringToModify,
                   std::string charsToReplace,
                   std::string replacementChars);

int main()
{
    std::string silly_typos = "annoiiyyyng syyyllii tiipos.";

    std::cout << "Look at these " << silly_typos << std::endl;
    silly_typos = strsub(silly_typos, "yyy", "i");
    std::cout << "After a little elbow-grease, a few less " << silly_typos << std::endl;
    silly_typos = strsub(silly_typos, "ii", "y");

    std::cout << "There, no more " << silly_typos << std::endl;
    return 0;
}

std::string strsub(std::string stringToModify,
                   std::string charsToReplace,
                   std::string replacementChars)
{
    std::string this_string = stringToModify;

    std::size_t this_occurrence = this_string.find(charsToReplace);
    while (this_occurrence != std::string::npos)
    {
        this_string.erase(this_occurrence, charsToReplace.size());
        this_string.insert(this_occurrence, replacementChars);
        this_occurrence = this_string.find(charsToReplace,
                                           this_occurrence + replacementChars.size());
    }

    return this_string;
}

यदि आप std::stringअपने मापदंडों के रूप में s का उपयोग करने पर भरोसा नहीं करना चाहते हैं तो आप इसके बजाय C- शैली के तार में पास कर सकते हैं, आप नीचे दिए गए अद्यतन नमूने देख सकते हैं:

#include <iostream>
#include <string>

std::string strsub(const char * stringToModify,
                   const char * charsToReplace,
                   const char * replacementChars,
                   uint64_t sizeOfCharsToReplace,
                   uint64_t sizeOfReplacementChars);

int main()
{
    std::string silly_typos = "annoiiyyyng syyyllii tiipos.";

    std::cout << "Look at these " << silly_typos << std::endl;
    silly_typos = strsub(silly_typos.c_str(), "yyy", "i", 3, 1);
    std::cout << "After a little elbow-grease, a few less " << silly_typos << std::endl;
    silly_typos = strsub(silly_typos.c_str(), "ii", "y", 2, 1);

    std::cout << "There, no more " << silly_typos << std::endl;
    return 0;
}

std::string strsub(const char * stringToModify,
                   const char * charsToReplace,
                   const char * replacementChars,
                   uint64_t sizeOfCharsToReplace,
                   uint64_t sizeOfReplacementChars)
{
    std::string this_string = stringToModify;

    std::size_t this_occurrence = this_string.find(charsToReplace);
    while (this_occurrence != std::string::npos)
    {
        this_string.erase(this_occurrence, sizeOfCharsToReplace);
        this_string.insert(this_occurrence, replacementChars);
        this_occurrence = this_string.find(charsToReplace,
            this_occurrence + sizeOfReplacementChars);
    }

    return this_string;
}

0

सरल स्थितियों के लिए यह किसी भी अन्य पुस्तकालय का उपयोग किए बिना बहुत अच्छी तरह से काम करता है तो std :: string (जो पहले से उपयोग में है)।

चरित्र के सभी आवृत्तियों को कुछ वर्ण_ bring में वर्ण b से बदलें :

for (size_t i = 0; i < some_string.size(); ++i) {
    if (some_string[i] == 'a') {
        some_string.replace(i, 1, "b");
    }
}

यदि स्ट्रिंग बड़ी है या बदलने के लिए कई कॉल एक समस्या है, तो आप इस उत्तर में वर्णित तकनीक को लागू कर सकते हैं: https://stackoverflow.com/a/29752943/3622300


0

यहाँ एक समाधान मैं एक अधिकतम DRI भावना में लुढ़का हुआ है। यह sHaystack में sNeedle खोजेगा और इसे sReplace द्वारा प्रतिस्थापित करेगा, nTimes यदि गैर 0 हो, तो सभी sNeedle घटनाएँ। यह बदले हुए पाठ में फिर से खोज नहीं करेगा।

std::string str_replace(
    std::string sHaystack, std::string sNeedle, std::string sReplace, 
    size_t nTimes=0)
{
    size_t found = 0, pos = 0, c = 0;
    size_t len = sNeedle.size();
    size_t replen = sReplace.size();
    std::string input(sHaystack);

    do {
        found = input.find(sNeedle, pos);
        if (found == std::string::npos) {
            break;
        }
        input.replace(found, len, sReplace);
        pos = found + replen;
        ++c;
    } while(!nTimes || c < nTimes);

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