c++ - الطريقة الأكثر أناقة لتكرار كلمات سلسلة


ما هي الطريقة الأكثر أناقة لتكرار كلمات سلسلة؟ يمكن افتراض أن السلسلة تتكون من كلمات مفصولة بمسافة بيضاء.

لاحظ أن أنا لست مهتما في وظائف سلسلة 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);
}


Answers



ما هو يستحق، وهنا طريقة أخرى لاستخراج الرموز من سلسلة المدخلات، والاعتماد فقط على مرافق المكتبة القياسية. إنه مثال على القوة والأناقة الكامنة وراء تصميم المحكمة الخاصة بلبنان.

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



يمكنني استخدام هذا لتقسيم سلسلة بواسطة محدد. الأول يضع النتائج في ناقلات ما قبل بناؤها، والثانية بإرجاع ناقلات جديدة.

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



قد يكون الحل المحتمل باستخدام بوست:

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

قد يكون هذا النهج أسرع من نهج stringstream . وبما أن هذا هو وظيفة قالب عام يمكن استخدامه لتقسيم أنواع أخرى من السلاسل (وشار، الخ أو أوتف-8) باستخدام جميع أنواع المحددات.

راجع الوثائق للحصول على التفاصيل.




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

using namespace std;

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

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

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



بالنسبة لأولئك الذين لا يجلسون جيدا للتضحية جميع الكفاءة لحجم رمز ونرى "كفاءة" كنوع من الأناقة، يجب أن يلي التالية بقعة حلوة (وأعتقد أن الطبقة حاوية قالب هو إضافة أنيقة بذهول).:

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 ... والباقي اختيارية. فإنه لا يستخدم تيارات أو مكتبة دفعة، ولكن مرنة بما فيه الكفاية لتكون قادرة على قبول بعض من هذه الأنواع الأجنبية بشكل طبيعي.




وهنا حل آخر. انها المدمجة وفعالة إلى حد معقول:

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

ويمكن بسهولة أن يكون تمبلاتيسد للتعامل مع سلسلة فاصل، سلاسل واسعة، الخ.

لاحظ أن تقسيم "" النتائج في سلسلة واحدة فارغة وتقسيم "," (أي سيب) النتائج في سلسلتين فارغة.

ويمكن أيضا توسيعها بسهولة لتخطي الرموز الفارغة:

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



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

istringstream iss(line, istringstream::in);

while( iss >> word )     
{

...

}

هذا هو طريقتي المفضلة لتكرار من خلال سلسلة. يمكنك أن تفعل ما تريد لكل كلمة.




هذا يشبه سؤال ستاك أوفيرفلو كيف يمكنني توصيف سلسلة في 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;
    }
}



أنا أحب ما يلي لأنه يضع النتائج في ناقلات، ويدعم سلسلة كما ديليم ويعطي السيطرة على حفظ القيم الفارغة. ولكن، فإنه لا تبدو جيدة كما.

#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() يعمل كبيرة.




إن المحكمة الخاصة بلبنان لا تملك مثل هذه الطريقة المتاحة بالفعل.

ومع ذلك، يمكنك إما استخدام وظيفة سترتوك C باستخدام عضو str.c_str ()، أو يمكنك كتابة الخاصة بك. إليك نموذج شفرة تم العثور عليه بعد بحث غوغل السريع ("تقسيم سلسلة ستل"):

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

إذا كان لديك أسئلة حول نموذج التعليمات البرمجية، ترك تعليق وسوف أشرح.

وفقط لأنها لا تنفذ تيبيديف يسمى المكرر أو الزائد << المشغل لا يعني أنه هو رمز سيئة. يمكنني استخدام وظائف C بشكل متكرر جدا. على سبيل المثال، برينتف و سكانف كلاهما أسرع ثم سين و كوت (إلى حد كبير)، وبناء فوبين هو أكثر ودية بكثير لأنواع ثنائية، وأنها تميل أيضا إلى إنتاج إيكس أصغر.

لا تباع على هذه الصفقة "الأناقة على الأداء".




هنا هي وظيفة الانقسام التي:

  • هو عام
  • يستخدم 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";,");



لدي حل 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;

ثم بدلا من الطباعة يمكنك وضعه في ناقلات.




طريقة أخرى مرنة وسريعة

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

لاستخدامها مع متجه من سلاسل (تحرير: منذ أشار شخص إلى عدم وراثة الطبقات ستل ... هرمف؛)):

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

محدود بالخيال؛)




إذا كنت ترغب في استخدام دفعة، ولكن تريد استخدام سلسلة كاملة كمحدد (بدلا من أحرف واحدة كما هو الحال في معظم الحلول المقترحة سابقا)، يمكنك استخدام 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;
}



وهنا حل بسيط يستخدم فقط مكتبة المعتاد المنطقي القياسية

#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

ملاحظة، قد تحتاج أيضا إلى اتخاذ وسيطة سلسلة بالرجوع، اعتمادا على مترجم.




باستخدام سترينغستريم كما لديك يعمل بشكل جيد تماما، والقيام بالضبط ما أردت. إذا كنت تبحث فقط عن طريقة مختلفة للقيام بهذه الأمور على الرغم من ذلك، يمكنك استخدام البحث / find_first_of و سوبسترينغ.

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



هناك وظيفة اسمه 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.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
}



حتى الآن استخدمت واحد في دفعة ، ولكن كنت بحاجة إلى شيء لا يعتمد على ذلك، لذلك جئت إلى هذا:

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 يمكنك تمرير أكثر من حرف واحد.




لقد توالت بلدي باستخدام سترتوك واستخدام دفعة لتقسيم سلسلة. أفضل طريقة لقد وجدت هو 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;
}

مجموعة الأدوات لديها مرونة أكثر بكثير من هذا المثال البسيط يظهر ولكن فائدة في تحليل سلسلة في عناصر مفيدة أمر لا يصدق.




يمكن أن تكون سلسلة سترينغستريم ملائمة إذا كنت بحاجة إلى تحليل السلسلة بواسطة رموز غير الفضاء:

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



قصيرة وأنيقة

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

يمكن استخدام أي سلسلة كمحدد، كما يمكن استخدامها مع البيانات الثنائية (ستد :: سلسلة يدعم البيانات الثنائية، بما في ذلك الخردة)

باستخدام:

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

انتاج:

this
is
!example!string



أنا جعلت هذا لأنني في حاجة إلى طريقة سهلة لتقسيم السلاسل و c-- سلاسل استنادا ... نأمل شخص آخر يمكن أن تجد أنه من المفيد أيضا. كما أنها لا تعتمد على الرموز ويمكنك استخدام الحقول كمحددات، وهو مفتاح آخر كنت بحاجة.

أنا متأكد من أن هناك تحسينات التي يمكن القيام بها لمواصلة تحسين أناقتها ويرجى القيام بكل الوسائل

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

سوف الإخراج:

هذه
هو
ل
مثال
سلسلة ج

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

آمل شخص آخر يمكن أن تجد هذه مفيدة ما أفعل.




ماذا عن هذا:

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



وإليك طريقة أخرى للقيام بذلك ..

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



أود أن استخدام الأساليب دفعة / التعابير المنطقية لهذه المهمة نظرا لأنها توفر أقصى قدر من المرونة لتحديد معايير تقسيم.

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



في الآونة الأخيرة لي لتقسيم كلمة فتش الإبل إلى subwords. لا توجد المحددات، مجرد أحرف العليا.

#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"، "سؤال" و "الصفقات". وتعمل وظيفة مع سلاسل ضيقة وواسعة. لأنها تحترم لغة الحالية فإنها تنقسم "RaumfahrtÜberwachungsVerordnung" إلى "Raumfahrt"، "Überwachungs" و "Verordnung".

ملاحظة std::upperيجب أن مرت حقا كوسيطة قالب وظيفة. ثم أكثر المعمم من هذه الوظيفة يمكن تقسيم في المحددات مثل ","، ";"أو " "أيضا.




يستخدم رمز أدناه 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<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;
}



أنا استخدم هذا مغفل لأننا وصلنا الفئة سلسلة لدينا "خاصة" (أي ليست المعيار):

void splitString(const String &s, const String &delim, std::vector<String> &result) {
    const int l = delim.length();
    int f = 0;
    int i = s.indexOf(delim,f);
    while (i>=0) {
        String token( i-f > 0 ? s.substring(f,i-f) : "");
        result.push_back(token);
        f=i+l;
        i = s.indexOf(delim,f);
    }
    String token = s.substring(f);
    result.push_back(token);
}