c++ मैं स्ट्रिंग के शब्दों पर कैसे पुन: प्रयास करूं?




string split (24)

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

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

    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";,");

मैं एक स्ट्रिंग के शब्दों पर फिर से प्रयास करने की कोशिश कर रहा हूँ।

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

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

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

#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);
}

क्या ऐसा करने के लिए एक और शानदार तरीका है?


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

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आप एक से अधिक चरित्र पारित कर सकते हैं।


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;
}

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

#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,]+" जांचता है।

नोट, यदि आप string बजाय wstring को विभाजित करना चाहते हैं,

  • सभी std::regex को std::wregex
  • सभी sregex_token_iterator को wsregex_token_iterator

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


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

#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;
}

यह स्टैक ओवरफ़्लो प्रश्न के समान है I 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;
    }
}

नीचे दिया गया कोड strtok()स्ट्रिंग को टोकन में विभाजित करने और वेक्टर में टोकन स्टोर करने के लिए उपयोग करता है।

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>

using namespace std;


char one_line_string[] = "hello hi how are you nice weather we are having ok then bye";
char seps[]   = " ,\t\n";
char *token;



int main()
{
   vector<string> vec_String_Lines;
   token = strtok( one_line_string, seps );

   cout << "Extracting and storing data in a vector..\n\n\n";

   while( token != NULL )
   {
      vec_String_Lines.push_back(token);
      token = strtok( NULL, seps );
   }
     cout << "Displaying end result in vector line storage..\n\n";

    for ( int i = 0; i < vec_String_Lines.size(); ++i)
    cout << vec_String_Lines[i] << "\n";
    cout << "\n\n\n";


return 0;
}

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

#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) को विभाजित करने के लिए किया जा सकता है।

विवरण के लिए documentation देखें।


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

#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;
}

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


Boost जाओ ! : -)

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

using namespace std;
using namespace boost;

int main(int argc, char**argv) {
    typedef vector < string > list_type;

    list_type list;
    string line;

    line = "Somewhere down the road";
    split(list, line, is_any_of(" "));

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

    return 0;
}

यह उदाहरण आउटपुट देता है -

Somewhere
down
the
road

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

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

#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;
}

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

मुझे यकीन है कि ऐसे सुधार हैं जो इसके लालित्य को और भी बेहतर बनाने के लिए किए जा सकते हैं और कृपया हर तरह से करें

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:");

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

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

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

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


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

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

istringstream iss(line, istringstream::in);

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

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;
}

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

हालांकि, आप या तो std::string::c_str() सदस्य का उपयोग कर सी के strtok() फ़ंक्शन का उपयोग कर सकते हैं, या आप अपना खुद का लिख ​​सकते हैं। एक त्वरित 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

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

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

"प्रदर्शन पर लालित्य" सौदा पर बेचा मत जाओ।


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

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

template<typename Out>
void split(const std::string &s, char delim, Out result) {
    std::stringstream ss(s);
    std::string item;
    while (std::getline(ss, 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", ':');

इसे करने का एक और तरीका यहाँ है ..

void split_string(string text,vector<string>& words)
{
  int i=0;
  char ch;
  string word;

  while(ch=text[i++])
  {
    if (isspace(ch))
    {
      if (!word.empty())
      {
        words.push_back(word);
      }
      word = "";
    }
    else
    {
      word += ch;
    }
  }
  if (!word.empty())
  {
    words.push_back(word);
  }
}

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

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;
}

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

#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() बहुत अच्छा काम करता है।


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

#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
}

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

#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>{}};

यदि आपको गैर-स्पेस प्रतीकों द्वारा स्ट्रिंग को पार्स करने की आवश्यकता है तो स्ट्रिंगस्ट्रीम सुविधाजनक हो सकता है:

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, ';')

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

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<> तुलना में तेज़ तरीका है vector<> जब प्रत्यक्ष पहुंच की आवश्यकता नहीं होती है, और आप भी बना सकते हैं अपनी खुद की स्ट्रिंग क्लास और std::list<subString> जैसे कुछ का उपयोग करें जहां subString अविश्वसनीय गति बढ़ने के लिए कोई प्रतिलिपि नहीं करता है।

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

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

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

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





split