मैं एक स्ट्रिंग के शब्दों पर कैसे पुनरावृति करूं?


2985

मैं एक स्ट्रिंग के शब्दों पर पुनरावृति करने की कोशिश कर रहा हूं।

स्ट्रिंग को व्हॉट्सएप द्वारा अलग किए गए शब्दों से बना माना जा सकता है।

ध्यान दें कि मुझे C स्ट्रिंग फ़ंक्शंस में दिलचस्पी नहीं है या उस तरह के चरित्र हेरफेर / पहुंच है। इसके अलावा, कृपया अपने उत्तर में दक्षता पर लालित्य को वरीयता दें।

मेरे पास अभी सबसे अच्छा समाधान है:

#include <iostream>
#include <sstream>
#include <string>

using namespace std;

int main()
{
    string s = "Somewhere down the road";
    istringstream iss(s);

    do
    {
        string subs;
        iss >> subs;
        cout << "Substring: " << subs << endl;
    } while (iss);
}

क्या ऐसा करने का अधिक सुरुचिपूर्ण तरीका है?


617
यार ... लालित्य मेरी पुस्तक में "दक्षता-कि-सुंदर-सुंदर" कहने का एक फैंसी तरीका है। कुछ भी पूरा करने के लिए सी फ़ंक्शन और त्वरित तरीकों का उपयोग करने से

14
while (iss) { string subs; iss >> subs; cout << "Substring: " << sub << endl; }
प्याऊ

21
@Eduardo: यह भी गलत है ... आपको किसी अन्य मान को स्ट्रीम करने की कोशिश करने और उस मान का उपयोग करने के बीच iss का परीक्षण करने की आवश्यकता है, अर्थातstring sub; while (iss >> sub) cout << "Substring: " << sub << '\n';
टोनी डेलरो

9
डिफ़ॉल्ट रूप से ऐसा करने के लिए C ++ में विभिन्न विकल्प: cplusplus.com/faq/fterences/strings/split
hB0

14
वहाँ सुंदर क्षमता से अधिक लालित्य है। सुरुचिपूर्ण विशेषताओं में निम्न पंक्ति गणना और उच्च सुगमता शामिल है। IMHO लालित्य दक्षता के लिए एक छद्म नहीं बल्कि स्थिरता है।
मैट

जवाबों:


1368

इसके लायक क्या है, यहां एक मानक स्ट्रिंग से टोकन निकालने का एक और तरीका है, जो केवल मानक पुस्तकालय सुविधाओं पर निर्भर है। यह एसटीएल के डिजाइन के पीछे की शक्ति और लालित्य का एक उदाहरण है।

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

int main() {
    using namespace std;
    string sentence = "And I feel fine...";
    istringstream iss(sentence);
    copy(istream_iterator<string>(iss),
         istream_iterator<string>(),
         ostream_iterator<string>(cout, "\n"));
}

निकाले गए टोकन को आउटपुट स्ट्रीम में कॉपी करने के बजाय, एक ही सामान्य copyएल्गोरिथ्म का उपयोग करके, उन्हें कंटेनर में डाला जा सकता है।

vector<string> tokens;
copy(istream_iterator<string>(iss),
     istream_iterator<string>(),
     back_inserter(tokens));

... या vectorसीधे बनाएँ :

vector<string> tokens{istream_iterator<string>{iss},
                      istream_iterator<string>{}};

164
क्या इसके लिए एक सीमांकक निर्दिष्ट करना संभव है? उदाहरण के लिए अल्पविराम पर विभाजन?
l3dx

15
@ जोनाथन: \ n इस मामले में परिसीमन नहीं है, यह कॉउट के आउटपुट के लिए अपराधी है।
huy

772
यह एक खराब समाधान है क्योंकि यह कोई अन्य सीमांकक नहीं लेता है, इसलिए स्केलेबल नहीं है और मुख्य नहीं है।
हैलो वर्ल्ड

37
वास्तव में, यह अन्य सीमांकक के साथ ठीक काम कर सकता है (हालांकि कुछ करना कुछ बदसूरत है)। आप ctype facet बनाते हैं, जो वांछित सीमांकक को व्हॉट्सएप के रूप में वर्गीकृत करता है, उस पहलू से युक्त एक लोकेल बनाता है, फिर स्ट्रिंग्स निकालने से पहले उस लोकेल के साथ स्ट्रीस्ट को इम्बेल करता है।
जेरी कॉफिन

53
@ किंडरचेट्रिंग "स्ट्रिंग को व्हाट्सएप द्वारा अलग किए गए शब्दों से बना माना जा सकता है" - हम्म, प्रश्न की समस्या के खराब समाधान की तरह नहीं लगता है। "स्केलेबल नहीं और मेनटेबल नहीं" - हाह , अच्छा।
क्रिश्चियन राऊ

2425

मैं एक सीमांकक द्वारा स्ट्रिंग को विभाजित करने के लिए इसका उपयोग करता हूं। पहला परिणाम पूर्व-निर्मित वेक्टर में डालता है, दूसरा एक नया वेक्टर देता है।

#include <string>
#include <sstream>
#include <vector>
#include <iterator>

template <typename Out>
void split(const std::string &s, char delim, Out result) {
    std::istringstream iss(s);
    std::string item;
    while (std::getline(iss, item, delim)) {
        *result++ = item;
    }
}

std::vector<std::string> split(const std::string &s, char delim) {
    std::vector<std::string> elems;
    split(s, delim, std::back_inserter(elems));
    return elems;
}

ध्यान दें कि यह समाधान खाली टोकन को नहीं छोड़ता है, इसलिए निम्नलिखित में 4 आइटम मिलेंगे, जिनमें से एक खाली है:

std::vector<std::string> x = split("one:two::three", ':');

86
खाली टोकन को छोड़ने से बचने के लिए, एक empty()जांच करें:if (!item.empty()) elems.push_back(item)
0x499602D2

11
कैसे के बारे में दो चार्ट के रूप में परिसीमन होता है ->?
हरोहुयंगताओ

7
@herohuyongtao, यह समाधान केवल सिंगल चार्ट सीमांकक के लिए काम करता है।
इवान टेरान

4
@JeshwanthKumarNK, यह आवश्यक नहीं है, लेकिन यह आपको इस तरह से एक समारोह में सीधे परिणाम पास करने जैसी चीजें करने देता है: यदि आप चाहें तो f(split(s, d, v))अभी भी एक पूर्व-आवंटित का लाभ है vector
इवान टेरान

8
कैविएट: स्प्लिट ("एक: दो :: तीन", ':') और स्प्लिट ("एक: दो :: तीन:", ':') समान मान लौटाते हैं।
19

834

बूस्ट का उपयोग कर एक संभावित समाधान हो सकता है:

#include <boost/algorithm/string.hpp>
std::vector<std::string> strs;
boost::split(strs, "string to split", boost::is_any_of("\t "));

यह दृष्टिकोण दृष्टिकोण से भी तेज हो सकता है stringstream। और चूंकि यह एक सामान्य टेम्प्लेट फ़ंक्शन है, इसलिए इसका उपयोग अन्य प्रकार के स्ट्रिंग्स (wchar, आदि या UTF-8) को सभी प्रकार के सीमांकक का उपयोग करके विभाजित करने के लिए किया जा सकता है।

देखें प्रलेखन जानकारी के लिए।


35
गति यहां अप्रासंगिक है, क्योंकि ये दोनों मामले स्ट्रेटोक जैसे फ़ंक्शन की तुलना में बहुत धीमा हैं।
टॉम

45
और जो लोग पहले से ही बढ़ावा नहीं है ... इस के लिए 1,000 से अधिक फ़ाइलों की प्रतिलिपि bcp :)
रोमन स्टार्कोव

12
चेतावनी, जब एक खाली स्ट्रिंग ("") दी जाती है, तो यह विधि एक वेक्टर लौटाती है जिसमें "" स्ट्रिंग होती है। तो विभाजन से पहले एक "if (string_to_split.empty ())" जोड़ें।
ऑफिशो

29
@Ian एंबेडेड डेवलपर्स सभी को बढ़ावा देने का उपयोग नहीं कर रहे हैं।
ACK_stoverflow

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

362
#include <vector>
#include <string>
#include <sstream>

int main()
{
    std::string str("Split me by whitespaces");
    std::string buf;                 // Have a buffer string
    std::stringstream ss(str);       // Insert the string into a stream

    std::vector<std::string> tokens; // Create vector to hold our words

    while (ss >> buf)
        tokens.push_back(buf);

    return 0;
}

12
यदि आप कॉमा से विभाजित करने के लिए उदाहरण के लिए उपयोग करते हैं getline, तो आप अन्य सीमांकक पर भी विभाजित कर सकते whileहैं while(getline(ss, buff, ','))
अली

181

उन लोगों के लिए जिनके पास कोड आकार के लिए सभी दक्षता का त्याग करने के लिए अच्छी तरह से नहीं बैठते हैं और एक प्रकार की लालित्य के रूप में "कुशल" देखते हैं, निम्नलिखित को एक मीठा स्थान मारना चाहिए (और मुझे लगता है कि टेम्पलेट कंटेनर वर्ग एक बहुत ही सुंदर अतिरिक्त है।)।

template < class ContainerT >
void tokenize(const std::string& str, ContainerT& tokens,
              const std::string& delimiters = " ", bool trimEmpty = false)
{
   std::string::size_type pos, lastPos = 0, length = str.length();

   using value_type = typename ContainerT::value_type;
   using size_type  = typename ContainerT::size_type;

   while(lastPos < length + 1)
   {
      pos = str.find_first_of(delimiters, lastPos);
      if(pos == std::string::npos)
      {
         pos = length;
      }

      if(pos != lastPos || !trimEmpty)
         tokens.push_back(value_type(str.data()+lastPos,
               (size_type)pos-lastPos ));

      lastPos = pos + 1;
   }
}

मैं आमतौर पर std::vector<std::string>अपने दूसरे पैरामीटर ( ContainerT) ... के रूप में उपयोग करने का विकल्प चुनता हूंlist<> इसके vector<>लिए तेजी से रास्ता है जब प्रत्यक्ष पहुंच की आवश्यकता नहीं होती है, और आप अपना स्वयं का स्ट्रिंग वर्ग भी बना सकते हैं और कुछ का उपयोग कर सकते हैं std::list<subString>जहां subStringअविश्वसनीय गति के लिए कोई प्रतियां नहीं करता है बढ़ती है।

यह इस पृष्ठ पर सबसे तेज़ टोकन से दोगुना से अधिक तेज़ है और कुछ अन्य की तुलना में लगभग 5 गुना तेज है। इसके अलावा सही पैरामीटर प्रकारों के साथ आप सभी स्ट्रिंग को समाप्त कर सकते हैं और अतिरिक्त गति में वृद्धि के लिए प्रतियां कॉपी कर सकते हैं।

इसके अतिरिक्त यह परिणाम की अत्यंत (अकुशल) वापसी नहीं करता है, बल्कि यह एक संदर्भ के रूप में टोकन को पारित करता है, इस प्रकार आपको कई कॉल का उपयोग करके टोकन बनाने की अनुमति देता है यदि आप ऐसा चाहते हैं।

अंत में यह आपको यह निर्दिष्ट करने की अनुमति देता है कि अंतिम वैकल्पिक पैरामीटर के माध्यम से परिणामों से खाली टोकन को ट्रिम करना है या नहीं।

इसके लिए सभी की जरूरत है std::string... बाकी वैकल्पिक हैं। यह धाराओं या बूस्ट लाइब्रेरी का उपयोग नहीं करता है, लेकिन इन विदेशी प्रकारों में से कुछ को स्वाभाविक रूप से स्वीकार करने में सक्षम होने के लिए पर्याप्त लचीला है।


5
मैं इसका काफी प्रशंसक हूं, लेकिन जी ++ (और शायद अच्छा अभ्यास) के लिए इसका उपयोग करने वाला कोई भी व्यक्ति टाइपराइफ और टाइपनेम होगा: typedef ContainerT Base; typedef typename Base::value_type ValueType; typedef typename ValueType::size_type SizeType; फिर उसके अनुसार value_type और size_types को स्थानापन्न करना होगा।
एडब्ल्यूएस

11
हममें से जिन लोगों के लिए टेम्प्लेट की सामग्री और पहली टिप्पणी पूरी तरह से विदेशी है, उनके लिए आवश्यक एक उपयोग उदाहरण भी शामिल है जो प्यारा होगा।
वेस मिलर

3
आह, मैं समझ गया। मैंने टोकेनाइज के फंक्शन बॉडी के अंदर aws 'के कमेंट से C ++ लाइन्स डाल दीं, फिर कंटेनर को बदलने के लिए tokens.push_back () लाइन्स को एडिट किया गया :: Value_type को सिर्फ ValueType और Change (कंटेनरटी :: value_type :: size_type) को ( आकार प्रकार)। फिक्स्ड बिट्स जी ++ के बारे में चमक रहा था। इसे टोकन के रूप में लागू करें (some_string, some_vector);
वेस मिलर

2
नमूना डेटा पर कुछ प्रदर्शन परीक्षणों को चलाने के अलावा, मुख्य रूप से मैंने इसे कम से कम संभव निर्देशों के रूप में कम कर दिया है और साथ ही कम से कम संभव मेमोरी प्रतियों को एक विकल्प वर्ग के उपयोग से सक्षम किया गया है जो केवल अन्य स्ट्रिंग्स में ऑफसेट / लंबाई को संदर्भित करता है। (मैंने खुद को रोल किया, लेकिन कुछ अन्य कार्यान्वयन हैं)। दुर्भाग्य से इस पर सुधार करने के लिए बहुत कुछ नहीं हो सकता है, लेकिन वृद्धिशील वृद्धि संभव थी।
Marius

3
कि कब के लिए सही आउटपुट है trimEmpty = true। ध्यान रखें कि "abo"इस उत्तर में कोई सीमांकक नहीं है, लेकिन परिसीमन पात्रों की सूची है। वर्णों के एकल सीमांकक स्ट्रिंग लेने के लिए इसे संशोधित करना सरल होगा (मुझे लगता है कि str.find_first_ofइसे बदलना चाहिए str.find_first, लेकिन मैं गलत हो सकता है ... परीक्षण नहीं कर सकता)
Marius

158

यहाँ एक और उपाय है। यह कॉम्पैक्ट और उचित रूप से कुशल है:

std::vector<std::string> split(const std::string &text, char sep) {
  std::vector<std::string> tokens;
  std::size_t start = 0, end = 0;
  while ((end = text.find(sep, start)) != std::string::npos) {
    tokens.push_back(text.substr(start, end - start));
    start = end + 1;
  }
  tokens.push_back(text.substr(start));
  return tokens;
}

इसे आसानी से स्ट्रिंग विभाजक, विस्तृत तार आदि को संभालने के लिए टेम्प्लेट किया जा सकता है।

ध्यान दें कि विभाजन ""एक खाली स्ट्रिंग और विभाजन में परिणाम करता है"," (यानी। sep) के परिणामस्वरूप दो खाली स्ट्रिंग्स में होता है।

खाली टोकन को छोड़ने के लिए इसे आसानी से विस्तारित किया जा सकता है:

std::vector<std::string> split(const std::string &text, char sep) {
    std::vector<std::string> tokens;
    std::size_t start = 0, end = 0;
    while ((end = text.find(sep, start)) != std::string::npos) {
        if (end != start) {
          tokens.push_back(text.substr(start, end - start));
        }
        start = end + 1;
    }
    if (end != start) {
       tokens.push_back(text.substr(start));
    }
    return tokens;
}

यदि खाली टोकन को छोड़ते समय एक स्ट्रिंग को कई सीमांकक पर विभाजित किया जाता है, तो इस संस्करण का उपयोग किया जा सकता है:

std::vector<std::string> split(const std::string& text, const std::string& delims)
{
    std::vector<std::string> tokens;
    std::size_t start = text.find_first_not_of(delims), end = 0;

    while((end = text.find_first_of(delims, start)) != std::string::npos)
    {
        tokens.push_back(text.substr(start, end - start));
        start = text.find_first_not_of(delims, end);
    }
    if(start != std::string::npos)
        tokens.push_back(text.substr(start));

    return tokens;
}

10
पहला संस्करण सरल है और काम पूरी तरह से हो जाता है। केवल एक बदलाव जो मैंने किया, वह एक पैरामीटर के रूप में इसे पारित करने के बजाय सीधे परिणाम वापस करना होगा।
gregschlom

2
आउटपुट दक्षता के लिए एक पैरामीटर के रूप में पारित किया जाता है। यदि परिणाम लौटाया जाता है तो इसके लिए वेक्टर की एक प्रति या फिर ढेर आवंटन की आवश्यकता होती है जिसे फिर से मुक्त करना होगा।
एलेक थॉमस

2
ऊपर मेरी टिप्पणी के लिए एक मामूली परिशिष्ट: यह फ़ंक्शन C ++ 11 चाल शब्दार्थ का उपयोग करते हुए बिना दंड के वेक्टर वापस कर सकता है।
एलेक थॉमस

7
@AlecThomas: C ++ 11 से पहले भी, अधिकांश कंपाइलर NRVO के माध्यम से रिटर्न कॉपी का अनुकूलन नहीं करेंगे? (वैसे भी, बहुत रसीला)
मार्सेलो कैंटोस

11
सभी उत्तरों में से यह सबसे आकर्षक और लचीला में से एक प्रतीत होता है। एक परिसीमन के साथ गेटलाइन के साथ, हालांकि इसका कम स्पष्ट समाधान है। क्या c ++ 11 मानक में इसके लिए कुछ भी नहीं है? क्या सी ++ 11 इन दिनों पंच कार्ड का समर्थन करता है?
Spacen Jasset

123

यह एक स्ट्रिंग के माध्यम से पुनरावृति करने का मेरा पसंदीदा तरीका है। आप प्रति शब्द जो चाहें कर सकते हैं।

string line = "a line of text to iterate through";
string word;

istringstream iss(line, istringstream::in);

while( iss >> word )     
{
    // Do something on `word` here...
}

क्या इसे घोषित करना संभव wordहै char?
abatishchev

क्षमा करें abatishchev, C ++ मेरा मजबूत बिंदु नहीं है। लेकिन मुझे लगता है कि प्रत्येक शब्द में प्रत्येक चरित्र के माध्यम से लूप में आंतरिक लूप जोड़ना मुश्किल नहीं होगा। लेकिन अभी मेरा मानना ​​है कि वर्तमान लूप शब्द पृथक्करण के लिए रिक्त स्थान पर निर्भर करता है। जब तक आप नहीं जानते कि हर जगह के बीच एक ही चरित्र है, जिस स्थिति में आप "शब्द" को एक चार में डाल सकते हैं ... क्षमा करें मैं अधिक मदद नहीं कर सकता, ive का अर्थ मेरे C ++ पर ब्रश करना है
gnomed

11
यदि आप शब्द को एक चार के रूप में घोषित करते हैं तो यह हर गैर-व्हाट्सएप चरित्र पर प्रसारित होगा। यह कोशिश करने के लिए काफी सरल है:stringstream ss("Hello World, this is*@#&$(@ a string"); char c; while(ss >> c) cout << c;
वेन वर्नर

79

यह स्टैक ओवरफ्लो प्रश्न के समान है मैं C ++ में स्ट्रिंग को कैसे टोकन कर सकता हूं?

#include <iostream>
#include <string>
#include <boost/tokenizer.hpp>

using namespace std;
using namespace boost;

int main(int argc, char** argv)
{
    string text = "token  test\tstring";

    char_separator<char> sep(" \t");
    tokenizer<char_separator<char>> tokens(text, sep);
    for (const string& t : tokens)
    {
        cout << t << "." << endl;
    }
}

क्या यह सभी टोकन की एक प्रतिलिपि बनाता है, या क्या यह केवल वर्तमान टोकन की शुरुआत और समाप्ति स्थिति रखता है?
einpoklum

66

मुझे निम्नलिखित पसंद है क्योंकि यह परिणामों को एक सदिश में रखता है, एक स्ट्रिंग को परिसीमन के रूप में समर्थन देता है और खाली मान रखने पर नियंत्रण देता है। लेकिन, यह तब उतना अच्छा नहीं लगता है।

#include <ostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;

vector<string> split(const string& s, const string& delim, const bool keep_empty = true) {
    vector<string> result;
    if (delim.empty()) {
        result.push_back(s);
        return result;
    }
    string::const_iterator substart = s.begin(), subend;
    while (true) {
        subend = search(substart, s.end(), delim.begin(), delim.end());
        string temp(substart, subend);
        if (keep_empty || !temp.empty()) {
            result.push_back(temp);
        }
        if (subend == s.end()) {
            break;
        }
        substart = subend + delim.size();
    }
    return result;
}

int main() {
    const vector<string> words = split("So close no matter how far", " ");
    copy(words.begin(), words.end(), ostream_iterator<string>(cout, "\n"));
}

बेशक, बूस्ट के पास split()आंशिक रूप से काम करता है। और, अगर 'व्हाइट-स्पेस' द्वारा, आप वास्तव में किसी भी प्रकार के व्हाइट-स्पेस का मतलब रखते हैं, तो is_any_of()काम के साथ बूस्ट के विभाजन का उपयोग करना ।


अंत में एक समाधान जो स्ट्रिंग के दोनों किनारों पर सही ढंग से खाली टोकन को संभाल रहा है
fmuecke

53

एसटीएल के पास ऐसी कोई विधि पहले से उपलब्ध नहीं है।

हालाँकि, आप या तो सदस्य strtok()का उपयोग करके C के फ़ंक्शन का उपयोग std::string::c_str()कर सकते हैं, या आप अपना स्वयं का लिख ​​सकते हैं। यहाँ एक कोड नमूना है जो मुझे त्वरित Google खोज ( "एसटीएल स्ट्रिंग स्प्लिट" ) के बाद मिला है :

void Tokenize(const string& str,
              vector<string>& tokens,
              const string& delimiters = " ")
{
    // Skip delimiters at beginning.
    string::size_type lastPos = str.find_first_not_of(delimiters, 0);
    // Find first "non-delimiter".
    string::size_type pos     = str.find_first_of(delimiters, lastPos);

    while (string::npos != pos || string::npos != lastPos)
    {
        // Found a token, add it to the vector.
        tokens.push_back(str.substr(lastPos, pos - lastPos));
        // Skip delimiters.  Note the "not_of"
        lastPos = str.find_first_not_of(delimiters, pos);
        // Find next "non-delimiter"
        pos = str.find_first_of(delimiters, lastPos);
    }
}

इससे लिया गया: http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html

यदि आपके पास कोड नमूने के बारे में प्रश्न हैं, तो एक टिप्पणी छोड़ दें और मैं समझाऊंगा।

और सिर्फ इसलिए कि यह एक typedefबुलाया पुनरावृत्ति को लागू नहीं करता है या <<ऑपरेटर को अधिभार नहीं देता है इसका मतलब यह नहीं है कि यह खराब कोड है। मैं सी फ़ंक्शन का अक्सर उपयोग करता हूं। उदाहरण के लिए, printfऔर scanfदोनों ( std::cinऔर std::cout) से तेज हैं ,fopen वाक्यविन्यास द्विआधारी प्रकार के लिए बहुत अधिक अनुकूल है, और वे छोटे EXE का उत्पादन भी करते हैं।

इस "लालित्य पर प्रदर्शन" सौदे पर मत बेचो


मुझे C स्ट्रिंग फ़ंक्शंस के बारे में पता है और मुझे प्रदर्शन के मुद्दों की भी जानकारी है (दोनों जिनमें से मैंने अपने प्रश्न में नोट किया है)। हालांकि, इस विशिष्ट प्रश्न के लिए, मैं एक सुंदर सी ++ समाधान की तलाश कर रहा हूं।
अश्विन नंजप्पा

11
@ नेल्सन LaQuet: मुझे लगता है: क्योंकि strtok reentrant नहीं है?
पियरसबल

40
@Nelson strtok को कभी string.c_str () पास नहीं करता है! strtok इनपुट स्ट्रिंग (प्रत्येक fudn सीमांकक को बदलने के लिए '\' 'वर्ण सम्मिलित करता है) और c_str () एक गैर-परिवर्तनीय स्ट्रिंग देता है।
इवान टेरान

3
@ नेल्सन: आपकी अंतिम टिप्पणी में उस सरणी का आकार str.size () + 1 होना चाहिए। लेकिन मैं आपकी थीसिस से सहमत हूं कि "सौंदर्यवादी" कारणों से सी कार्यों से बचने के लिए यह मूर्खतापूर्ण है।
j_random_hacker 9

2
@ अंपुलम: नहीं, C ++ स्ट्रीम की सुस्ती, पहलुओं के कारण होती है। जब वे सिंक्रनाइज़ेशन अक्षम हो जाते हैं तब भी stdio.h फ़ंक्शन की तुलना में वे धीमे होते हैं (और स्ट्रिंग पर, जो सिंक्रनाइज़ नहीं हो सकते हैं)।
बेन वोइग्ट

42

यहाँ एक विभाजन कार्य है कि:

  • सामान्य है
  • मानक C ++ (कोई बढ़ावा नहीं) का उपयोग करता है
  • कई सीमांकक स्वीकार करता है
  • खाली टोकन को अनदेखा करता है (आसानी से बदला जा सकता है)

    template<typename T>
    vector<T> 
    split(const T & str, const T & delimiters) {
        vector<T> v;
        typename T::size_type start = 0;
        auto pos = str.find_first_of(delimiters, start);
        while(pos != T::npos) {
            if(pos != start) // ignore empty tokens
                v.emplace_back(str, start, pos - start);
            start = pos + 1;
            pos = str.find_first_of(delimiters, start);
        }
        if(start < str.length()) // ignore trailing delimiter
            v.emplace_back(str, start, str.length() - start); // add what's left of the string
        return v;
    }

उदाहरण उपयोग:

    vector<string> v = split<string>("Hello, there; World", ";,");
    vector<wstring> v = split<wstring>(L"Hello, there; World", L";,");

आप सूची का उपयोग करने के लिए जोड़ना भूल गए: "बेहद अक्षम"
Xander ट्यूलिप

1
@XanderTulip, क्या आप अधिक रचनात्मक हो सकते हैं और बता सकते हैं कि कैसे या क्यों?
मार्को एम।

3
@XanderTulip: मुझे लगता है कि आप इसे सदिश मान द्वारा वापस लौटाने की बात कर रहे हैं। रिटर्न-वैल्यू-ऑप्टिमाइजेशन (RVO, google it) को इस बात का ध्यान रखना चाहिए। इसके अलावा C ++ 11 में आप मूव रेफरेंस द्वारा लौट सकते हैं।
जोसेफ गार्विन

3
इसे वास्तव में आगे अनुकूलित किया जा सकता है: .push_back (str.substr (...)) के बजाय .emplace_back (str, start, pos - start) का उपयोग किया जा सकता है। इस तरह से स्ट्रिंग ऑब्जेक्ट कंटेनर में निर्मित होता है और इस प्रकार हम एक चालन ऑपरेशन से बचते हैं।
महाई बायसॉग

@ हां हां। अच्छा विचार। जब मैंने यह लिखा तो VS10 के पास emplace_back समर्थन नहीं था। मैं अपना जवाब अपडेट करूंगा। साभार
मार्को एम।

36

मेरे पास इस समस्या का 2 लाइन समाधान है:

char sep = ' ';
std::string s="1 This is an example";

for(size_t p=0, q=0; p!=s.npos; p=q)
  std::cout << s.substr(p+(p!=0), (q=s.find(sep, p+1))-p-(p!=0)) << std::endl;

फिर प्रिंट करने के बजाय आप इसे वेक्टर में डाल सकते हैं।


35

फिर भी एक और लचीला और तेज़ तरीका

template<typename Operator>
void tokenize(Operator& op, const char* input, const char* delimiters) {
  const char* s = input;
  const char* e = s;
  while (*e != 0) {
    e = s;
    while (*e != 0 && strchr(delimiters, *e) == 0) ++e;
    if (e - s > 0) {
      op(s, e - s);
    }
    s = e + 1;
  }
}

स्ट्रिंग के वेक्टर के साथ इसका उपयोग करने के लिए (संपादित करें: चूंकि किसी ने बताया कि एसटीएल कक्षाएं विरासत में नहीं मिली हैं ... hrmoff।)::

template<class ContainerType>
class Appender {
public:
  Appender(ContainerType& container) : container_(container) {;}
  void operator() (const char* s, unsigned length) { 
    container_.push_back(std::string(s,length));
  }
private:
  ContainerType& container_;
};

std::vector<std::string> strVector;
Appender v(strVector);
tokenize(v, "A number of words to be tokenized", " \t");

बस! और यह टोकन का उपयोग करने का सिर्फ एक तरीका है, जैसे कि शब्दों को कैसे गिनना है:

class WordCounter {
public:
  WordCounter() : noOfWords(0) {}
  void operator() (const char*, unsigned) {
    ++noOfWords;
  }
  unsigned noOfWords;
};

WordCounter wc;
tokenize(wc, "A number of words to be counted", " \t"); 
ASSERT( wc.noOfWords == 7 );

कल्पना द्वारा सीमित;)



32

यहां एक सरल समाधान है जो केवल मानक रेगेक्स लाइब्रेरी का उपयोग करता है

#include <regex>
#include <string>
#include <vector>

std::vector<string> Tokenize( const string str, const std::regex regex )
{
    using namespace std;

    std::vector<string> result;

    sregex_token_iterator it( str.begin(), str.end(), regex, -1 );
    sregex_token_iterator reg_end;

    for ( ; it != reg_end; ++it ) {
        if ( !it->str().empty() ) //token could be empty:check
            result.emplace_back( it->str() );
    }

    return result;
}

रेगेक्स तर्क कई तर्कों (रिक्त स्थान, अल्पविराम, आदि) के लिए जाँच की अनुमति देता है

मैं आमतौर पर केवल रिक्त स्थान और अल्पविराम पर विभाजित करने की जांच करता हूं, इसलिए मेरे पास यह डिफ़ॉल्ट फ़ंक्शन भी है:

std::vector<string> TokenizeDefault( const string str )
{
    using namespace std;

    regex re( "[\\s,]+" );

    return Tokenize( str, re );
}

"[\\s,]+"रिक्त स्थान (के लिए चेक \\s) और अल्पविराम (, )।

ध्यान दें, यदि आप wstringइसके बजाय विभाजित करना चाहते हैं string,

  • सभी std::regexको बदल देंstd::wregex
  • सभी sregex_token_iteratorको बदल देंwsregex_token_iterator

ध्यान दें, आप अपने संकलक के आधार पर, संदर्भ द्वारा स्ट्रिंग तर्क भी लेना चाह सकते हैं।


यह मेरा पसंदीदा जवाब होता, लेकिन st :: :: regex GCC 4.8 में टूट गया है। उन्होंने कहा कि उन्होंने इसे जीसीसी 4.9 में सही तरीके से लागू किया। मैं आपको अभी भी अपना +1
मोचीसन

1
यह मामूली बदलावों के साथ मेरा पसंदीदा है: वेक्टर ने आपके संदर्भ के अनुसार संदर्भ दिया, और तर्क "str" ​​और "regex" भी संदर्भों से पारित हुए। धन्यवाद।
क्वांटम कर्ल

1
रेगेक्स पैटर्न के साथ काम करते समय कच्चे तार बहुत उपयोगी होते हैं। इस तरह, आपको भागने के दृश्यों का उपयोग करने की आवश्यकता नहीं है ... आप बस उपयोग कर सकते हैं R"([\s,]+)"
सैम

26

उपयोग के std::stringstreamरूप में आप पूरी तरह से ठीक काम करता है, और ठीक वही करें जो आप चाहते थे। यदि आप अभी कुछ करने के विभिन्न तरीकों की तलाश कर रहे हैं, तो आप std::find()/ std::find_first_of()और का उपयोग कर सकते हैं std::string::substr()

यहाँ एक उदाहरण है:

#include <iostream>
#include <string>

int main()
{
    std::string s("Somewhere down the road");
    std::string::size_type prev_pos = 0, pos = 0;

    while( (pos = s.find(' ', pos)) != std::string::npos )
    {
        std::string substring( s.substr(prev_pos, pos-prev_pos) );

        std::cout << substring << '\n';

        prev_pos = ++pos;
    }

    std::string substring( s.substr(prev_pos, pos-prev_pos) ); // Last word
    std::cout << substring << '\n';

    return 0;
}

यह केवल सिंगल कैरेक्टर डेलिमिटर के लिए काम करता है। एक साधारण परिवर्तन इसे मल्टीचैकर के साथ काम करने देता है:prev_pos = pos += delimiter.length();
डेविड डोरिया

25

यदि आप बूस्ट का उपयोग करना पसंद करते हैं, लेकिन संपूर्ण स्ट्रिंग को सीमांकक के रूप में उपयोग करना चाहते हैं (पहले प्रस्तावित समाधानों में से अधिकांश में एकल वर्णों के बजाय), तो आप उपयोग कर सकते हैं boost_split_iterator

सुविधाजनक टेम्पलेट सहित उदाहरण कोड:

#include <iostream>
#include <vector>
#include <boost/algorithm/string.hpp>

template<typename _OutputIterator>
inline void split(
    const std::string& str, 
    const std::string& delim, 
    _OutputIterator result)
{
    using namespace boost::algorithm;
    typedef split_iterator<std::string::const_iterator> It;

    for(It iter=make_split_iterator(str, first_finder(delim, is_equal()));
            iter!=It();
            ++iter)
    {
        *(result++) = boost::copy_range<std::string>(*iter);
    }
}

int main(int argc, char* argv[])
{
    using namespace std;

    vector<string> splitted;
    split("HelloFOOworldFOO!", "FOO", back_inserter(splitted));

    // or directly to console, for example
    split("HelloFOOworldFOO!", "FOO", ostream_iterator<string>(cout, "\n"));
    return 0;
}

20

एक रेगेक्स समाधान का उपयोग करता है जो केवल मानक रेगेक्स पुस्तकालय का उपयोग करता है। (मैं थोड़ा कठोर हूं, इसलिए कुछ वाक्यविन्यास त्रुटियां हो सकती हैं, लेकिन यह कम से कम सामान्य विचार है)

#include <regex.h>
#include <string.h>
#include <vector.h>

using namespace std;

vector<string> split(string s){
    regex r ("\\w+"); //regex matches whole words, (greedy, so no fragment words)
    regex_iterator<string::iterator> rit ( s.begin(), s.end(), r );
    regex_iterator<string::iterator> rend; //iterators to iterate thru words
    vector<string> result<regex_iterator>(rit, rend);
    return result;  //iterates through the matches to fill the vector
}

शायद बेहतर रेगेक्स दृष्टिकोण के साथ इसी तरह की प्रतिक्रियाएं: यहां , और यहां
नोबार

20

नाम का एक फंक्शन है strtok

#include<string>
using namespace std;

vector<string> split(char* str,const char* delim)
{
    char* saveptr;
    char* token = strtok_r(str,delim,&saveptr);

    vector<string> result;

    while(token != NULL)
    {
        result.push_back(token);
        token = strtok_r(NULL,delim,&saveptr);
    }
    return result;
}

3
strtokC मानक लाइब्रेरी से है, C ++ से नहीं। मल्टीथ्रेडेड कार्यक्रमों में उपयोग करना सुरक्षित नहीं है। यह इनपुट स्ट्रिंग को संशोधित करता है।
केविन पैनको

13
चूँकि यह एक स्थिर वैरिएबल में पहली कॉल से चार सूचक को संग्रहीत करता है, ताकि बाद में कॉल पर जब NULL पारित हो, तो यह याद रखता है कि किस सूचक का उपयोग किया जाना चाहिए। यदि कोई दूसरा थ्रेड कॉल करता है strtokजब कोई अन्य थ्रेड अभी भी संसाधित हो रहा है, तो यह चार्ट पॉइंटर ओवरराइट हो जाएगा, और दोनों थ्रेड्स के बाद गलत परिणाम होंगे। mkssoftware.com/docs/man3/strtok.3.asp
केविन

1
जैसा कि स्टर्टोक से पहले उल्लेख किया गया है असुरक्षित है और यहां तक ​​कि सी में strtok_r उपयोग के लिए अनुशंसित है
सिस्टमफॉल्ट

4
strtok_r का उपयोग किया जा सकता है यदि आप उस कोड के एक भाग में हैं जिसे एक्सेस किया जा सकता है। यह उपर्युक्त सभी का एकमात्र समाधान है जो "लाइन शोर" नहीं है, और क्या, वास्तव में, सी + + के साथ गलत है के लिए एक वसीयतनामा है
एरिक एरोनीस्टी

अद्यतन किया जाता है ताकि C ++ विनक से थ्रेड सुरक्षा के आधार पर कोई आपत्ति न हो।
एरिक एरोनेस्टी

17

Stringstream सुविधाजनक हो सकता है अगर आप गैर अंतरिक्ष प्रतीकों से स्ट्रिंग पार्स करने की जरूरत है:

string s = "Name:JAck; Spouse:Susan; ...";
string dummy, name, spouse;

istringstream iss(s);
getline(iss, dummy, ':');
getline(iss, name, ';');
getline(iss, dummy, ':');
getline(iss, spouse, ';')

14

अब तक मैं बूस्ट में एक का उपयोग करता था , लेकिन मुझे कुछ ऐसा चाहिए था जो इस पर निर्भर न हो, इसलिए मैं इस पर आया:

static void Split(std::vector<std::string>& lst, const std::string& input, const std::string& separators, bool remove_empty = true)
{
    std::ostringstream word;
    for (size_t n = 0; n < input.size(); ++n)
    {
        if (std::string::npos == separators.find(input[n]))
            word << input[n];
        else
        {
            if (!word.str().empty() || !remove_empty)
                lst.push_back(word.str());
            word.str("");
        }
    }
    if (!word.str().empty() || !remove_empty)
        lst.push_back(word.str());
}

एक अच्छी बात यह है कि separatorsआप एक से अधिक पात्रों को पारित कर सकते हैं।


13

मैंने स्ट्रेटोक का उपयोग करके अपना स्वयं का रोल किया है और स्ट्रिंग को विभाजित करने के लिए बूस्ट का उपयोग किया है। सबसे अच्छी विधि जो मुझे मिली है वह है C ++ स्ट्रिंग टूलकिट लाइब्रेरी । यह अविश्वसनीय रूप से लचीला और तेज है।

#include <iostream>
#include <vector>
#include <string>
#include <strtk.hpp>

const char *whitespace  = " \t\r\n\f";
const char *whitespace_and_punctuation  = " \t\r\n\f;,=";

int main()
{
    {   // normal parsing of a string into a vector of strings
        std::string s("Somewhere down the road");
        std::vector<std::string> result;
        if( strtk::parse( s, whitespace, result ) )
        {
            for(size_t i = 0; i < result.size(); ++i )
                std::cout << result[i] << std::endl;
        }
    }

    {  // parsing a string into a vector of floats with other separators
        // besides spaces

        std::string s("3.0, 3.14; 4.0");
        std::vector<float> values;
        if( strtk::parse( s, whitespace_and_punctuation, values ) )
        {
            for(size_t i = 0; i < values.size(); ++i )
                std::cout << values[i] << std::endl;
        }
    }

    {  // parsing a string into specific variables

        std::string s("angle = 45; radius = 9.9");
        std::string w1, w2;
        float v1, v2;
        if( strtk::parse( s, whitespace_and_punctuation, w1, v1, w2, v2) )
        {
            std::cout << "word " << w1 << ", value " << v1 << std::endl;
            std::cout << "word " << w2 << ", value " << v2 << std::endl;
        }
    }

    return 0;
}

टूलकिट में इस सरल उदाहरण शो की तुलना में बहुत अधिक लचीलापन है लेकिन एक स्ट्रिंग को उपयोगी तत्वों में पार्स करने में इसकी उपयोगिता अविश्वसनीय है।


13

लघु और सुरुचिपूर्ण

#include <vector>
#include <string>
using namespace std;

vector<string> split(string data, string token)
{
    vector<string> output;
    size_t pos = string::npos; // size_t to avoid improbable overflow
    do
    {
        pos = data.find(token);
        output.push_back(data.substr(0, pos));
        if (string::npos != pos)
            data = data.substr(pos + token.size());
    } while (string::npos != pos);
    return output;
}

किसी भी स्ट्रिंग को सीमांकक के रूप में उपयोग कर सकते हैं, बाइनरी डेटा के साथ भी उपयोग किया जा सकता है (std :: string बाइनरी डेटा का समर्थन करता है, जिसमें नल भी शामिल है)

का उपयोग करते हुए:

auto a = split("this!!is!!!example!string", "!!");

उत्पादन:

this
is
!example!string

1
मुझे यह समाधान पसंद है क्योंकि यह विभाजक को एक स्ट्रिंग बनाने की अनुमति देता है न कि एक चार, हालांकि, यह स्ट्रिंग की जगह को संशोधित कर रहा है, इसलिए यह मूल स्ट्रिंग की प्रतिलिपि बनाने के लिए मजबूर कर रहा है।
एलेसेंड्रो टेरुज़ी

11

मैंने इसे बनाया क्योंकि मुझे स्ट्रिंग्स और सी-आधारित स्ट्रिंग्स को विभाजित करने का एक आसान तरीका चाहिए ... उम्मीद है कि कोई और इसे उपयोगी भी पा सकता है। इसके अलावा यह टोकन पर निर्भर नहीं करता है और आप खेतों को सीमांकक के रूप में उपयोग कर सकते हैं, जो एक और कुंजी है जिसकी मुझे आवश्यकता है।

मुझे यकीन है कि ऐसे सुधार हैं जो आगे भी अपनी शान में सुधार कर सकते हैं और कृपया सभी तरीकों से करें

StringSplitter.hpp:

#include <vector>
#include <iostream>
#include <string.h>

using namespace std;

class StringSplit
{
private:
    void copy_fragment(char*, char*, char*);
    void copy_fragment(char*, char*, char);
    bool match_fragment(char*, char*, int);
    int untilnextdelim(char*, char);
    int untilnextdelim(char*, char*);
    void assimilate(char*, char);
    void assimilate(char*, char*);
    bool string_contains(char*, char*);
    long calc_string_size(char*);
    void copy_string(char*, char*);

public:
    vector<char*> split_cstr(char);
    vector<char*> split_cstr(char*);
    vector<string> split_string(char);
    vector<string> split_string(char*);
    char* String;
    bool do_string;
    bool keep_empty;
    vector<char*> Container;
    vector<string> ContainerS;

    StringSplit(char * in)
    {
        String = in;
    }

    StringSplit(string in)
    {
        size_t len = calc_string_size((char*)in.c_str());
        String = new char[len + 1];
        memset(String, 0, len + 1);
        copy_string(String, (char*)in.c_str());
        do_string = true;
    }

    ~StringSplit()
    {
        for (int i = 0; i < Container.size(); i++)
        {
            if (Container[i] != NULL)
            {
                delete[] Container[i];
            }
        }
        if (do_string)
        {
            delete[] String;
        }
    }
};

StringSplitter.cpp:

#include <string.h>
#include <iostream>
#include <vector>
#include "StringSplit.hpp"

using namespace std;

void StringSplit::assimilate(char*src, char delim)
{
    int until = untilnextdelim(src, delim);
    if (until > 0)
    {
        char * temp = new char[until + 1];
        memset(temp, 0, until + 1);
        copy_fragment(temp, src, delim);
        if (keep_empty || *temp != 0)
        {
            if (!do_string)
            {
                Container.push_back(temp);
            }
            else
            {
                string x = temp;
                ContainerS.push_back(x);
            }

        }
        else
        {
            delete[] temp;
        }
    }
}

void StringSplit::assimilate(char*src, char* delim)
{
    int until = untilnextdelim(src, delim);
    if (until > 0)
    {
        char * temp = new char[until + 1];
        memset(temp, 0, until + 1);
        copy_fragment(temp, src, delim);
        if (keep_empty || *temp != 0)
        {
            if (!do_string)
            {
                Container.push_back(temp);
            }
            else
            {
                string x = temp;
                ContainerS.push_back(x);
            }
        }
        else
        {
            delete[] temp;
        }
    }
}

long StringSplit::calc_string_size(char* _in)
{
    long i = 0;
    while (*_in++)
    {
        i++;
    }
    return i;
}

bool StringSplit::string_contains(char* haystack, char* needle)
{
    size_t len = calc_string_size(needle);
    size_t lenh = calc_string_size(haystack);
    while (lenh--)
    {
        if (match_fragment(haystack + lenh, needle, len))
        {
            return true;
        }
    }
    return false;
}

bool StringSplit::match_fragment(char* _src, char* cmp, int len)
{
    while (len--)
    {
        if (*(_src + len) != *(cmp + len))
        {
            return false;
        }
    }
    return true;
}

int StringSplit::untilnextdelim(char* _in, char delim)
{
    size_t len = calc_string_size(_in);
    if (*_in == delim)
    {
        _in += 1;
        return len - 1;
    }

    int c = 0;
    while (*(_in + c) != delim && c < len)
    {
        c++;
    }

    return c;
}

int StringSplit::untilnextdelim(char* _in, char* delim)
{
    int s = calc_string_size(delim);
    int c = 1 + s;

    if (!string_contains(_in, delim))
    {
        return calc_string_size(_in);
    }
    else if (match_fragment(_in, delim, s))
    {
        _in += s;
        return calc_string_size(_in);
    }

    while (!match_fragment(_in + c, delim, s))
    {
        c++;
    }

    return c;
}

void StringSplit::copy_fragment(char* dest, char* src, char delim)
{
    if (*src == delim)
    {
        src++;
    }

    int c = 0;
    while (*(src + c) != delim && *(src + c))
    {
        *(dest + c) = *(src + c);
        c++;
    }
    *(dest + c) = 0;
}

void StringSplit::copy_string(char* dest, char* src)
{
    int i = 0;
    while (*(src + i))
    {
        *(dest + i) = *(src + i);
        i++;
    }
}

void StringSplit::copy_fragment(char* dest, char* src, char* delim)
{
    size_t len = calc_string_size(delim);
    size_t lens = calc_string_size(src);

    if (match_fragment(src, delim, len))
    {
        src += len;
        lens -= len;
    }

    int c = 0;
    while (!match_fragment(src + c, delim, len) && (c < lens))
    {
        *(dest + c) = *(src + c);
        c++;
    }
    *(dest + c) = 0;
}

vector<char*> StringSplit::split_cstr(char Delimiter)
{
    int i = 0;
    while (*String)
    {
        if (*String != Delimiter && i == 0)
        {
            assimilate(String, Delimiter);
        }
        if (*String == Delimiter)
        {
            assimilate(String, Delimiter);
        }
        i++;
        String++;
    }

    String -= i;
    delete[] String;

    return Container;
}

vector<string> StringSplit::split_string(char Delimiter)
{
    do_string = true;

    int i = 0;
    while (*String)
    {
        if (*String != Delimiter && i == 0)
        {
            assimilate(String, Delimiter);
        }
        if (*String == Delimiter)
        {
            assimilate(String, Delimiter);
        }
        i++;
        String++;
    }

    String -= i;
    delete[] String;

    return ContainerS;
}

vector<char*> StringSplit::split_cstr(char* Delimiter)
{
    int i = 0;
    size_t LenDelim = calc_string_size(Delimiter);

    while(*String)
    {
        if (!match_fragment(String, Delimiter, LenDelim) && i == 0)
        {
            assimilate(String, Delimiter);
        }
        if (match_fragment(String, Delimiter, LenDelim))
        {
            assimilate(String,Delimiter);
        }
        i++;
        String++;
    }

    String -= i;
    delete[] String;

    return Container;
}

vector<string> StringSplit::split_string(char* Delimiter)
{
    do_string = true;
    int i = 0;
    size_t LenDelim = calc_string_size(Delimiter);

    while (*String)
    {
        if (!match_fragment(String, Delimiter, LenDelim) && i == 0)
        {
            assimilate(String, Delimiter);
        }
        if (match_fragment(String, Delimiter, LenDelim))
        {
            assimilate(String, Delimiter);
        }
        i++;
        String++;
    }

    String -= i;
    delete[] String;

    return ContainerS;
}

उदाहरण:

int main(int argc, char*argv[])
{
    StringSplit ss = "This:CUT:is:CUT:an:CUT:example:CUT:cstring";
    vector<char*> Split = ss.split_cstr(":CUT:");

    for (int i = 0; i < Split.size(); i++)
    {
        cout << Split[i] << endl;
    }

    return 0;
}

उत्पादन होगा:

यह
है
एक
उदाहरण
cstring

int main(int argc, char*argv[])
{
    StringSplit ss = "This:is:an:example:cstring";
    vector<char*> Split = ss.split_cstr(':');

    for (int i = 0; i < Split.size(); i++)
    {
        cout << Split[i] << endl;
    }

    return 0;
}

int main(int argc, char*argv[])
{
    string mystring = "This[SPLIT]is[SPLIT]an[SPLIT]example[SPLIT]string";
    StringSplit ss = mystring;
    vector<string> Split = ss.split_string("[SPLIT]");

    for (int i = 0; i < Split.size(); i++)
    {
        cout << Split[i] << endl;
    }

    return 0;
}

int main(int argc, char*argv[])
{
    string mystring = "This|is|an|example|string";
    StringSplit ss = mystring;
    vector<string> Split = ss.split_string('|');

    for (int i = 0; i < Split.size(); i++)
    {
        cout << Split[i] << endl;
    }

    return 0;
}

खाली प्रविष्टियाँ रखने के लिए (डिफ़ॉल्ट रूप से खाली किए गए को बाहर रखा जाएगा):

StringSplit ss = mystring;
ss.keep_empty = true;
vector<string> Split = ss.split_string(":DELIM:");

लक्ष्य यह था कि यह C # की स्प्लिट () विधि के समान हो, जहाँ एक स्ट्रिंग को विभाजित करना उतना ही आसान है:

String[] Split = 
    "Hey:cut:what's:cut:your:cut:name?".Split(new[]{":cut:"}, StringSplitOptions.None);

foreach(String X in Split)
{
    Console.Write(X);
}

मुझे आशा है कि कोई अन्य इसे उतना उपयोगी पा सकता है जितना मैं करता हूं।


10

इस बारे में क्या:

#include <string>
#include <vector>

using namespace std;

vector<string> split(string str, const char delim) {
    vector<string> v;
    string tmp;

    for(string::const_iterator i; i = str.begin(); i <= str.end(); ++i) {
        if(*i != delim && i != str.end()) {
            tmp += *i; 
        } else {
            v.push_back(tmp);
            tmp = ""; 
        }   
    }   

    return v;
}

यह यहां सबसे अच्छा जवाब है, यदि आप केवल एक एकल सीमांकक चरित्र पर विभाजित करना चाहते हैं। मूल प्रश्न हालांकि व्हाट्सएप पर विभाजित करना चाहता था, जिसका अर्थ है एक या एक से अधिक लगातार रिक्त स्थान या टैब का संयोजन। आपने वास्तव में stackoverflow.com/questions/53849
Oktalist

10

यह उत्तर स्ट्रिंग लेता है और इसे स्ट्रिंग के वेक्टर में डालता है। यह बूस्ट लाइब्रेरी का उपयोग करता है।

#include <boost/algorithm/string.hpp>
std::vector<std::string> strs;
boost::split(strs, "string to split", boost::is_any_of("\t "));


9

मैं इस कार्य के लिए बूस्ट / रेगेक्स विधियों का उपयोग करना पसंद करता हूं क्योंकि वे बंटवारे के मानदंडों को निर्दिष्ट करने के लिए अधिकतम लचीलापन प्रदान करते हैं।

#include <iostream>
#include <string>
#include <boost/regex.hpp>

int main() {
    std::string line("A:::line::to:split");
    const boost::regex re(":+"); // one or more colons

    // -1 means find inverse matches aka split
    boost::sregex_token_iterator tokens(line.begin(),line.end(),re,-1);
    boost::sregex_token_iterator end;

    for (; tokens != end; ++tokens)
        std::cout << *tokens << std::endl;
}

9

हाल ही में मुझे एक ऊंट-आवरण शब्द को सब-पासवर्ड में विभाजित करना पड़ा। कोई सीमांकक नहीं हैं, सिर्फ ऊपरी अक्षर हैं।

#include <string>
#include <list>
#include <locale> // std::isupper

template<class String>
const std::list<String> split_camel_case_string(const String &s)
{
    std::list<String> R;
    String w;

    for (String::const_iterator i = s.begin(); i < s.end(); ++i) {  {
        if (std::isupper(*i)) {
            if (w.length()) {
                R.push_back(w);
                w.clear();
            }
        }
        w += *i;
    }

    if (w.length())
        R.push_back(w);
    return R;
}

उदाहरण के लिए, यह "AQueryTrades" को "A", "क्वेरी" और "ट्रेड्स" में विभाजित करता है। फ़ंक्शन संकीर्ण और विस्तृत स्ट्रिंग्स के साथ काम करता है। क्योंकि यह वर्तमान लोकेल का सम्मान करता है, यह "RaumfahrtwberwachungsVerordnung" को "Raumfahrt", "wberwachungs" और "Verordnung" में विभाजित करता है।

नोट std::upperवास्तव में फ़ंक्शन टेम्पलेट तर्क के रूप में पारित किया जाना चाहिए। फिर इस फ़ंक्शन से अधिक सामान्यीकृत सीमांकक की तरह विभाजित हो सकता है ",", ";"या " "भी।


2
इसमें 2 संशोधन हुए हैं। यह अच्छा है। ऐसा लगता है जैसे मेरी अंग्रेजी में "जर्मन" का बहुत कुछ था। हालांकि, संशोधनवादी ने दो छोटे कीड़े तय नहीं किए शायद वे वैसे भी स्पष्ट थे: std::isupperतर्क के रूप में पारित किया जा सकता है, नहीं std::upper। दूसरा एक typenameसे पहले डाल दिया String::const_iterator
एंड्रियास स्पिंडलर

9
#include<iostream>
#include<string>
#include<sstream>
#include<vector>
using namespace std;

    vector<string> split(const string &s, char delim) {
        vector<string> elems;
        stringstream ss(s);
        string item;
        while (getline(ss, item, delim)) {
            elems.push_back(item);
        }
        return elems;
    }

int main() {

        vector<string> x = split("thi is an sample test",' ');
        unsigned int i;
        for(i=0;i<x.size();i++)
            cout<<i<<":"<<x[i]<<endl;
        return 0;
}

9

का उपयोग कर std::string_viewऔर एरिक Niebler range-v3पुस्तकालय:

https://wandbox.org/permlink/kW5lwRCL1pxjp2pW

#include <iostream>
#include <string>
#include <string_view>
#include "range/v3/view.hpp"
#include "range/v3/algorithm.hpp"

int main() {
    std::string s = "Somewhere down the range v3 library";
    ranges::for_each(s  
        |   ranges::view::split(' ')
        |   ranges::view::transform([](auto &&sub) {
                return std::string_view(&*sub.begin(), ranges::distance(sub));
            }),
        [](auto s) {std::cout << "Substring: " << s << "\n";}
    );
}

एल्गोरिथ्म के forबजाय रेंज लूप का उपयोग करके ranges::for_each:

#include <iostream>
#include <string>
#include <string_view>
#include "range/v3/view.hpp"

int main()
{
    std::string str = "Somewhere down the range v3 library";
    for (auto s : str | ranges::view::split(' ')
                      | ranges::view::transform([](auto&& sub) { return std::string_view(&*sub.begin(), ranges::distance(sub)); }
                      ))
    {
        std::cout << "Substring: " << s << "\n";
    }
}

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