2011-04-09 12 views
20

क्या std :: स्ट्रिंग में सभी स्लैश से बचने के लिए "\" "स्ट्रिंग में"/"की सभी घटनाओं को प्रतिस्थापित करने का एक अच्छा आसान तरीका है?std :: string का उपयोग कर दो वर्णों के साथ एक वर्ण की सभी घटनाओं को कैसे प्रतिस्थापित करें?

उत्तर

29

संभवतः यह करने का सबसे आसान तरीका boost string algorithms library के साथ है।

boost::replace_all(myString, "/", "\\/"); 

    std::string result = boost::replace_all_copy(myString, "/", "\\/"); 
2

ऐसा करने के तरीके पर एक उदाहरण cppreference.com std::string::replace page पर दिया जाता है:

std::string& replaceAll(std::string& context, std::string const& from, std::string const& to) 
{ 
    std::size_t lookHere = 0; 
    std::size_t foundHere; 
    while((foundHere = context.find(from, lookHere)) != std::string::npos) 
    { 
      context.replace(foundHere, from.size(), to); 
      lookHere = foundHere + to.size(); 
    } 
    return context; 
} 
+0

इस लिए जा रहा है 'ओ (एन * एम) 'जहां' n' स्ट्रिंग की लंबाई है और 'm' प्रतिस्थापन की संख्या है यदि' से' और '' 'अलग-अलग लंबाई हैं क्योंकि प्रत्येक प्रतिस्थापन के लिए इसे पूंछ को स्थानांतरित करना है डोर। – 6502

6

जवाब नहीं ... वहाँ कोई "आसान" तरीका है अगर आप एक एक लाइनर मतलब मानक पुस्तकालय द्वारा पहले ही प्रदान किया गया है। हालांकि उस समारोह को लागू करना मुश्किल नहीं है।

सबसे पहले मुझे लगता है कि शायद आपको \\\ और अन्य विशेष वर्णों के साथ प्रतिस्थापित करने की आवश्यकता होगी। इस मामले में ildjarn द्वारा दिए गए replaceAll कार्यान्वयन का उपयोग परेशान होने वाला है (आपको एक ही स्ट्रिंग को कई बार प्रतिस्थापित करने की आवश्यकता होगी)।

मेरी राय में स्ट्रिंग प्रसंस्करण के कई मामले हैं जहां स्पष्ट char * दृष्टिकोण का उपयोग करके कुछ भी धड़कता नहीं है। इस विशेष मामले तथापि शायद सिर्फ एक सूचकांक का उपयोग कर में ठीक है:

std::string escape(const std::string& s) 
{ 
    int n = s.size(), wp = 0; 
    std::vector<char> result(n*2); 
    for (int i=0; i<n; i++) 
    { 
     if (s[i] == '/' || s[i] == '\\') 
      result[wp++] = '\\'; 
     result[wp++] = s[i]; 
    } 
    return std::string(&result[0], &result[wp]); 
} 

मूल रूप से विचार ऊपर मैं सिर्फ संभाला / और \ स्ट्रिंग पर ले जाने और किसी भी विशेष वर्ण से पहले एक अतिरिक्त \ चरित्र जोड़ने के लिए (में है, लेकिन आप विचार समझ गये)। परिणाम लेंस में अधिकतम 2*n पर जाना जाता है, इसलिए मैं इसे पूरी प्रोसेसिंग ओ (एन) (replaceAll दृष्टिकोण बनाने के लिए पूर्ववत करता हूं, इसके बजाय शेष स्ट्रिंग को दाईं ओर ले जाता रहता है, जिससे इसे ओ (एन^2) बना दिया जाता है) । "this is a test with /slashes/ that should be /escaped/" जैसे छोटे तारों के लिए भी उपर्युक्त फ़ंक्शन मेरे पीसी पर अधिक कुशल (1.3x गति में) है, भले ही replaceAll पर कॉल करें और escape में दो विशेष वर्णों को संभालने के लिए।

ध्यान दें कि यह फ़ंक्शन स्वाभाविक रूप से स्ट्रिंग (आईएमओ एक बेहतर इंटरफ़ेस) को संशोधित करने के बजाय एक अलग स्ट्रिंग देता है और समय तुलना में मुझे प्रत्येक कॉल के लिए स्ट्रिंग बनाना पड़ता था ताकि परिणाम समानता की ओर भी स्थानांतरित हो जाएं क्योंकि उस निरंतर समय जोड़ा।

ऊपर पढ़ें/लिखें दृष्टिकोण भी आसानी से और अधिक जटिल प्रतिस्थापन (जैसे >&gt; या पात्रों के साथ नहीं प्रिंट करने योग्य सीमा में %xx एन्कोडिंग के साथ की जगह) के लिए अभी भी बड़ा तार (बस एक पास) के लिए एक अच्छा दक्षता बनाए रखने के लिए बढ़ाया जा सकता।

+0

यह विधि std :: प्रतिस्थापन से सबसे निश्चित रूप से तेज़ है; हालांकि, निष्पक्ष होने के लिए, मेरे पास खोजने और बदलने के लिए बहुत अधिक अलग-अलग वर्ण थे। मैं बूस्ट का उपयोग करने के लिए इसे भी पसंद करता हूं क्योंकि मुझे कुछ सरल स्ट्रिंग मैनिपुलेशन करने के लिए बस एक संपूर्ण लाइब्रेरी को लिंक करने की ज़रूरत नहीं है। – Roderick

0

मैं सवाल पर वाग्विस्तार, एक स्ट्रीमिंग का कार्यान्वयन करने के लिए आप पात्रों की एक किस्म से बचने के लिए अनुमति देता है बनाने के लिए।

स्ट्रीमिंग वास्तव में बड़ी मात्रा [1] के लिए बिस्कुट लेती है, क्योंकि आप ढेर विखंडन/प्रदर्शन नरक में अन्यथा प्राप्त करेंगे। इसके अलावा, इस बारे में आप किसी भी स्रोत में संग्रहीत तार से बचने के लिए के रूप में नमूने दिखाने

See it Live On Coliru

#include <iostream> 
#include <iterator> 
#include <set> 
#include <sstream> 
#include <string> 

template <class _II, class _OI> 
    static _OI escapeSomeChars(const _II inIt, const _II endIt, _OI outIt) 
{ 
    for (_II it=inIt; it!=endIt; ++it) 
     switch (*it) 
     { 
      case '\0': outIt++ = '\\'; outIt++ = '0'; break; 
      case '\n': outIt++ = '\\'; outIt++ = 'n'; break; 
      case '\\': 
      case '"' : 
      case '$' : 
      case '/' : outIt++ = '\\'; 
      default : outIt++ = *it; 
     } 

    return outIt; 
} 

static std::string escapeSomeChars(const std::string& input) 
{ 
    std::ostringstream os; 
    escapeSomeChars(input.begin(), input.end(), std::ostream_iterator<char>(os)); 
    return os.str(); 
} 

namespace /*anon*/ { 
    struct rawchar { // helper - see e.g. http://bytes.com/topic/c/answers/436124-copy-istream_iterator-question 
     char _c; rawchar(char c=0) : _c(c) {} 
     operator const char&() const { return _c; } 
     friend std::istream& operator>>(std::istream& is, rawchar& out) { return is.get(out._c); } 
    }; 
} 

int main() 
{ 
    static const char data[] = "\"I will \\$one day \\have \\all \\\\my slash\\es escaped, much \\like\\ in the source!\n\""; 

    // use the overload for std::string 
    std::cout << escapeSomeChars(data); 
    std::cout << std::endl; 

    // streaming in & out: 
    std::istringstream is(data); 
    escapeSomeChars(std::istream_iterator<rawchar>(is), std::istream_iterator<rawchar>(), std::ostream_iterator<char>(std::cout)); 
    std::cout << std::endl; 

    // but you don't need an istream, you can use any STL iterator range 
    escapeSomeChars(data, data+sizeof(data)/sizeof(data[0]), std::ostream_iterator<char>(std::cout)); 
    std::cout << std::endl; 

    // but any source and target will do: 
    std::string asstring(data); 
    std::set<char> chars(asstring.begin(), asstring.end()); 

    asstring.clear(); 
    escapeSomeChars(chars.begin(), chars.end(), std::back_inserter(asstring)); 

    std::cout << "Unique characters in data: '" << asstring << "', but properly escaped!" << std::endl; 
    return 0; 
} 

मैं एक स्विच चुना है, क्योंकि यह संकलक द्वारा अनुकूलित किया जाना होगा अनुमति देता है।बचने योग्य पात्रों के गतिशील सेट के लिए, मैं किसी प्रकार का लुकअप पसंद करूंगा (std :: find के साथ एक वेक्टर, हालांकि बड़े सेट के लिए सेट :: खोज के साथ std :: सेट बेहतर विकल्प बन जाएगा)।

उम्मीद है कि यह

[1] देखें उदाहरण के लिए इस खूबसूरत बग मैं हाल ही में सामना करना पड़ा: GParted: Simplified cleanup_cursor() implementation

1

एक दूसरे उप-स्ट्रिंग द्वारा एक स्ट्रिंग में एक उप-स्ट्रिंग के सभी आवृत्तियां प्रतिस्थापित करने के लिए:

#include <iostream> 

void replace_all(std::string& input, const std::string& from, const std::string& to) { 
    size_t pos = 0; 
    while ((pos = input.find(from, pos)) != std::string::npos) { 
    input.replace(pos, from.size(), to); 
    pos += to.size(); 
    } 
} 

int main() { 
    std::string str("i am a geek/nerd/crazy person."); 
    replace_all(str, "/", "\\/"); 
    std::cout << str << '\n'; 
} 

आउटपुट:

$ g++-6.1.0 -std=c++17 -g -Og -Werror -Wall -Wextra -pedantic -Wold-style-cast -Wnon-virtual-dtor -Wshadow -Wcast-align -Wunused -Woverloaded-virtual -Wconversion -Wsign-conversion -Wmisleading-indentation -fsanitize=address,leak,undefined; ./a.out 
i am a geek\/nerd\/crazy person.