නූලක වචන ගැන නැවත කියන්නේ කෙසේද?


2991

මම උත්සාහ කරන්නේ නූලක වචන නැවත කියවීමටයි.

නූල සුදු අවකාශයෙන් වෙන් කරන ලද වචන වලින් සමන්විත යැයි උපකල්පනය කළ හැකිය.

මම සී සංගීත කාර්යයන් හෝ ඒ ආකාරයේ චරිත හැසිරවීම / ප්‍රවේශය ගැන උනන්දු නොවන බව සලකන්න. එසේම, කරුණාකර ඔබේ පිළිතුරේ කාර්යක්ෂමතාවයට වඩා අලංකාරයට ප්‍රමුඛත්වය දෙන්න.

මට දැන් ඇති හොඳම විසඳුම නම්:

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

මෙය කිරීමට වඩාත් අලංකාර ක්‍රමයක් තිබේද?


619
මචන් ... අලංකාරය යනු මගේ පොතේ "කාර්යක්ෂමතාව-පෙනුම-ලස්සන" යැයි කීමට මනස්කාන්ත ක්‍රමයකි. අච්චුවක් තුළ අඩංගු නොවන නිසා කිසිවක් ඉටු කිරීම සඳහා සී කාර්යයන් සහ ඉක්මන් ක්‍රම භාවිතා කිරීමෙන් පසුබට නොවන්න;)

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

22
D එඩ්වාඩෝ: එයත් වැරදියි ... ඔබ වෙනත් අගයක් ප්‍රවාහනය කිරීමට උත්සාහ කිරීම සහ එම අගය භාවිතා කිරීම අතර නිකුතුව පරීක්ෂා කළ යුතුය, එනම්string sub; while (iss >> sub) cout << "Substring: " << sub << '\n';
ටෝනි ඩෙල්රෝයි

9
පෙරනිමියෙන් මෙය කිරීමට C ++ හි විවිධ විකල්ප: cplusplus.com/faq/afteences/strings/split
hB0

14
ලස්සන කාර්යක්ෂමතාවයට වඩා අලංකාරයට වැඩි යමක් ඇත. අලංකාර ගුණාංග අතර අඩු රේඛා ගණන සහ ඉහළ නිරවද්‍යතාව ඇතුළත් වේ. IMHO Elegance යනු කාර්යක්ෂමතාව සඳහා වන ප්‍රොක්සියක් නොව නඩත්තු කිරීමේ හැකියාවයි.
මතෙ

Answers:


1371

එය වටින දෙය සඳහා, සම්මත පුස්තකාල පහසුකම් මත පමණක් රඳා පවතින ආදාන නූලකින් ටෝකන ලබා ගැනීමට තවත් ක්‍රමයක් මෙන්න. එය STL හි සැලසුම පිටුපස ඇති බලය හා අලංකාරය පිළිබඳ උදාහරණයකි.

#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
On ජොනතන්: case n මෙම නඩුවේ පරිසීමකය නොවේ, එය කෝට් කිරීමට ප්‍රතිදානය කිරීම සඳහා වන පරිසීමකයයි.
හූ

772
මෙය වෙනත් විසඳුමක් නොගන්නා බැවින් මෙය දුර්වල විසඳුමකි, එබැවින් පරිමාණය කළ නොහැකි සහ නඩත්තු කළ නොහැකි ය.
හෙලෝ වර්ල්ඩ්

37
ඇත්ත වශයෙන්ම, මෙය වෙනත් පරිසීමකයන් සමඟ හොඳින් ක්‍රියා කළ හැකිය (සමහරක් කිරීම තරමක් කැත වුවත්). ඔබ අපේක්ෂිත පරිසීමකයන් සුදු අවකාශය ලෙස වර්ගීකරණය කරන ctype පැතිකඩක් සාදයි, එම මුහුණත අඩංගු ස්ථානයක් සාදන්න, ඉන්පසු නූල් උකහා ගැනීමට පෙර එම ප්‍රදේශය සමඟ නූල් ප්‍රවාහය යොදන්න.
ජෙරී කොෆින්

53
Ind කින්ඩර්චොකලට් " නූල සුදු අවකාශයෙන් වෙන් කරන ලද වචන වලින් සමන්විත යැයි උපකල්පනය කළ හැකිය" - හ්ම්, ප්‍රශ්නයේ ගැටලුවට දුර්වල විසඳුමක් ලෙස නොපෙනේ. "පරිමාණය කළ නොහැකි සහ නඩත්තු කළ නොහැකි" - හාහ්, ලස්සන එකක්.
ක්‍රිස්ටියන් රාවු

2426

මම මෙය පරිසීමකය මගින් නූල් බෙදීමට භාවිතා කරමි. පළමුවැන්න ප්‍රති results ල කලින් සාදන ලද දෛශිකයකට දමයි, දෙවැන්න නව දෛශිකයක් ලබා දෙයි.

#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
ඩෙලිම් හි අක්ෂර දෙකක් අඩංගු වන්නේ ->කෙසේද?
herohuyongtao

7
@herohuyongtao, මෙම විසඳුම ක්‍රියාත්මක වන්නේ තනි වර්‍ග පරිසීමක සඳහා පමණි.
ඉවාන් ටෙරාන්

4
@ ජේශ්වන්ත් කුමාර්එන්කේ, එය අවශ්‍ය නොවේ, නමුත් ප්‍රති result ලය කෙලින්ම මෙවැනි ශ්‍රිතයකට යොමු කිරීම වැනි දේ කිරීමට එය ඔබට ඉඩ සලසයි: ඔබ කැමති නම් f(split(s, d, v))කලින් වෙන් කළ ප්‍රතිලාභයක් තිබියදීත් vector.
ඉවාන් ටෙරාන්

8
Caveat: split ("one: two :: three", ':') සහ split ("one: two :: three:", ':') එකම අගය ලබා දෙයි.
dshin

835

Boost භාවිතා කළ හැකි විසඳුමක් විය හැක්කේ:

#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
දැනටමත් තල්ලුවක් නොමැති අය සඳහා ... bcp මේ සඳහා ලිපිගොනු 1,000 කට වඩා පිටපත් කරයි :)
රෝමන් ස්ටාර්කොව්

12
අවවාදයයි, හිස් නූලක් ("") ලබා දුන් විට, මෙම ක්‍රමය මඟින් දෛශිකය නැවත ලබා දෙයි. එබැවින් බෙදීමට පෙර "if (! String_to_split.empty ())" එකතු කරන්න.
Offirmo

29
An කාවැද්දූ සංවර්ධකයින් සියල්ලම තල්ලුව භාවිතා නොකරයි.
ACK_stoverflow

31
අතිරේකයක් ලෙස: මම තල්ලුව භාවිතා කළ යුත්තේ මා හට අවශ්‍ය විටෙක පමණි, සාමාන්‍යයෙන් මම කැමති මගේම පුස්තකාල පුස්තකාලයට තනිවම හා අතේ ගෙන යා හැකි වන අතර එමඟින් කුඩා නිශ්චිත නිශ්චිත කේතයක් ලබා ගත හැකි වන අතර එමඟින් යම් ඉලක්කයක් සපුරා ගත හැකිය. ඒ ආකාරයෙන් කේතය පොදු නොවන, ක්‍රියාකාරී, සුළු හා අතේ ගෙන යා හැකි ය. බූස්ටයට එහි ස්ථානයක් ඇත, නමුත් මම යෝජනා කරන්නේ එය ටෝකන නූල් සඳහා තරමක් අධික ලෙස මරා දැමිය යුතු බවයි: පින්තූරයක් එල්ලීම සඳහා බිත්තියට නව නියපොත්තක් ලබා ගැනීම සඳහා ඔබේ මුළු නිවසම ඉංජිනේරු ආයතනයකට ප්‍රවාහනය නොකරනු ඇත .... ඔවුන් එය කළ හැකිය අතිශයින්ම හොඳයි, නමුත් වාසි අවාසි වලට වඩා බොහෝ සෙයින් වැඩි ය.
GMasucci

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

13
ඔබ ද ඔබ භාවිතා නම්, අනෙක් ක්රමයන්හි මත බෙදී හැකි getlineතුළ whileකොමා, භාවිතය මගින් බිඳීගිය තත්ත්වය උදා while(getline(ss, buff, ',')).
අලි

182

කේත ප්‍රමාණය සඳහා සියලු කාර්යක්‍ෂමතාවයන් කැපකිරීමට සුදුසු නැති අය සහ “කාර්යක්ෂමතාව” එක්තරා ආකාරයක අලංකාරයක් ලෙස දැකීමට නම්, පහත සඳහන් දෑ මිහිරි ස්ථානයකට පැමිණිය යුතුය (තවද අච්චු බහාලුම් පන්තිය අතිවිශිෂ්ට අලංකාර එකතු කිරීමක් යැයි මම සිතමි.):

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<> access ජු ප්‍රවේශය අවශ්‍ය නොවන වන අතර, ඔබට ඔබේම පන්ති පන්තියක් නිර්මාණය කර std::list<subString>කොතැනද වැනි දෙයක් භාවිතා කළ හැකියsubString කර ඇදහිය නොහැකි වේගයට පිටපත් නොකරන වැඩිවේ.

එය මෙම පිටුවේ වේගවත්ම ටෝකනකරණය මෙන් දෙගුණයකටත් වඩා වේගවත් වන අතර අනෙක් ඒවාට වඩා 5 ගුණයකින් වේගවත් වේ. පරිපූර්ණ පරාමිති වර්ග සමඟ අමතර වේග වැඩි කිරීම සඳහා ඔබට සියලු නූල් සහ ලැයිස්තු පිටපත් ඉවත් කළ හැකිය.

ඊට අමතරව එය (අතිශයින්ම අකාර්යක්ෂම) ප්‍රති result ල ලබා නොදෙන අතර එය ටෝකන යොමු කිරීමක් ලෙස සම්මත කරයි, එමඟින් ඔබ කැමති නම් බහු ඇමතුම් භාවිතා කරමින් ටෝකන සෑදීමටද ඉඩ සලසයි.

අවසාන විකල්ප පරාමිතිය හරහා ප්‍රති results ල වලින් හිස් ටෝකන කපා දැමිය යුතුද යන්න නියම කිරීමට එය ඔබට ඉඩ දෙයි.

එයට අවශ්‍ය වන්නේ std::string... ඉතිරිය අත්‍යවශ්‍ය නොවේ. එය ධාරා හෝ බූස්ට් පුස්තකාලය භාවිතා නොකරයි, නමුත් මෙම විදේශීය වර්ග සමහරක් ස්වභාවිකව පිළිගැනීමට තරම් නම්‍යශීලී වේ.


5
මම මේ සඳහා තරමක් රසිකයෙක්, නමුත් g ++ (සහ බොහෝ විට හොඳ පුහුණුවීම් සඳහා) මෙය භාවිතා කරන ඕනෑම කෙනෙකුට typedef ContainerT Base; typedef typename Base::value_type ValueType; typedef typename ValueType::size_type SizeType; යතුරු ලියනය සහ යතුරු ලියන අවශ්‍ය වේ: ඉන්පසු අගය_ වර්ගය සහ ප්‍රමාණ_ වර්ග ඒ අනුව ආදේශ කිරීම.
aws

11
අච්චු දේවල් සහ පළමු විවරණය මුළුමනින්ම විදේශීය වන අප සඳහා, අවශ්‍ය ඇතුළත් කිරීම් සහිත සෙන්ටිමීටර භාවිතා කිරීමේ නිදසුනක් සුන්දර වනු ඇත.
වෙස් මිලර්

3
හොඳයි, මම ඒක හොයාගත්තා. මම ටෝකනයිස් () හි ක්‍රියාකාරී ශරීරය තුළ ඇව්ස්ගේ අදහස් දැක්වීමේ සිට සී ++ රේඛා තැබුවෙමි, පසුව ටෝකන.පුෂ්_බැක් () රේඛා සංස්කරණය කර බහාලුම් ටී :: අගය_ වර්ගය අගය ටයිප් ලෙස වෙනස් කර (බහාලුම් :: අගය_ වර්ගය :: ප්‍රමාණය_ වර්ගය) ( තරම වර්ගය). G ++ බිටු සවි කර ඇත. එය ටෝකනයිස් ලෙස ආයාචනා කරන්න (some_string, some_vector);
වෙස් මිලර්

2
නියැදි දත්ත මත කාර්ය සාධන පරීක්ෂණ කිහිපයක් ක්‍රියාත්මක කිරීමට අමතරව, මූලික වශයෙන් මම එය හැකි තරම් උපදෙස් දක්වා අඩු කර ඇති අතර වෙනත් නූල්වල ඕෆ්සෙට් / දිග පමණක් සඳහන් කරන උපස්ථර පංතියක් භාවිතා කිරීමෙන් සක්‍රීය කළ හැකි මතක පිටපත් ද අඩුය. (මම මගේම දෑ පෙරළා ගත්තෙමි, නමුත් තවත් ක්‍රියාත්මක කිරීම් කිහිපයක් තිබේ). අවාසනාවකට මෙය වැඩිදියුණු කිරීම සඳහා තවත් බොහෝ දේ කළ නොහැකි නමුත් වර්ධක වැඩිවීම් සිදුවිය.
මාරියස්

3
කවදාද යන්න සඳහා නිවැරදි ප්‍රතිදානය එයයි trimEmpty = true. "abo"මෙම පිළිතුරෙහි පරිසීමකයක් නොවන බව මතක තබා ගන්න , නමුත් පරිසීමක අක්ෂර ලැයිස්තුව. තනි පරිසීමක අක්ෂර මාලාවක් ගැනීම සඳහා එය වෙනස් කිරීම සරල ය (මම සිතන්නේ str.find_first_ofවෙනස් විය යුතුය str.find_first, නමුත් මට වැරදියි ... පරීක්ෂා කළ නොහැක)
මාරියස්

159

මෙන්න තවත් විසඳුමක්. එය සංයුක්ත හා සාධාරණ ලෙස කාර්යක්ෂම වේ:

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

10
පළමු අනුවාදය සරල වන අතර කාර්යය මනාව ඉටු කරයි. මා කළ එකම වෙනස වන්නේ පරාමිතියක් ලෙස සම්මත කරනවා වෙනුවට ප්‍රති result ලය කෙලින්ම ලබා දීමයි.
gregschlom

2
ප්‍රතිදානය කාර්යක්ෂමතාව සඳහා පරාමිතියක් ලෙස සම්මත වේ. ප්‍රති result ලය ආපසු ලබා දුන්නේ නම් එයට දෛශිකයේ පිටපතක් හෝ ගොඩවල් වෙන් කිරීමක් අවශ්‍ය වේ.
ඇලෙක් තෝමස්

2
ඉහත මගේ අදහස් දැක්වීමට සුළු එකතු කිරීමක්: C ++ 11 චලනය අර්ථ නිරූපණයන් භාවිතා කරන්නේ නම් මෙම ශ්‍රිතයට දෛශිකයක් නොමැතිව දෛශිකය ආපසු ලබා දිය හැකිය.
ඇලෙක් තෝමස්

7
LeAlecThomas: C ++ 11 ට පෙර පවා, බොහෝ සම්පාදකයින් NRVO හරහා ආපසු පිටපත ප්‍රශස්තිකරණය නොකරන්නේද? (කෙසේ වෙතත් +1; ඉතා සංක්ෂිප්තයි)
මාර්සෙලෝ කැන්ටොස්

11
සියලු පිළිතුරු අතරින් මෙය වඩාත් සිත්ගන්නාසුළු හා නම්‍යශීලී එකක් ලෙස පෙනේ. අඩු පැහැදිලි විසඳුමක් වුවද, පරිසීමකය සමඟ ගෙට්ලයින් සමඟ එක්ව. C ++ 11 ප්‍රමිතියට මේ සඳහා කිසිවක් නොමැතිද? C ++ 11 මේ දිනවල පන්ච් කාඩ් සඳහා සහය දක්වයිද?
ස්පේසන් ජැසෙට්

125

නූලක් හරහා නැවත යෙදීමට මෙය මගේ ප්‍රියතම ක්‍රමයයි. ඔබට වචනයකට අවශ්‍ය ඕනෑම දෙයක් කළ හැකිය.

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 ++ මගේ ශක්තිමත් කාරණය නොවේ. නමුත් සෑම වචනයකම සෑම අක්‍ෂරයක් හරහාම ලූපයක් ලබා ගැනීම සඳහා අභ්‍යන්තර පුඩුවක් එක් කිරීම අපහසු නොවනු ඇතැයි මම සිතමි. නමුත් දැන් මම විශ්වාස කරන්නේ වත්මන් ලූපය වචන වෙන් කිරීම සඳහා වන අවකාශයන් මත රඳා පවතින බවයි. සෑම අවකාශයක් අතර ඇත්තේ එක අක්‍ෂරයක් පමණක් බව ඔබ නොදන්නේ නම්, ඔබට "වචනය"
වර්‍ගයකට දැමිය

11
ඔබ වචනය වර්‍ගයක් ලෙස ප්‍රකාශ කළහොත් එය සුදු පැහැති නොවන සෑම අක්ෂරයකටම වඩා වෙනස් වේ. එය උත්සාහ කිරීමට තරම් සරල ය:stringstream ss("Hello World, this is*@#&$(@ a string"); char c; while(ss >> c) cout << c;
වේන් වර්නර්

79

මෙය Stack Overflow ප්‍රශ්නයට සමානය . 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

මම පහත සඳහන් දේට කැමතියි, මන්ද එය ප්‍රති results ල දෛශිකයක් තුළට දමයි, නූලක් ඩෙලිම් ලෙස සහාය වන අතර හිස් අගයන් තබා ගැනීම පාලනය කරයි. නමුත්, එය එතරම් හොඳ පෙනුමක් නැත.

#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()කළ හැකිය, නැතහොත් ඔබට ඔබේම දෑ ලිවිය හැකිය. ඉක්මන් ගූගල් සෙවුමකින් පසුව මා සොයාගත් කේත නියැදියක් මෙන්න ( "STL string split" ):

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හැඳින්වූ iterator එකක් ක්‍රියාත්මක නොකිරීම හෝ <<ක්‍රියාකරු අධික ලෙස පැටවීම නිසා එය නරක කේතයක් යැයි අදහස් නොකෙරේ. මම නිතරම C ශ්‍රිත භාවිතා කරමි. උදාහරණයක් ලෙස, printfසහ scanfදෙකම වේගවත් වන std::cinඅතර std::cout(සැලකිය යුතු ලෙස) ,.fopen කාරක රීති වැඩි ගොඩක් ද්විමය වර්ග සඳහා හිතකාමී වන අතර, ඔවුන් ද කුඩා EXEs නිෂ්පාදනය කිරීමට නැඹුරු.

මෙම "කාර්යසාධනය පිළිබඳ අලංකාරය" ගනුදෙනුවට විකුණන්න එපා .


මම සී නූල් ක්‍රියාකාරිත්වය ගැන දන්නා අතර කාර්ය සාධන ගැටළු ද දනිමි (මේ දෙකම මගේ ප්‍රශ්නයේ සටහන් කර ඇත). කෙසේ වෙතත්, මෙම විශේෂිත ප්රශ්නය සඳහා, මම අලංකාර C ++ විසඳුමක් සොයමි.
අශ්වින් නන්ජප්පා

11
@ නෙල්සන් ලාකෙට්: මට අනුමාන කිරීමට ඉඩ දෙන්න: ස්ට්රෝටොක් නැවත නොපැමිණෙන නිසා?
paercebal

41
El නෙල්සන් කිසි විටෙකත් string.c_str () strtok වෙත නොයන්න! strtok විසින් ආදාන නූල ඉවත දමයි (එක් එක් ෆවුඩ්න් පරිසීමකය ප්‍රතිස්ථාපනය කිරීම සඳහා '\ 0' අක්ෂර ඇතුල් කරයි) සහ c_str () වෙනස් කළ නොහැකි නූලක් ලබා දෙයි.
ඉවාන් ටෙරාන්

3
@ නෙල්සන්: ඔබේ අන්තිම අදහස් දැක්වීමේදී එම අරාව විශාල ප්‍රමාණයේ () + 1 විය යුතුය. නමුත් "සෞන්දර්යාත්මක" හේතූන් මත සී ක්‍රියාකාරකම් වළක්වා ගැනීම මෝඩකමක් බව ඔබේ නිබන්ධනය සමඟ මම එකඟ වෙමි.
j_random_hacker

2
ul පෝල්ම්: නැත, සී ++ ධාරාවන්හි මන්දගාමී බව ඇති වන්නේ මුහුණුවරෙනි. සමමුහුර්තකරණය අක්‍රිය වූ විට පවා ඒවා 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 Tulip

1
AndXanderTulip, ඔබට වඩාත් tive ලදායී විය හැකි අතර කෙසේද හෝ ඇයි යන්න පැහැදිලි කළ හැකිද?
මාකෝ එම්.

3
AndXanderTulip: මම හිතන්නේ ඔබ එය යොමු කරන්නේ දෛශිකය අගය අනුව ආපසු ලබා දීමටයි. ප්‍රතිලාභ-අගය-ප්‍රශස්තකරණය (RVO, google it) මේ ගැන සැලකිලිමත් විය යුතුය. C ++ 11 හි ඔබට චලනය යොමු කිරීමෙන් ආපසු යා හැකිය.
ජෝශප් ගාර්වින්

3
මෙය සැබවින්ම තවදුරටත් ප්‍රශස්තිකරණය කළ හැකිය: .push_back (str.substr (...)) වෙනුවට කෙනෙකුට .emplace_back (str, start, pos - start) භාවිතා කළ හැකිය. මේ ආකාරයට නූල් වස්තුව කන්ටේනරය තුළ ඉදිකර ඇති අතර එමඟින් අපි .substr ශ්‍රිතය මඟින් සිදුකරන චලනය වන + වෙනත් ෂෙනානිගන් වලින් වැළකී සිටිමු.
මිහයි බිනොග්

ඔව්. හොඳ අදහස. මා මෙය ලියන විට VS10 ට emplace_back සහාය නොතිබුණි. මම මගේ පිළිතුර යාවත්කාලීන කරමි. ස්තූතියි
මාකෝ එම්.

37

මෙම ගැටලුවට මට පේළි 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;
  }
}

නූල් දෛශිකයක් සමඟ එය භාවිතා කිරීම සඳහා (සංස්කරණය කරන්න: STL පන්ති උරුම කර නොගන්නා ලෙස යමෙකු පෙන්වා දුන් බැවින් ... hrmf;)):

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

සටහන, ඔබේ සම්පාදකයා මත පදනම්ව, තන්තු තර්කය යොමු කිරීම මඟින් ඔබට අවශ්‍ය විය හැකිය.


මෙය මගේ ප්‍රියතම පිළිතුර වනු ඇත, නමුත් std :: regex GCC 4.8 හි කැඩී ඇත. ඔවුන් එය GCC 4.9 හි නිවැරදිව ක්‍රියාත්මක කළ බව පැවසූහ. මම තවමත් ඔබට මගේ +1 ලබා දෙන්නෙමි
mchiasson

1
සුළු වෙනස්කම් සහිතව මෙය මගේ ප්‍රියතමය: ඔබ පැවසූ පරිදි දෛශිකය නැවත යොමු කරන ලද අතර, යොමු කිරීම් මගින් සම්මත කරන ලද “str” සහ “regex” යන තර්ක ද ඇත. thx.
QuantumKarl

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
strtokසී සම්මත පුස්තකාලයෙන් මිස සී ++ වලින් නොවේ. බහු තෙරපුම් වැඩසටහන් වල භාවිතා කිරීම ආරක්ෂිත නොවේ. එය ආදාන නූල වෙනස් කරයි.
කෙවින් පැන්කෝ

13
පළමු ඇමතුමේ සිට චාර් පොයින්ටරය ස්ථිතික විචල්‍යයක ගබඩා කර ඇති නිසා, පසුව එන ඇමතුම් වලදී NULL සම්මත වූ විට, එය භාවිතා කළ යුතු දර්ශකය මතක තබා ගනී. strtokතවත් ත්‍රෙඩ් එකක් තවමත් සැකසෙන විට දෙවන නූල් ඇමතුමක් ලබා දෙන්නේ නම් , මෙම වර්‍ග දර්ශකය නැවත ලියනු ලබන අතර, නූල් දෙකම වැරදි ප්‍රති .ල ලබා දෙනු ඇත. mkssoftware.com/docs/man3/strtok.3.asp
කෙවින් පැන්කෝ

1
strtok ට පෙර සඳහන් කළ පරිදි අනාරක්ෂිත වන අතර C strtok_r හි පවා භාවිතා කිරීම රෙකමදාරු කරනු ලැබේ
systemsfault

4
ඔබ ප්‍රවේශ විය හැකි කේත කොටසක සිටී නම් strtok_r භාවිතා කළ හැකිය. “රේඛීය ශබ්දය” නොවන ඉහත සියල්ලටම ඇති එකම විසඳුම මෙය වන අතර, හරියටම c ++ හි වැරැද්ද කුමක්ද යන්න පිළිබඳ සාක්ෂියකි
එරික් ඇරොනෙස්ටි

යාවත්කාලීන කරන ලද බැවින් 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:");

ඉලක්කය වූයේ එය සී # බෙදීම් () ක්‍රමයට සමාන කිරීම ය, එහිදී නූලක් බෙදීම පහසුය:

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

මෙන්න එය කළ හැකි තවත් ක්‍රමයක් ..

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

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", "විමසුම" සහ "වෙළඳ" ලෙස බෙදේ. ශ්‍රිතය පටු හා පුළුල් නූල් සමඟ ක්‍රියා කරයි. එය වර්තමාන පෙදෙසට ගරු කරන හෙයින් එය "රම්ෆහර්ටෙබර්වාචුංස් වර්ඩ්ඩ්න්ග්" "රම්ෆහර්ට්", "ඇබර්වාචුන්ග්ස්" සහ "වේරෝර්ඩ්නුං" ලෙස බෙදී යයි.

සටහන 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සහ එරික් නියෙබ්ලර්ගේ 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";
    }
}

යෙප්, පදනම් සඳහා පරාසය වඩා හොඳ පෙනුමක් - මම එකඟයි
Porsche9II
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.