আমি স্ট্রিংয়ের শব্দগুলি দিয়ে কীভাবে পুনরাবৃত্তি করব?


2984

আমি একটি স্ট্রিং শব্দ উপর পুনরাবৃত্তি চেষ্টা করছি।

স্ট্রিংটি হোয়াইটস্পেস দ্বারা পৃথক শব্দের সমন্বয়ে গঠিত বলে ধরে নেওয়া যায়।

নোট করুন যে আমি সি স্ট্রিং ফাংশনগুলিতে বা এই জাতীয় চরিত্রের হেরফের / অ্যাক্সেসে আগ্রহী নই। এছাড়াও, দয়া করে আপনার উত্তরে দক্ষতার চেয়ে কমনীয়াকে প্রাধান্য দিন।

আমার কাছে এখন সেরা সমাধানটি হ'ল:

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

using namespace std;

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

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

এটি করার জন্য আরও কি মার্জিত উপায় আছে?


617
ডুড ... কমনীয়তা আমার বইতে "দক্ষতা-দেখতে-দেখতে সুন্দর" বলার অভিনব উপায়। কোনও কার্যকারিতা কেবলমাত্র কোনও টেম্পলেটের মধ্যে থাকা না

14
while (iss) { string subs; iss >> subs; cout << "Substring: " << sub << endl; }
পাইয়ন

21
@ এডুয়ার্ডো: এটিও ভুল ... আপনার অন্য মূল্য প্রবাহের চেষ্টা করার সময় এবং সেই মানটি ব্যবহার করার মধ্যে পরীক্ষা করা দরকার, যেমনstring sub; while (iss >> sub) cout << "Substring: " << sub << '\n';
টনি দেলরয়

9
সি ++ তে বিভিন্ন বিকল্প ডিফল্টরূপে এটি করতে: cplusplus.com/faq/sequens/strings/split
hB0

14
চমত্কার দক্ষতার চেয়ে আরও কমনীয়তা রয়েছে। মার্জিত বৈশিষ্ট্যগুলির মধ্যে কম লাইন গণনা এবং উচ্চ স্বীকৃতি। আইএমএইচও কমনীয়তা দক্ষতার জন্য নয় তবে রক্ষণাবেক্ষণের জন্য প্রক্সি।
ম্যাট

উত্তর:


1368

এটির মূল্য কী তা জন্য, কেবলমাত্র স্ট্যান্ডার্ড লাইব্রেরি সুবিধার উপর নির্ভর করে একটি ইনপুট স্ট্রিং থেকে টোকেন নিষ্কাশনের আরও একটি উপায়। এটি এসটিএল ডিজাইনের পিছনে শক্তি এবং কমনীয়তার উদাহরণ।

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

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

নিষ্ক্রিয় টোকেনগুলি আউটপুট স্ট্রিমে অনুলিপি করার পরিবর্তে, একই জেনেরিক copyঅ্যালগরিদম ব্যবহার করে কেউ সেগুলিকে একটি ধারক মধ্যে .োকাতে পারে।

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

... বা vectorসরাসরি তৈরি করুন :

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

164
এটির জন্য কোনও ডিলিমিটার নির্দিষ্ট করা সম্ভব? উদাহরণস্বরূপ কমাতে বিভক্তকরণের মতো?
l3dx

15
@ জোনাথন: case n এক্ষেত্রে ডিলিমিটার নয়, এটি আউটপুট আউটপুট দেওয়ার জন্য ডিলিমিনার।
হাই

772
এটি একটি দুর্বল সমাধান কারণ এটি অন্য কোনও সীমানা গ্রহণ করে না, অতএব স্কেলযোগ্য এবং সংরক্ষণযোগ্য নয়।
হ্যালো ওয়ার্ল্ড

37
প্রকৃতপক্ষে, এটি অন্যান্য সীমানা সরবরাহকারীদের সাথে ঠিক কাজ করতে পারে (যদিও কিছু করা কিছুটা কুৎসিত)। আপনি একটি সিটিপি ফ্যাক্ট তৈরি করেন যা পছন্দসই ডিলিমিটারগুলিকে হোয়াইটস্পেস হিসাবে শ্রেণিবদ্ধ করে, সেই ফ্যাক্ট যুক্ত একটি লোকেল তৈরি করে, তারপরে স্ট্রিংগুলি বের করার আগে সেই লোকেলের সাথে স্ট্রিংস্ট্রিমটি ইমবিউ করে।
জেরি কফিন

53
@ কিন্ডারকোলেট "এই স্ট্রিংটি হোয়াইটস্পেসের দ্বারা পৃথক শব্দের সমন্বয়ে গঠিত বলে ধরে নেওয়া যেতে পারে" - হুম, প্রশ্নের সমস্যার দুর্বল সমাধান বলে মনে হয় না। "স্কেলযোগ্য এবং সংরক্ষণযোগ্য নয়" - হাহ , দুর্দান্ত।
খ্রিস্টান রাউ

2425

আমি এটি একটি সীমানার দ্বারা স্ট্রিং বিভক্ত করতে ব্যবহার করি। প্রথমটি একটি প্রাক-নির্মিত ভেক্টরে ফলাফল রাখে, দ্বিতীয়টি একটি নতুন ভেক্টর প্রদান করে।

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

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

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

নোট করুন যে এই সমাধানটি খালি টোকেনগুলি এড়িয়ে যায় না, সুতরাং নিম্নলিখিত 4 টি আইটেম সন্ধান করবে, যার মধ্যে একটি শূন্য:

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

86
খালি টোকেন এড়িয়ে চলা এড়াতে, একটি empty()চেক করুন:if (!item.empty()) elems.push_back(item)
0x499602D2

11
কীভাবে ডিলিমের মধ্যে দুটি চর রয়েছে ->?
নায়কহিয়ংটাও

7
@ হ্যারোহ্যুংটাও, এই সমাধানটি কেবল একক চর ডিলিমেটারদের জন্য কাজ করে।
ইভান তিরান

4
@ যশওয়ানথ কুমারএনকে, এটি প্রয়োজনীয় নয়, তবে এটি আপনাকে এই জাতীয় কোনও কার্যক্রমে ফলাফলটি সরাসরি পাস করার মতো জিনিস করতে দেয়: আপনি যদি চান তবে f(split(s, d, v))পূর্ব-বরাদ্দের সুবিধাও রয়েছে vector
ইভান তেরান

8
গুহা: বিভক্ত ("এক: দুই :: তিন", ':') এবং বিভক্ত ("এক: দুই :: তিন:", ':') একই মান ফেরত দেয়।
dshin

834

বুস্ট ব্যবহার করে একটি সম্ভাব্য সমাধান হতে পারে:

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

এই পদ্ধতির পদ্ধতির চেয়ে আরও দ্রুত হতে পারে stringstream। এবং যেহেতু এটি জেনেরিক টেম্পলেট ফাংশন তাই এটি অন্যান্য ধরণের ডিলিমিটারগুলি ব্যবহার করে অন্যান্য ধরণের স্ট্রিং (ডাব্লুচার, ইত্যাদি বা ইউটিএফ -8) বিভক্ত করতে ব্যবহার করা যেতে পারে।

বিশদ জন্য ডকুমেন্টেশন দেখুন ।


35
গতি এখানে অপ্রাসঙ্গিক, কারণ এই উভয় ক্ষেত্রেই স্ট্রোটকের মতো ফাংশনটির চেয়ে অনেক ধীর।
টম

45
এবং যাঁদের ইতিমধ্যে উত্সাহ নেই তাদের জন্য ... বিসিপি এটির জন্য 1000 টিরও বেশি ফাইলের কপি করুন :)
রোমান স্টারকভ

12
সতর্কতা, যখন একটি খালি স্ট্রিং দেওয়া হয় (""), এই পদ্ধতিতে স্ট্রিং যুক্ত ভেক্টরকে ফিরিয়ে দেয়। সুতরাং বিভাজনের আগে একটি "if (! স্ট্রিং_টো_স্প্লিট.ইম্পটি ())" যুক্ত করুন।
অফারমো

29
@ ইয়ান এম্বেডেড বিকাশকারীরা সবাই বুস্ট ব্যবহার করছেন না।
ACK_stoverflow

31
সংযোজন হিসাবে: আমি কেবল তখনই বুস্ট ব্যবহার করি, সাধারণত আমি নিজের কোডের নিজস্ব লাইব্রেরিতে যুক্ত করতে পছন্দ করি যা একক এবং বহনযোগ্য যাতে আমি একটি নির্দিষ্ট নির্দিষ্ট কোডটি অর্জন করতে পারি, যা একটি নির্দিষ্ট লক্ষ্য অর্জন করে। এইভাবে কোডটি অ-সর্বজনীন, পারফরম্যান্ট, তুচ্ছ এবং পোর্টেবল। বুস্টের তার জায়গা আছে তবে আমি পরামর্শ দিচ্ছি যে টোকেনাইজিং স্ট্রিংগুলির জন্য এটি খানিকটা ওভারকিল: আপনি কোনও ছবি ঝুলানোর জন্য আপনার পুরো বাড়িটি একটি ইঞ্জিনিয়ারিং ফার্মে স্থানান্তরিত করবেন না যাতে তারা একটি ছবি ঝুলিয়ে দেবে .... অত্যন্ত ভাল, কিন্তু উপদ্বারা দ্বারা বহুগুণে বেড়ে যায় না।
GMasucci

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

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

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

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

    return 0;
}

12
আপনি যদি অন্যান্য শর্তেও বিভক্ত করতে পারেন তবে যদি আপনি শর্তে যেমন কমা দ্বারা বিভক্ত হয়ে ব্যবহার getlineকরেন তবে whileব্যবহার করুন while(getline(ss, buff, ','))
আলী 20

181

যাদের সাথে কোড আকারের জন্য সমস্ত দক্ষতা ত্যাগ করতে এবং "দক্ষ" এক ধরণের কমনীয়তা হিসাবে দেখতে ভাল লাগে না, তাদের নীচেরগুলিতে একটি মিষ্টি স্পটটি আঘাত করা উচিত (এবং আমি মনে করি যে টেম্পলেট ধারক শ্রেণিটি একটি দুর্দান্তভাবে মার্জিত সংযোজন)):

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

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

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

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

      lastPos = pos + 1;
   }
}

আমি সাধারণত std::vector<std::string>আমার দ্বিতীয় প্যারামিটার ( ContainerT) হিসাবে ধরণগুলি ব্যবহার করতে পছন্দ করি ... তবে সরাসরি অ্যাক্সেসের প্রয়োজন হয় না তার list<>চেয়ে অনেক বেশি দ্রুত vector<>এবং আপনি এমনকি নিজের স্ট্রিং ক্লাস তৈরি করতে পারেন এবং এমন কোনও কিছু ব্যবহার করতে পারেন std::list<subString>যেখানে subStringঅবিশ্বাস্য গতির জন্য কোনও অনুলিপি না করে বাড়ে।

এটি এই পৃষ্ঠায় দ্রুততম টোকেনাইজের চেয়ে দ্বিগুণের বেশি এবং অন্য কারও চেয়ে প্রায় 5 গুণ বেশি দ্রুত। নিখুঁত প্যারামিটার ধরণের সাহায্যে আপনি সমস্ত স্ট্রিংকে মুছে ফেলতে এবং অতিরিক্ত গতি বৃদ্ধির জন্য অনুলিপিগুলি তালিকাভুক্ত করতে পারেন।

অতিরিক্তভাবে এটি ফলাফলের (অত্যন্ত অদক্ষ) রিটার্নটি করে না, বরং এটি টোকেনকে একটি রেফারেন্স হিসাবে পাস করে, এভাবে আপনি যদি চান তবে একাধিক কল ব্যবহার করে টোকেন তৈরি করতে দেয়।

শেষ পর্যন্ত এটি আপনাকে শেষ alচ্ছিক প্যারামিটারের মাধ্যমে ফলাফল থেকে খালি টোকেনগুলি ছাঁটাতে হবে কিনা তা নির্দিষ্ট করার অনুমতি দেয়।

এটির জন্য যা দরকার তা হ'ল std::string... বাকিগুলি alচ্ছিক। এটি স্ট্রিম বা বুস্ট লাইব্রেরি ব্যবহার করে না, তবে এই বিদেশী ধরণের কয়েকটি প্রাকৃতিকভাবে গ্রহণ করতে সক্ষম হতে যথেষ্ট নমনীয়।


5
আমি এটির বেশ অনুরাগী, তবে জি ++ (এবং সম্ভবত ভাল অনুশীলনের জন্য) যে কেউ এটি ব্যবহার করছেন typedef ContainerT Base; typedef typename Base::value_type ValueType; typedef typename ValueType::size_type SizeType; টাইপডেফ এবং টাইপনেমগুলি চাইবেন : তারপরে সেই অনুযায়ী মান_প্রকার এবং আকার_প্রকারগুলি বেছে নিন।
আউজ

11
আমাদের মধ্যে যাঁদের জন্য টেমপ্লেট স্টাফ এবং প্রথম মন্তব্য সম্পূর্ণ বিদেশী, প্রয়োজনীয় ব্যবহারের সাথে সিএমপ্লিটের ব্যবহার উদাহরণ সুদৃশ্য।
ওয়েজ মিলার

3
আহ্, ভাল, আমি এটি বুঝতে পেরেছি। আমি টোকেনাইজ () এর ফাংশন বডিটির অভ্যন্তরে অ্যাবস-এর মন্তব্য থেকে সি ++ লাইনগুলি রেখেছি, তারপরে কনটেনারটি :: মান_প্রকারকে কেবলমাত্র ভ্যালু টাইপের পরিবর্তনের জন্য টোকেনস.পশ_ব্যাক () লাইনগুলি সম্পাদনা করেছি (কনটেনারটি :: মান_প্রকার :: আকার_প্রকার) থেকে ( আকারের ধরণ). ফিক্সড বিটস জি ++ সম্পর্কে হাহাকার ছিল। এটিকে কেবল টোকেনাইজ (কিছু_ স্ট্রিং, কিছু_ভেক্টর) হিসাবে ডাকা;
ওয়েস মিলার

2
নমুনা ডেটাতে কয়েকটি কর্মক্ষমতা পরীক্ষা চালানো ছাড়াও, প্রাথমিকভাবে আমি এটিকে কমিয়ে আনা সম্ভব নির্দেশাবলীর মধ্যে এবং কম স্ট্রিং ক্লাস ব্যবহার করে সক্ষম মেমোরি অনুলিপিগুলি কেবল অন্য স্ট্রিংয়ে অফসেট / দৈর্ঘ্যের উল্লেখ করে থাকি। (আমি আমার নিজের ঘূর্ণায়মান, তবে আরও কিছু বাস্তবায়ন রয়েছে)। দুর্ভাগ্যক্রমে এর উন্নতি করতে অন্য কেউ করতে পারে এমন খুব বেশি কিছু নেই, তবে ক্রমবর্ধমান বৃদ্ধি সম্ভব হয়েছিল।
মারিউস

3
এটি কখনের জন্য সঠিক ফলাফল trimEmpty = true। মনে রাখবেন যে "abo"এই উত্তরের কোনও ডিলিমিটার নয়, তবে সীমানার অক্ষরের তালিকা। একক অক্ষরে অক্ষরের স্ট্রিং নিতে এটি পরিবর্তন করা সহজ হবে (আমার মনে হয় এটিকে str.find_first_ofপরিবর্তন করা উচিত str.find_first, তবে আমি ভুল হতে পারি ... পরীক্ষা করতে পারছি না)
মারিয়াস

158

এখানে আরও একটি সমাধান। এটি কমপ্যাক্ট এবং যুক্তিসঙ্গতভাবে দক্ষ:

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

স্ট্রিং বিভাজক, প্রশস্ত স্ট্রিং ইত্যাদি হ্যান্ডেল করার জন্য এটি সহজেই টেম্পলেটাইজ করা যেতে পারে

নোট করুন যে বিভাজনের ""ফলে একটি ফাঁকা স্ট্রিং এবং বিভক্তকরণ ","(যেমন। সেপ) ফলাফল দুটি খালি স্ট্রিংয়ের ফলাফল in

খালি টোকেন এড়াতে এটি সহজেই প্রসারিত করা যেতে পারে:

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
প্রথম সংস্করণটি সহজ এবং কাজটি নিখুঁতভাবে সম্পন্ন করে। আমি কেবলমাত্র পরিবর্তনটি করবো তা হ'ল ফলাফলটি প্যারামিটার হিসাবে পাস করার পরিবর্তে সরাসরি ফিরিয়ে দেওয়া।
গ্রেগস্লোম

2
দক্ষতা জন্য আউটপুট একটি পরামিতি হিসাবে পাস করা হয়। ফলাফলটি যদি ফিরে আসে তবে এটির জন্য ভ্যাক্টরের একটি অনুলিপি বা একটি গাদা বরাদ্দ প্রয়োজন যা পরে মুক্ত করতে হবে।
আলেক থমাস

2
উপরে আমার মন্তব্যে একটি সামান্য সংযোজন: সি ++ 11 সরানো শব্দার্থবিজ্ঞান ব্যবহার করা হলে এই ফাংশনটি বিনা শাস্তিতে ভেক্টরকে ফিরিয়ে দিতে পারে।
অ্যালেক থমাস

7
@ অ্যালকথোমাস: সি ++ এর আগেও বেশিরভাগ সংকলকরা এনআরভিওর মাধ্যমে রিটার্ন অনুলিপিটি অপ্টিমাইজ করবে না? (+1 যাইহোক; খুব সংক্ষিপ্ত)
মার্সেলো ক্যান্টোস

11
সমস্ত উত্তরগুলির মধ্যে এটি সবচেয়ে আবেদনময় এবং নমনীয় বলে মনে হয়। একসাথে ডিলিমিটারের সাথে গেটলাইন সহ, যদিও এটির একটি কম স্পষ্ট সমাধান। সি ++ 11 মানের কি এর জন্য কিছু নেই? সি ++ 11 আজকাল পাঞ্চ কার্ড সমর্থন করে?
স্পেসেন জ্যাসেট

123

স্ট্রিংয়ের মাধ্যমে পুনরাবৃত্তি করার এটি আমার প্রিয় উপায়। আপনি প্রতিটি শব্দ প্রতি যা চান তা করতে পারেন।

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

istringstream iss(line, istringstream::in);

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

এটি wordহিসাবে ঘোষণা করা সম্ভব char?
আবাটিশচেভ

দুঃখিত abatishchev, সি ++ আমার দৃ strong় বিন্দু নয়। তবে আমি কল্পনা করি প্রতিটি শব্দে প্রতিটি চরিত্রের মধ্য দিয়ে লুপের অভ্যন্তরীণ লুপ যুক্ত করা কঠিন হবে না। তবে এখনই আমি বিশ্বাস করি যে বর্তমান লুপটি শব্দ বিভাজনের জন্য ফাঁকা জায়গাগুলির উপর নির্ভর করে। আপনি যদি না জানেন যে প্রতিটি জায়গার মধ্যে কেবল একটি একক চরিত্র রয়েছে, সেক্ষেত্রে আপনি কেবল একটি
চরকে

11
আপনি যদি শব্দটিকে চর হিসাবে ঘোষণা করেন তবে এটি প্রতিটি অ-শ্বেত স্থানের অক্ষর দিয়ে পুনরাবৃত্তি করবে। এটি চেষ্টা করার পক্ষে যথেষ্ট সহজ:stringstream ss("Hello World, this is*@#&$(@ a string"); char c; while(ss >> c) cout << c;
ওয়েইন ওয়ার্নার

79

এটি স্ট্যাক ওভারফ্লো প্রশ্নের মতোই কীভাবে আমি সি ++ এ স্ট্রিং টোকানাইজ করব?

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

using namespace std;
using namespace boost;

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

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

এটি কি সমস্ত টোকেনের অনুলিপি তৈরি করে, বা এটি কেবল বর্তমান টোকেনের শুরু এবং শেষের অবস্থান রাখে?
einpoklum

66

আমি নিম্নলিখিতটি পছন্দ করি কারণ এটি ফলাফলগুলিকে ভেক্টরে রাখে, ডিলিম হিসাবে স্ট্রিং সমর্থন করে এবং খালি মান রাখার উপর নিয়ন্ত্রণ দেয়। তবে, এটি ততটা ভাল লাগে না।

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

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

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

অবশ্যই, বুস্টের একটি রয়েছে split()যা আংশিকভাবে এর মতো কাজ করে। এবং, যদি 'হোয়াইট স্পেস' দ্বারা, আপনি সত্যিকার অর্থে বুস্টের বিভাজনকে is_any_of()দুর্দান্ত কাজের সাথে ব্যবহার করে কোনও ধরণের সাদা-স্পেস বলতে চাইছেন ।


অবশেষে একটি সমাধান যা খালি টোকেনগুলি স্ট্রিংয়ের উভয় পাশে সঠিকভাবে পরিচালনা করছে
fmuecke

53

এসটিএলে ইতিমধ্যে ইতিমধ্যে কোনও পদ্ধতি উপলব্ধ নেই।

তবে, আপনি সদস্যটি strtok()ব্যবহার করে সি এর ফাংশন ব্যবহার std::string::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/ ডকুমেন্টস / সিসিপিএফএইচটিও / ভলিউম / সি++ প্রোগ্রামগ্রামিং- হাওটিও- .h.এইচটিএমএল

কোড নমুনা সম্পর্কে আপনার যদি প্রশ্ন থাকে তবে একটি মন্তব্য দিন এবং আমি ব্যাখ্যা করব।

এবং কেবল কারণ এটি একটি typedefপরিচিত পুনরাবৃত্তির প্রয়োগ করে না বা <<অপারেটরটির ওভারলোড বোঝায় না এটি খারাপ কোড। আমি বেশ ঘন ঘন সি ফাংশন ব্যবহার করি। উদাহরণস্বরূপ, printfএবংscanf উভয়ই দ্রুত std::cinএবং std::cout(উল্লেখযোগ্যভাবে) এর চেয়ে দ্রুত , fopenসিন্টেক্সটি বাইনারি ধরণের জন্য অনেক বেশি বন্ধুত্বপূর্ণ এবং এগুলি আরও ছোট এক্সইএস উত্পাদন করতে ঝোঁক।

এই "কমনীয়তা ওভার পারফরম্যান্স" বিক্রি করবেন না চুক্তিতে ।


আমি সি স্ট্রিং ফাংশন সম্পর্কে সচেতন এবং আমি পারফরম্যান্স সংক্রান্ত সমস্যাগুলি সম্পর্কেও সচেতন (উভয়ই আমি আমার প্রশ্নে উল্লেখ করেছি)। তবে, এই নির্দিষ্ট প্রশ্নের জন্য, আমি একটি মার্জিত সি ++ সমাধান খুঁজছি।
আশ্বিন নানজাপ্পা

11
@ নেলসন লা কিউয়েট: আমাকে অনুমান করতে দাও: কারণ স্ট্রোটোক প্রত্যাবর্তনকারী নয়?
প্যারাজবাল

40
না @Nelson কি কখনো strtok করার string.c_str () পাস! স্ট্রোকক ইনপুট স্ট্রিং ট্র্যাশ করে (প্রতিটি ফাউডন ডিলিমিটার প্রতিস্থাপনের জন্য '\ 0' অক্ষর সন্নিবেশ করায়) এবং c_str () একটি অ-পরিবর্তনীয় স্ট্রিং প্রদান করে।
ইভান তেরান 18

3
@ নেলসন: আপনার শেষ মন্তব্যে সেই অ্যারের আকারের স্ট্রাইস সাইজ () + 1 হওয়া দরকার। তবে আমি আপনার থিসিসের সাথে একমত যে "নান্দনিক" কারণে সি ক্রিয়াকলাপগুলি এড়ানোর পক্ষে নির্বোধ।
j_random_hacker

2
@ পলম: না, সি ++ স্ট্রিমগুলির স্লোনেসটি ফ্যাক্টসের কারণে হয়। সিঙ্ক্রোনাইজেশন অক্ষম করা অবস্থায় (এবং স্ট্রিংস্ট্রিমগুলিতে, যা সিঙ্ক্রোনাইজ করতে পারে না) এমনকি তারা স্টডিও এইচ ফাংশনের চেয়েও ধীর।
বেন ভয়েগট

42

এখানে একটি বিভক্ত ফাংশন যা:

  • জেনেরিক
  • স্ট্যান্ডার্ড সি ++ ব্যবহার করে (কোনও উন্নতি নেই)
  • একাধিক সীমানা গ্রহণকারী গ্রহণ করে
  • খালি টোকেন উপেক্ষা করুন (সহজেই পরিবর্তন করা যেতে পারে)

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

আপনি ব্যবহারের তালিকায় যুক্ত করতে ভুলে গেছেন: "চূড়ান্ত অদক্ষ"
জ্যান্সার টিউলিপ

1
@ এক্সেন্ডারটুলিপ, আপনি কি আরও গঠনমূলক হতে পারেন এবং ব্যাখ্যা করতে পারেন কীভাবে বা কেন?
মার্কো এম।

3
@ এক্সান্ডারটুলিপ: আমি ধরে নিয়েছি যে আপনি এটির দ্বারা ভেক্টরকে ফিরিয়ে দেওয়ার বিষয়ে উল্লেখ করছেন। রিটার্ন-ভ্যালু-অপটিমাইজেশন (আরভিও, গুগল এটি) এর যত্ন নেওয়া উচিত। এছাড়াও সি ++ 11 এ আপনি সরানো রেফারেন্স দিয়ে ফিরে আসতে পারেন।
জোসেফ গারভিন

3
এটি প্রকৃতপক্ষে আরও অনুকূলিত করা যায়: .push_back (str.substr (...)) এর পরিবর্তে কেউ .emplace_back (str, start, pos - start) ব্যবহার করতে পারে। এইভাবে স্ট্রিং অবজেক্টটি কনটেইনারটিতে নির্মিত হয় এবং এইভাবে আমরা .susbstr ফাংশন দ্বারা চালিত একটি অপারেশন + অন্যান্য শেননিগান এড়াতে পারি।
মিহাই বায়োগ

@ জুপ্প হ্যাঁ ভাল ধারণা. আমি যখন এটি লিখেছি তখন ভিএস 10 এর এমপ্লেস_ব্যাক সমর্থন ছিল না। আমি আমার উত্তর আপডেট করব। ধন্যবাদ
মার্কো এম।

36

আমার এই সমস্যার 2 লাইনের সমাধান রয়েছে:

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

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

তারপরে মুদ্রণের পরিবর্তে আপনি এটি কোনও ভেক্টরে রেখে দিতে পারেন।


35

তবুও অন্য একটি নমনীয় এবং দ্রুত উপায়

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

এটি স্ট্রিংয়ের ভেক্টর দিয়ে ব্যবহার করতে (সম্পাদনা করুন: যেহেতু কেউ এসটিএল ক্লাস উত্তরাধিকারী না করার জন্য নির্দেশ করেছেন ... 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

দ্রষ্টব্য, আপনি আপনার সংকলকটির উপর নির্ভর করে রেফারেন্সের মাধ্যমে স্ট্রিং আর্গুমেন্টটিও নিতে চাইতে পারেন।


এটি আমার প্রিয় উত্তর হতে পারে তবে স্ট্যান্ড :: রেজেক্সটি জিসিসি ৪.৮ এ বিভক্ত। তারা বলেছিল যে তারা এটিকে জিসিসি ৪.৯-এ সঠিকভাবে প্রয়োগ করেছে। আমি এখনও আপনাকে আমার +1
দিচ্ছি

1
এটি ছোটখাটো পরিবর্তনগুলির সাথে আমার প্রিয়: ভেক্টর আপনি যেমনটি বলেছিলেন তেমন রেফারেন্স হিসাবে ফিরে এসেছে এবং "টিআর" এবং "রেজেক্স" আর্গুমেন্টগুলি রেফারেন্স দ্বারাও পাস করেছে। ধন্যবাদ.
কোয়ান্টামকার্ল

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
কারণ এটি স্ট্যাটিক ভেরিয়েবলের প্রথম কল থেকে চর পয়েন্টার সংরক্ষণ করে, যাতে পরবর্তী কলগুলিতে যখন এনএইউএল পাস হয় তখন এটি কী পয়েন্টারটি ব্যবহার করা উচিত তা মনে রাখে। strtokঅন্য থ্রেড এখনও প্রক্রিয়া চলাকালীন যদি দ্বিতীয় থ্রেড কল করে, এই চর পয়েন্টারটি ওভাররাইট করা হবে এবং উভয় থ্রেডের পরে ভুল ফলাফল হবে। mkssoftware.com/docs/man3/strtok.3.asp
কেভিন

1
যেমনটি বলা হয়েছে যে স্ট্রোটোকটি অনিরাপদ এবং সি স্ট্রোকক_আরও ব্যবহারের জন্য সুপারিশ করা হয়েছে
সিস্টেমসফল

4
strtok_r আপনি ব্যবহার করা যেতে পারে এমন কোনও কোডের বিভাগে থাকলে ব্যবহার করা যেতে পারে। এই হল শুধুমাত্র যে উপরের সব সমাধান "লাইনের গোলমাল" নয়, এবং কি, ঠিক, গ সঙ্গে ++, ভুল একটি উইল
এরিক Aronesty

আপডেট হয়েছে যাতে সি ++ উইঙ্কস থেকে থ্রেড সুরক্ষার ভিত্তিতে কোনও আপত্তি থাকতে পারে না।
এরিক অ্যারোনস্টি

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

আমি স্ট্রটোক ব্যবহার করে আমার নিজস্ব রোল করেছি এবং একটি স্ট্রিংকে বিভক্ত করতে বুস্ট ব্যবহার করেছি। আমি খুঁজে পাওয়া সবচেয়ে ভাল পদ্ধতি হ'ল সি ++ স্ট্রিং টুলকিট লাইব্রেরি । এটি অবিশ্বাস্যভাবে নমনীয় এবং দ্রুত।

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

যে কোনও স্ট্রিংকে ডিলিমিটার হিসাবে ব্যবহার করতে পারে, বাইনারি ডেটাও ব্যবহার করা যায় (স্ট্যান্ড :: স্ট্রিং নালাসহ বাইনারি ডেটা সমর্থন করে)

ব্যবহার:

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", "ক্যোয়ারী" এবং "ট্রেডস" এ বিভক্ত করে। ফাংশনটি সরু এবং প্রশস্ত স্ট্রিংগুলির সাথে কাজ করে। কারণ এটি বর্তমান লোকালকে শ্রদ্ধা করে এটি "রাউমফাহার্টটিবারওয়্যাচুংস ভারর্ডনং" কে "রাউমফাহার্ট", ​​"Überwachungs" এবং "ভেরর্ডনং" এ বিভক্ত করে।

নোটটি std::upperসত্যিই ফাংশন টেম্পলেট আর্গুমেন্ট হিসাবে পাস করা উচিত। তাহলে আরো অনেক এই ফাংশন থেকে সাধারণ বিভক্ত করতে পারেন বিভেদক পছন্দ এ ",", ";"বা " "খুব।


2
2 টি রেভেশন হয়েছে। ওটা সুন্দর. দেখে মনে হচ্ছে আমার ইংরাজিকে অনেকটা "জার্মান" আছে। তবে সংশোধনবাদী দুটি ছোটখাটো বাগ সম্ভবত স্থির করেনি কারণ এগুলি যেভাবেই সুস্পষ্ট ছিল: std::isupperযুক্তি হিসাবে পাস করা যেতে পারে, না std::upper। দ্বিতীয় একটি typenameআগে রাখা String::const_iterator
Andreas Spindler

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

ইয়েপ্প,
ভিত্তিকের
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.