আমি কীভাবে সি ++ এ স্ট্রিং টোকানাইজ করব?


414

জাভাতে একটি সুবিধাজনক বিভাজন পদ্ধতি রয়েছে:

String str = "The quick brown fox";
String[] results = str.split(" ");

সি ++ এ করার কোন সহজ উপায় আছে?


172
আমি বিশ্বাস করতে পারি না যে এই রুটিন টাস্কটি সি ++
wfbarksdale

6
এটি সি ++ তে মাথা ব্যথা নয় - এটি অর্জনের বিভিন্ন উপায় রয়েছে। প্রোগ্রামাররা সি # এর চেয়ে সি ++ সম্পর্কে কম সচেতন - এটি বিপণন এবং বিনিয়োগ সম্পর্কে ... বিভিন্ন সি ++ বিকল্পগুলি অর্জনের জন্য এটি দেখুন: সিপিপ্লসপ্লাসস
ফাক

9
@ এইচবি0 অনেক প্রশ্নের উত্তর দিয়ে যাচ্ছে এবং এখনও সিদ্ধান্ত নেওয়ার উপায় নয় এমন মাথা ব্যথার কারণ। একটিতে লাইব্রেরিটির প্রয়োজন, অন্যটি কেবলমাত্র জায়গাগুলির জন্য, অন্যটি স্পেস পরিচালনা করে না ..
পাসচালিস


2
সি ++ এর সমস্ত কিছুর জন্য লড়াই করতে হবে কেন?
ওয়াল আসফ

উত্তর:


145

সি ++ স্ট্যান্ডার্ড লাইব্রেরি অ্যালগরিদমগুলি কংক্রিটের পাত্রে না হয়ে পুনরুক্তিদের কাছাকাছি প্রায় সার্বজনীন ভিত্তিক। দুর্ভাগ্যক্রমে splitএটি সি ++ স্ট্যান্ডার্ড লাইব্রেরিতে জাভা জাতীয় ফাংশন সরবরাহ করা শক্ত করে তোলে , যদিও কেউ যুক্তি দেয় না যে এটি সুবিধাজনক হবে। তবে এর রিটার্ন টাইপ কেমন হবে? std::vector<std::basic_string<…>>? হতে পারে, তবে তারপরে আমরা বরাদ্দগুলি (সম্ভাব্য অপ্রয়োজনীয় এবং ব্যয়বহুল) করতে বাধ্য হয়েছি।

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

এর সহজতম সময়ে, আপনি std::string::findআঘাত না করা অবধি ব্যবহার করে পুনরাবৃত্তি করতে পারবেন std::string::nposএবং ব্যবহার করে সামগ্রীগুলি বের করতে পারবেন std::string::substr

হোয়াইটস্পেসে বিভাজনের জন্য আরও তরল (এবং আইডোম্যাটিক, তবে বেসিক) সংস্করণটি ব্যবহার করবে std::istringstream:

auto iss = std::istringstream{"The quick brown fox"};
auto str = std::string{};

while (iss >> str) {
    process(str);
}

std::istream_iteratorগুলি ব্যবহার করে স্ট্রিং স্ট্রিমের বিষয়বস্তুগুলি এর পুনরুক্তকারী পরিসীমা নির্মাণকারী ব্যবহার করে কোনও ভেক্টরে অনুলিপি করা যেতে পারে।

একাধিক গ্রন্থাগার (যেমন বুস্ট টোকেনাইজার ) নির্দিষ্ট টোকেনিসার সরবরাহ করে।

আরও উন্নত বিভাজনের জন্য নিয়মিত প্রকাশের প্রয়োজন। সি ++ std::regex_token_iteratorবিশেষত এই উদ্দেশ্যে সরবরাহ করে:

auto const str = "The quick brown fox"s;
auto const re = std::regex{R"(\s+)"};
auto const vec = std::vector<std::string>(
    std::sregex_token_iterator{begin(str), end(str), re, -1},
    std::sregex_token_iterator{}
);

53
দুঃখের বিষয়, বুস্ট সবসময় সমস্ত প্রকল্পের জন্য উপলব্ধ না। আমাকে একটি উত্সাহীন উত্তর খুঁজতে হবে।
ফাজিবুনি স্লিপারস

36
প্রতিটি প্রকল্প "ওপেন সোর্স" এর জন্য উন্মুক্ত নয়। আমি ভারী নিয়ন্ত্রিত শিল্পগুলিতে কাজ করি। আসলেই এটি কোনও সমস্যা নয়। এটি জীবনের সত্য ঘটনা। বুস্ট সর্বত্র পাওয়া যায় না।
FuzzyBunnySlippers

5
@ ননলাইনারআইডিয়াস অন্যান্য প্রশ্ন / উত্তর মোটেই ওপেন সোর্স প্রকল্পগুলি সম্পর্কে ছিল না। যে কোনও প্রকল্পের ক্ষেত্রেও একই কথা । এটি বলেছিল, আমি অবশ্যই মিস্রা সি এর মতো সীমাবদ্ধ মানদণ্ডগুলি সম্পর্কে বুঝতে পারি তবে এটি বুঝতে পেরেছি যে আপনি যাইহোক যাইহোক স্ক্র্যাচ থেকে সবকিছু তৈরি করেন (যদি না আপনি কোনও অনুগত লাইব্রেরি - বিরলতা খুঁজে না পান)। যাইহোক, বিন্দুটি খুব কমই যে "বুস্ট উপলব্ধ নয়" - এটি আপনার বিশেষ প্রয়োজনীয়তা যার জন্য প্রায় কোনও সাধারণ-উদ্দেশ্য উত্তর অনুপযুক্ত হবে।
কনরাড রুডলফ

1
@ ননলাইনারিআইডিয়াস কেস পয়েন্টে অন্য, নন-বুস্টের উত্তরগুলিও মিস্রা-র সাথে সামঞ্জস্যপূর্ণ নয়।
কনরাড রুডলফ

3
@ দিমিত্রি "এসটিএল বার্ফ" কি ?! এবং পুরো সম্প্রদায় সি প্রিপ্রোসেসর প্রতিস্থাপনের পক্ষে - আসলে, এটি করার প্রস্তাব রয়েছে। পরিবর্তে পিএইচপি বা অন্য কোনও ভাষা ব্যবহার করার জন্য আপনার পরামর্শটি পিছনের দিকে একটি বিশাল পদক্ষেপ হবে।
কনরাড রুডল্ফ

188

বুস্ট tokenizer বর্গ বেশ সহজ জিনিস এই সাজানোর করতে পারেন:

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

using namespace std;
using namespace boost;

int main(int, char**)
{
    string text = "token, test   string";

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

সি ++ 11 এর জন্য আপডেট হয়েছে:

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

using namespace std;
using namespace boost;

int main(int, char**)
{
    string text = "token, test   string";

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

1
ভাল জিনিস, আমি সম্প্রতি এটি ব্যবহার করেছি। টোকেনের (টেক্সট, সেপ) বিটের আগে দুটি ">" অক্ষর আলাদা করার জন্য আমি একটি সাদা জায়গা ব্যবহার না করা অবধি আমার ভিজ্যুয়াল স্টুডিও সংকলকের একটি স্বতন্ত্র কানাচিদ রয়েছে: (ত্রুটি C2947: প্রত্যাশা '>' টেমপ্লেট-আর্গুমেন্ট-তালিকাটি শেষ করতে, পাওয়া গেছে '> > ')
AndyUK

@ অ্যান্ডিয়ুক হ্যাঁ, স্থান ব্যতীত সংকলক দুটি সমাপ্ত টেম্পলেটগুলির চেয়ে এক্সট্রাকশন অপারেটর হিসাবে পার্স করে।
এনাব্রেনটেন

তাত্ত্বিকভাবে এটি সি ++ 0 এক্স
ডেভিড সাউদার

3
char_separatorকনস্ট্রাক্টরের তৃতীয় পরামিতিগুলি থেকে সাবধান থাকুন ( drop_empty_tokensএটি ডিফল্ট, বিকল্পটি হ'ল keep_empty_tokens)।
বেনোইট

5
@puk - এটি সি ++ শিরোনাম ফাইলগুলির জন্য একটি সাধারণত ব্যবহৃত প্রত্যয়। ( .hসি হেডারগুলির জন্য পছন্দ করুন)
ফেরুচিয়ো

167

এখানে একটি আসল সহজ:

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

vector<string> split(const char *str, char c = ' ')
{
    vector<string> result;

    do
    {
        const char *begin = str;

        while(*str != c && *str)
            str++;

        result.push_back(string(begin, str));
    } while (0 != *str++);

    return result;
}

.h ফাইলে এই পদ্ধতির জন্য কি আমার প্রোটোটাইপ যুক্ত করতে হবে?
সুহরব সামিয়েভ

5
এটি ঠিক "সেরা" উত্তর নয় কারণ এটি এখনও একটি স্ট্রিং আক্ষরিক ব্যবহার করে যা প্লেইন সি ধ্রুবক অক্ষর অ্যারে। আমি বিশ্বাস করি যে প্রশ্নকারী জিজ্ঞাসা করছে যে তিনি একটি সি ++ স্ট্রিং টোকানাইজ করতে পারেন যা পরবর্তীতে প্রবর্তিত "স্ট্রিং" টাইপযুক্ত।
বিজয় কুমার কান্ত

এটির একটি নতুন উত্তর প্রয়োজন কারণ আমি দৃ +়ভাবে সন্দেহ করি যে সি ++ 11 এ নিয়মিত প্রকাশের অন্তর্ভুক্তি সেরা উত্তরটি কী হবে তা পরিবর্তন করেছে।
সর্বাত্মক

113

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

char myString[] = "The quick brown fox";
char *p = strtok(myString, " ");
while (p) {
    printf ("Token: %s\n", p);
    p = strtok(NULL, " ");
}

কয়েকটি সতর্কতা (যা আপনার প্রয়োজন অনুসারে নাও পারে)। প্রক্রিয়াটিতে স্ট্রিংটি "ধ্বংস" হয়, এর অর্থ EOS অক্ষরগুলি ডিলিমটার স্পটে ইনলাইন স্থাপন করা হয়। সঠিক ব্যবহারের জন্য আপনাকে স্ট্রিংয়ের একটি নন-কনস্ট্যান্ড সংস্করণ তৈরি করতে হবে। আপনি মাঝারি পার্সের ছাড়কদের তালিকাও পরিবর্তন করতে পারেন।

আমার নিজের মতামত অনুসারে, উপরের কোডটি এর জন্য পৃথক ক্লাস লেখার চেয়ে অনেক সহজ এবং ব্যবহার করা সহজ। আমার কাছে, ভাষাটি সরবরাহ করে এমন একটি ফাংশন এবং এটি এটি ভাল এবং পরিষ্কারভাবে করে। এটি কেবল একটি "সি ভিত্তিক" সমাধান। এটি উপযুক্ত, এটি সহজ, এবং আপনাকে প্রচুর অতিরিক্ত কোড লিখতে হবে না :-)


42
আমি সিটিকে অপছন্দ করি না, তবে স্ট্রোকক থ্রেড-নিরাপদ নয় এবং আপনার অবশ্যই নিশ্চিত হওয়া উচিত যে আপনি যে স্ট্রিংটি প্রেরণ করেছেন তাতে কোনও সম্ভাব্য বাফার ওভারফ্লো এড়াতে নাল অক্ষর রয়েছে।
tloach

11
Strtok_r আছে, তবে এটি একটি সি ++ প্রশ্ন ছিল।
অধ্যাপক ফ্যালকেন চুক্তিটি

3
@ টোলোচ: এমএস সি ++ কম্পাইলার স্ট্রোককে থ্রেড নিরাপদ বলে আভ্যন্তরীণ স্ট্যাটিক ভেরিয়েবলটি টিএলএসে তৈরি করা হয়েছে (থ্রেড লোকাল স্টোরেজ) (আসলে এটি সংকলক নির্ভরশীল)
আহমেদ

3
@ আহাম্মেদ: থ্রেড নিরাপদ অর্থ বিভিন্ন থ্রেডে দু'বার ফাংশনটি চালানো সক্ষম হওয়ার চেয়ে বেশি। এই ক্ষেত্রে যদি স্ট্রোটোক চলাকালীন থ্রেডটি সংশোধন করা হয় তবে স্ট্রোটকের পুরো রান চলাকালীন স্ট্রিংটি বৈধ হওয়া সম্ভব, তবে স্ট্রিং বদল হওয়ার কারণে স্ট্রটোক এখনও বিচলিত হবে, এটি ইতিমধ্যে নাল চরিত্রের অতীত হয়ে গেছে, এবং এটি চলে যাচ্ছে মেমরি পড়তে থাকুন যতক্ষণ না এটি সুরক্ষা লঙ্ঘন হয় বা কোনও শূন্য চরিত্র খুঁজে না পায়। এটি আসল সি স্ট্রিং ফাংশনগুলির সাথে একটি সমস্যা, যদি আপনি কোনও জায়গায় কোনও দৈর্ঘ্য নির্দিষ্ট না করেন তবে আপনি সমস্যার মধ্যে পড়েছেন।
tloach

4
স্ট্রোককে একটি অ-কনস্ট্যান্ট নাল-টার্মিনেটেড চর অ্যারেটির জন্য একটি পয়েন্টার প্রয়োজন, যা সি ++ কোডে সন্ধান করা কোনও সাধারণ প্রাণী নয় ... স্টাডি :: স্ট্রিং থেকে এ রূপান্তর করার জন্য আপনার প্রিয় উপায় কী?
fuzzyTew

105

আর একটি দ্রুত উপায় ব্যবহার করা হয় getline। কিছুটা এইরকম:

stringstream ss("bla bla");
string s;

while (getline(ss, s, ' ')) {
 cout << s << endl;
}

আপনি যদি চান, আপনি একটি সহজ split()পদ্ধতিতে ফিরে আসতে পারেন vector<string>যা সত্যই কার্যকর।


2
স্ট্রিংয়ে 0x0A অক্ষর সহ এই কৌশলটি ব্যবহার করতে আমার সমস্যা হয়েছিল যা সময়কালে লুপটি প্রস্থান করে। অন্যথায়, এটি একটি দুর্দান্ত সহজ এবং দ্রুত সমাধান।
রায়ান এইচ।

4
এটি ভাল তবে কেবল মনে রাখতে হবে যে এটি করে ডিফল্ট ডিলিমিটার '\ n' বিবেচনা করা হয় না। এই উদাহরণটি কার্যকর হবে, তবে আপনি যদি এমন কিছু ব্যবহার করছেন: যখন (গেটলাইন (ইনফাইল, শব্দ, '')) যেখানে ইনফাইলে যদি একাধিক লাইন যুক্ত আইফ্রিম অবজেক্ট থাকে তবে আপনি মজাদার ফলাফল পাবেন ..
হ্যাকরক

এটি খুব খারাপ গেটলাইন স্ট্রিংয়ের পরিবর্তে স্ট্রিমটি ফেরত দেয়, এটি অস্থায়ী স্টোরেজ ছাড়াই সূচনা তালিকায় ব্যবহারের অযোগ্য করে
তোলে

1
শান্ত! কোনও উত্সাহ এবং সি ++ 11 নয়, সেই উত্তরাধিকারী প্রকল্পগুলির ভাল সমাধান আছে!
Deqing

1
এটি উত্তর, ফাংশনটির নামটি কিছুটা বিশ্রী।
নীল

82

এটি মোটামুটি সরাসরি করার জন্য আপনি স্ট্রিম, পুনরুক্তিকারী এবং অনুলিপি অ্যালগোরিদম ব্যবহার করতে পারেন।

#include <string>
#include <vector>
#include <iostream>
#include <istream>
#include <ostream>
#include <iterator>
#include <sstream>
#include <algorithm>

int main()
{
  std::string str = "The quick brown fox";

  // construct a stream from the string
  std::stringstream strstr(str);

  // use stream iterators to copy the stream to the vector as whitespace separated strings
  std::istream_iterator<std::string> it(strstr);
  std::istream_iterator<std::string> end;
  std::vector<std::string> results(it, end);

  // send the vector to stdout.
  std::ostream_iterator<std::string> oit(std::cout);
  std::copy(results.begin(), results.end(), oit);
}

17
আমি এই স্টাড্ডকে দেখতে পেয়েছি: পড়তে জ্বালাময়ী .. কেন "ব্যবহার" ব্যবহার করবেন না?
ব্যবহারকারী 35978

80
@ ভাদি: কারণ অন্য কারও পোস্ট সম্পাদনা করা বেশ চক্রান্তকারী। @ ফিজ: আমি stdআমার অবজেক্টটি কোথা থেকে এসেছে তা এইভাবে জানাতে পছন্দ করি, এটি কেবল স্টাইলের বিষয়।
ম্যাথিউ এম।

7
আমি আপনার কারণটি বুঝতে পেরেছি এবং আমি মনে করি এটি যদি আপনার পক্ষে কাজ করে তবে এটি আসলে একটি ভাল পছন্দ but উপরের দিকে "নেমস্পেস স্ট্যান্ড ব্যবহার করে" এর মতো সম্পূর্ণ বিদেশী উদাহরণটি পড়তে ও বুঝতে সহজতর কারণ এটি নিম্নলিখিত রেখাগুলি ব্যাখ্যা করার জন্য কম প্রচেষ্টা প্রয়োজন ... বিশেষত এই ক্ষেত্রে কারণ সবকিছু স্ট্যান্ডার্ড লাইব্রেরি থেকে। আপনি "স্টাড :: স্ট্রিং ব্যবহার করে" সিরিজ দিয়ে অবজেক্টগুলি কোথা থেকে এসেছে তা পড়া সহজ এবং স্পষ্ট করে তুলতে পারেন; ইত্যাদি বিশেষত যেহেতু ফাংশনটি এত ছোট।
CHESirekow

61
"Std ::" উপসর্গগুলি বিরক্তিকর বা কুরুচিপূর্ণ হওয়া সত্ত্বেও সেগুলি উদাহরণ কোডে অন্তর্ভুক্ত করা ভাল, যাতে এই ফাংশনগুলি কোথা থেকে আসছে তা সম্পূর্ণ পরিষ্কার। যদি তারা আপনাকে বিরক্ত করে, আপনি উদাহরণটি চুরি করার পরে এটিকে নিজের হিসাবে দাবি করার পরে তাদের "ব্যবহার" দিয়ে প্রতিস্থাপন করা তুচ্ছ।
ডিএলচাম্বার্স

20
হাঁ! তিনি কি বললেন! সেরা অনুশীলনগুলি হল স্ট্যান্ড উপসর্গটি ব্যবহার করা। কোনও বৃহত্তর কোড বেসটি সন্দেহ নেই যে এটির নিজস্ব লাইব্রেরি এবং নেমস্পেস রয়েছে এবং যখন আপনি নেমস্পেস বিবাদ সৃষ্টি করতে শুরু করবেন তখন "নেমস্পেস স্ট্যান্ড" ব্যবহার করা আপনাকে মাথা ব্যথা দেয়।
মাইক

48

কোন অপরাধ ভাবেন, কিন্তু এই ধরনের একটি সহজ সমস্যা, আপনি তৈরি করছেন জিনিষ পথ খুব জটিল। বুস্ট ব্যবহার করার অনেক কারণ রয়েছে । তবে এই সাধারণ কোনও কিছুর জন্য, এটি 20 # স্লেজ সহ একটি উড়াল মারার মতো।

void
split( vector<string> & theStringVector,  /* Altered/returned value */
       const  string  & theString,
       const  string  & theDelimiter)
{
    UASSERT( theDelimiter.size(), >, 0); // My own ASSERT macro.

    size_t  start = 0, end = 0;

    while ( end != string::npos)
    {
        end = theString.find( theDelimiter, start);

        // If at end, use length=maxLength.  Else use length=end-start.
        theStringVector.push_back( theString.substr( start,
                       (end == string::npos) ? string::npos : end - start));

        // If at end, use start=maxSize.  Else use start=end+delimiter.
        start = (   ( end > (string::npos - theDelimiter.size()) )
                  ?  string::npos  :  end + theDelimiter.size());
    }
}

উদাহরণস্বরূপ (ডগের ক্ষেত্রে),

#define SHOW(I,X)   cout << "[" << (I) << "]\t " # X " = \"" << (X) << "\"" << endl

int
main()
{
    vector<string> v;

    split( v, "A:PEP:909:Inventory Item", ":" );

    for (unsigned int i = 0;  i < v.size();   i++)
        SHOW( i, v[i] );
}

এবং হ্যাঁ, আমরা বিভক্ত করতে পারতাম () একটি উত্তীর্ণের পরিবর্তে কোনও নতুন ভেক্টরকে ফিরিয়ে দিতে পারি It's এটি মোড়ানো এবং ওভারলোডের পক্ষে তুচ্ছ। তবে আমি যা করছি তার উপর নির্ভর করে আমি প্রায়শই নতুন তৈরির চেয়ে প্রাক-বিদ্যমান বস্তুগুলিকে পুনরায় ব্যবহার করা ভাল বলে মনে করি। (যতক্ষণ না আমি মাঝেমধ্যে ভেক্টরটি খালি করতে ভুলি না!)

তথ্যসূত্র: http://www.cplusplus.com/references/string/string/

(আমি মূলত ডগের প্রশ্নের জবাব লিখছিলাম: সি ++ স্ট্রিংস মডিফাইং এবং এক্সট্র্যাক্টিং এর উপর ভিত্তি করে বিভাজক (বদ্ধ) But


12
আপনি কেবলমাত্র এক জায়গায় ব্যবহার করেন এমন ম্যাক্রোটিকে কেন সংজ্ঞায়িত করুন। এবং আপনার ইউএসএসআরটি স্ট্যান্ডার্ড শোধকের চেয়ে আরও ভাল। এর চেয়ে 3 টি টোকনে তুলনা বিভক্ত করা আপনার অন্যথায় প্রয়োজনের চেয়ে আরও বেশি কমা প্রয়োজন ছাড়া অন্য কিছুই করে না।
ক্রেলবার

1
সম্ভবত ইউএসএসআরটি ম্যাক্রো দেখায় (ত্রুটি বার্তায়) দুটি তুলনামূলক মানের (এবং এর মানগুলির) মধ্যে আসল সম্পর্ক? আইএমএইচও, এটি আসলে বেশ ভাল ধারণা।
ঘাসানপিএল

10
ওহ, কেন std::stringশ্রেণিতে একটি বিভাজন () ফাংশন অন্তর্ভুক্ত নেই?
মিঃ শিকাড্যান্স

আমি মনে করি যখন লুপটি শেষ লাইনটি হওয়া উচিত start = ((end > (theString.size() - theDelimiter.size())) ? string::npos : end + theDelimiter.size());এবং যখন লুপটি হওয়া উচিত while (start != string::npos)। এছাড়াও, আমি ভেক্টরের ভিতরে beforeোকানোর আগে এটি খালি নয় তা নিশ্চিত করার জন্য আমি সাবস্ট্রিংগুলি পরীক্ষা করে দেখি।
জন কে

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

46

regex_token_iteratorএস ব্যবহার করে একটি সমাধান :

#include <iostream>
#include <regex>
#include <string>

using namespace std;

int main()
{
    string str("The quick brown fox");

    regex reg("\\s+");

    sregex_token_iterator iter(str.begin(), str.end(), reg, -1);
    sregex_token_iterator end;

    vector<string> vec(iter, end);

    for (auto a : vec)
    {
        cout << a << endl;
    }
}

5
এটি শীর্ষ স্থানের উত্তর হওয়া উচিত। এটি সি ++> = ১১
সর্বজনীন

1
আমি খুশি হলাম আমি এই উত্তরে পুরোপুরি স্ক্রোল করেছি (বর্তমানে কেবল 9 টি আপভোট ছিল) এই টাস্কটির জন্য সি -+ 11 কোডটি দেখতে ঠিক এটির মতো হওয়া উচিত!
ইয়েফিক

বাহ্যিক গ্রন্থাগারগুলির উপর নির্ভর করে না এবং ইতিমধ্যে উপলব্ধ গ্রন্থাগারগুলি ব্যবহার করে এমন দুর্দান্ত উত্তর
অ্যান্ড্রু

1
ডিলিমিটারগুলিতে সর্বাধিক নমনীয়তা দেয় দুর্দান্ত উত্তর। কয়েকটি সতর্কতা: + s + রেজেক্স ব্যবহার করে পাঠ্যের মাঝখানে খালি টোকেনগুলি এড়ানো হয়, তবে পাঠ্যটি শ্বেত স্পেস দিয়ে শুরু হলে একটি খালি প্রথম টোকেন দেয়। এছাড়াও, রেজেক্সটি ধীর বলে মনে হচ্ছে: আমার ল্যাপটপে, এলোমেলো পাঠের ২০ এমবি জন্য, 0.6 সেকেন্ড লাগে, স্ট্রিংক, স্টার্সেপ, বা পার্লামের জন্য sthrfind_first_of এর জন্য পারহমের উত্তর, বা পার্লের জন্য 0.027 সেকেন্ড, বা পাইথনের জন্য 0.021 সেকেন্ড । সংক্ষিপ্ত পাঠ্যের জন্য, গতি কোনও উদ্বেগের বিষয় নাও হতে পারে।
মার্ক গেটস

2
ঠিক আছে এটি দেখতে দুর্দান্ত লাগছে তবে এটি নিয়মিত অভিব্যক্তিগুলির পরিষ্কারভাবে অতিরিক্ত ব্যবহার। পারফরম্যান্সের বিষয়ে চিন্তা না করলেই যুক্তিযুক্ত।
মারেক আর

35

বুস্টের একটি শক্তিশালী বিভক্ত ফাংশন রয়েছে: বুস্ট :: অ্যালগরিদম :: বিভাজন

নমুনা প্রোগ্রাম:

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

int main() {
    auto s = "a,b, c ,,e,f,";
    std::vector<std::string> fields;
    boost::split(fields, s, boost::is_any_of(","));
    for (const auto& field : fields)
        std::cout << "\"" << field << "\"\n";
    return 0;
}

আউটপুট:

"a"
"b"
" c "
""
"e"
"f"
""

26

আমি জানি আপনি একটি সি ++ সমাধান চেয়েছিলেন, তবে আপনি এটি সহায়ক হিসাবে বিবেচনা করতে পারেন:

কিউটি

#include <QString>

...

QString str = "The quick brown fox"; 
QStringList results = str.split(" "); 

এই উদাহরণে বুস্টের চেয়ে সুবিধাটি হ'ল এটি হ'ল এটি আপনার পোস্টের কোডটিতে সরাসরি এক থেকে এক ম্যাপিং।

কিউটি ডকুমেন্টেশনে আরও দেখুন


22

এখানে একটি নমুনা টোকেনাইজার ক্লাস যা আপনি যা চান তা করতে পারে

//Header file
class Tokenizer 
{
    public:
        static const std::string DELIMITERS;
        Tokenizer(const std::string& str);
        Tokenizer(const std::string& str, const std::string& delimiters);
        bool NextToken();
        bool NextToken(const std::string& delimiters);
        const std::string GetToken() const;
        void Reset();
    protected:
        size_t m_offset;
        const std::string m_string;
        std::string m_token;
        std::string m_delimiters;
};

//CPP file
const std::string Tokenizer::DELIMITERS(" \t\n\r");

Tokenizer::Tokenizer(const std::string& s) :
    m_string(s), 
    m_offset(0), 
    m_delimiters(DELIMITERS) {}

Tokenizer::Tokenizer(const std::string& s, const std::string& delimiters) :
    m_string(s), 
    m_offset(0), 
    m_delimiters(delimiters) {}

bool Tokenizer::NextToken() 
{
    return NextToken(m_delimiters);
}

bool Tokenizer::NextToken(const std::string& delimiters) 
{
    size_t i = m_string.find_first_not_of(delimiters, m_offset);
    if (std::string::npos == i) 
    {
        m_offset = m_string.length();
        return false;
    }

    size_t j = m_string.find_first_of(delimiters, i);
    if (std::string::npos == j) 
    {
        m_token = m_string.substr(i);
        m_offset = m_string.length();
        return true;
    }

    m_token = m_string.substr(i, j - i);
    m_offset = j;
    return true;
}

উদাহরণ:

std::vector <std::string> v;
Tokenizer s("split this string", " ");
while (s.NextToken())
{
    v.push_back(s.GetToken());
}

19

এটি একটি সহজ এসটিএল-কেবলমাত্র সমাধান (~ 5 লাইন!) std::findএবং std::find_first_not_ofএটি ডিলিমিটারের পুনরাবৃত্তিগুলি (যেমন স্পেস বা পিরিয়ডের মতো উদাহরণস্বরূপ) পরিচালনা করে, পাশাপাশি অগ্রণী এবং পিছনে বিসর্জনকারীকে পরিচালনা করে:

#include <string>
#include <vector>

void tokenize(std::string str, std::vector<string> &token_v){
    size_t start = str.find_first_not_of(DELIMITER), end=start;

    while (start != std::string::npos){
        // Find next occurence of delimiter
        end = str.find(DELIMITER, start);
        // Push back the token found into vector
        token_v.push_back(str.substr(start, end-start));
        // Skip all occurences of the delimiter to find new start
        start = str.find_first_not_of(DELIMITER, end);
    }
}

এটি সরাসরি চেষ্টা করে দেখুন !


3
এটি একটি ভাল তবে আমি মনে করি এটি একাধিক ডিলিমিটারগুলির সাথে সঠিকভাবে কাজ করার জন্য আপনার সন্ধানের পরিবর্তে find_first_of () ব্যবহার করা উচিত।

2
@ ব্যবহারকারী 755921 একাধিক ডিলিমিটারগুলি ফাইন্ড_ফেষ্ট_নোট_ফর দিয়ে শুরু করার অবস্থানটি খুঁজে পাওয়া যায় না।
শিক্ষানবিশ

16

পাইস্ট্রিং একটি ছোট লাইব্রেরি যা স্পাইথ পদ্ধতি সহ পাইথনের স্ট্রিং ফাংশনগুলির একটি গোছা প্রয়োগ করে:

#include <string>
#include <vector>
#include "pystring.h"

std::vector<std::string> chunks;
pystring::split("this string", chunks);

// also can specify a separator
pystring::split("this-string", chunks, "-");

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

বাহ, আপনি সিরিয়াসলি আমার দিনটি তৈরি করেছেন !! পাইস্ট্রিং সম্পর্কে জানতাম না। এটি আমার অনেক সময় বাঁচাতে চলেছে!
এ্যাক্রেস করুন

11

আমি অনুরূপ প্রশ্নের জন্য এই উত্তর পোস্ট।
চাকা পুনরুদ্ধার করবেন না। আমি বেশ কয়েকটি গ্রন্থাগার ব্যবহার করেছি এবং আমার কাছে আসা দ্রুত এবং সবচেয়ে নমনীয় হ'ল: সি ++ স্ট্রিং টুলকিট লাইব্রেরি

এখানে স্ট্যাকওভারফ্লোতে আমি যেখানে পোস্ট করেছি সেখানে এটি কীভাবে ব্যবহার করতে হয় তার উদাহরণ is

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

8

এই উদাহরণটি পরীক্ষা করুন। এটি আপনাকে সাহায্য করতে পারে ..

#include <iostream>
#include <sstream>

using namespace std;

int main ()
{
    string tmps;
    istringstream is ("the dellimiter is the space");
    while (is.good ()) {
        is >> tmps;
        cout << tmps << "\n";
    }
    return 0;
}

1
আমি করতামwhile ( is >> tmps ) { std::cout << tmps << "\n"; }
জর্ডিক্স

6

এমএফসি / এটিএল একটি খুব সুন্দর টোকনাইজার রয়েছে। এমএসডিএন থেকে:

CAtlString str( "%First Second#Third" );
CAtlString resToken;
int curPos= 0;

resToken= str.Tokenize("% #",curPos);
while (resToken != "")
{
   printf("Resulting token: %s\n", resToken);
   resToken= str.Tokenize("% #",curPos);
};

Output

Resulting Token: First
Resulting Token: Second
Resulting Token: Third

1
এই টোকেনাইজ () ফাংশনটি খালি টোকেনগুলি এড়িয়ে যাবে, উদাহরণস্বরূপ, যদি মূল স্ট্রিংয়ে "%%" টি স্ট্রিং থাকে, কোনও খালি টোকেন ফেরত পাওয়া যায় না। এটি এড়িয়ে গেছে
শেন

4

আপনি সি ব্যবহার করতে ইচ্ছুক হলে, আপনি স্ট্রটোক ফাংশনটি ব্যবহার করতে পারেন । মাল্টি-থ্রেডিং ইস্যুগুলি ব্যবহার করার সময় আপনার মনোযোগ দেওয়া উচিত।


3
নোট করুন যে স্ট্রটোক আপনি যে স্ট্রিংটি পরীক্ষা করছেন তা সংশোধন করে, তাই আপনি অনুলিপি চর * স্ট্রিংগুলিতে অনুলিপি তৈরি না করে ব্যবহার করতে পারবেন না।
গ্রিম পেরো

9
মাল্টিথ্রেডিং ইস্যুটি হ'ল স্ট্রটোক এটি কোথায় রয়েছে তা ট্র্যাক রাখতে বিশ্বব্যাপী পরিবর্তনশীল ব্যবহার করে, সুতরাং আপনার যদি দুটি থ্রেড থাকে যা প্রতিটি স্ট্রোটোক ব্যবহার করেন, আপনি অপরিবর্তিত আচরণ পাবেন।
জনএমসিজি

@ জনএমসিজি বা কেবল ব্যবহার করুন strtok_sযা মূলত strtokসুস্পষ্ট রাষ্ট্রীয় পাসের সাথে হয়।
ম্যাথিয়াস

4

সাধারণ স্টাফের জন্য আমি কেবল নিম্নলিখিতটি ব্যবহার করি:

unsigned TokenizeString(const std::string& i_source,
                        const std::string& i_seperators,
                        bool i_discard_empty_tokens,
                        std::vector<std::string>& o_tokens)
{
    unsigned prev_pos = 0;
    unsigned pos = 0;
    unsigned number_of_tokens = 0;
    o_tokens.clear();
    pos = i_source.find_first_of(i_seperators, pos);
    while (pos != std::string::npos)
    {
        std::string token = i_source.substr(prev_pos, pos - prev_pos);
        if (!i_discard_empty_tokens || token != "")
        {
            o_tokens.push_back(i_source.substr(prev_pos, pos - prev_pos));
            number_of_tokens++;
        }

        pos++;
        prev_pos = pos;
        pos = i_source.find_first_of(i_seperators, pos);
    }

    if (prev_pos < i_source.length())
    {
        o_tokens.push_back(i_source.substr(prev_pos));
        number_of_tokens++;
    }

    return number_of_tokens;
}

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


4

আপনি কেবল একটি নিয়মিত এক্সপ্রেশন লাইব্রেরি ব্যবহার করতে পারেন এবং নিয়মিত এক্সপ্রেশন ব্যবহার করে এটি সমাধান করতে পারেন।

এক্সপ্রেশন (\ ডাব্লু +) এবং \ 1 (বা নিয়মিত এক্সপ্রেশনগুলির গ্রন্থাগার বাস্তবায়নের উপর নির্ভর করে $ 1) এর পরিবর্তনশীল ব্যবহার করুন।


রেজেক্সের পরামর্শের জন্য +1, আপনার যদি ওয়ার্প স্পিডের প্রয়োজন না হয় তবে এটি সর্বাধিক নমনীয় সমাধান, এখনও সর্বত্র সমর্থিত নয় তবে সময় যত যায় তত কম গুরুত্বপূর্ণ হয়ে উঠবে।
ওডিনথনার্ড

আমার কাছ থেকে +1, কেবল সি ++ 11 এ <রিজেক্স> চেষ্টা করেছেন। এত সহজ এবং মার্জিত
স্টাহলরাট

4

অনেক অতিরিক্ত জটিল পরামর্শ এখানে। এই সহজ স্ট্যান্ডিং :: স্ট্রিং সমাধানটি ব্যবহার করে দেখুন:

using namespace std;

string someText = ...

string::size_type tokenOff = 0, sepOff = tokenOff;
while (sepOff != string::npos)
{
    sepOff = someText.find(' ', sepOff);
    string::size_type tokenLen = (sepOff == string::npos) ? sepOff : sepOff++ - tokenOff;
    string token = someText.substr(tokenOff, tokenLen);
    if (!token.empty())
        /* do something with token */;
    tokenOff = sepOff;
}

4

আমি ভেবেছিলাম >>স্ট্রিং স্ট্রিমগুলির অপারেটর এটি ছিল:

string word; sin >> word;

1
একটি খারাপ (খুব সাধারণ) উদাহরণ দেওয়ার জন্য আমার দোষ। আমি যতদূর জানি, এটি কেবল তখনই কাজ করে যখন আপনার ডিলিমিটারটি সাদা স্থান হয়।
বিল

4

অ্যাডাম পিয়ার্সের উত্তরটি হ'ল একটি হাতের কাঁটা টোকেনাইজার সরবরাহ করে const char*। পুনরাবৃত্তকারীদের সাথে এটি করা আরও কিছুটা সমস্যাযুক্ত কারণ কোনও stringপ্রান্তের পুনরাবৃত্তিকে বাড়ানো অপরিজ্ঞাত । এটি বলেছিল, প্রদত্ত string str{ "The quick brown fox" }আমরা অবশ্যই এটি অর্জন করতে পারি:

auto start = find(cbegin(str), cend(str), ' ');
vector<string> tokens{ string(cbegin(str), start) };

while (start != cend(str)) {
    const auto finish = find(++start, cend(str), ' ');

    tokens.push_back(string(start, finish));
    start = finish;
}

Live Example


যদি আপনি স্ট্যান্ডার্ড কার্যকারিতাটি ব্যবহার করে বিমূর্ত জটিলতার সন্ধান করে থাকেন, যেমন অন ​​ফ্রন্টের পরামর্শ অনুসারে strtok একটি সহজ বিকল্প:

vector<string> tokens;

for (auto i = strtok(data(str), " "); i != nullptr; i = strtok(nullptr, " ")) tokens.push_back(i);

যদি আপনার সি ++ 17 এ অ্যাক্সেস না থাকে তবে আপনাকে data(str)এই উদাহরণ হিসাবে যেমন বিকল্প করতে হবে : http://ideone.com/8kAGoa

উদাহরণে প্রদর্শিত না হলেও strtokপ্রতিটি টোকেনের জন্য একই ডিলিমিটার ব্যবহার করার দরকার নেই। যদিও এই সুবিধার পাশাপাশি, বেশ কয়েকটি ত্রুটি রয়েছে:

  1. strtokএকসাথে একাধিকটিতে ব্যবহার করা যাবে না strings: হয় nullptrবর্তমানের টোকানাইজিং চালিয়ে যেতে একটি অবশ্যই পাস করতে হবে stringঅথবা একটি নতুন char*টোকেনাইজ পাস করতে হবে (এমন কিছু মানহীন বাস্তবায়ন রয়েছে যা এটি সমর্থন করে যেমন, যেমন strtok_s:)
  2. একই কারণে strtokএকাধিক থ্রেডে একসাথে ব্যবহার করা যাবে না (এটি তবে বাস্তবায়িত সংজ্ঞায়িত হতে পারে, উদাহরণস্বরূপ: ভিজ্যুয়াল স্টুডিওর বাস্তবায়ন থ্রেড নিরাপদ )
  3. কলিংটি এটি যে অপারেটিং চলছে তা strtokসংশোধন stringকরে, সুতরাং এটি const stringএস, const char*গুলি, বা আক্ষরিক স্ট্রিংগুলিতে ব্যবহার করা যাবে না , এর সাথে টোকনাইজ strtokকরতে বা stringযার বিষয়বস্তু সংরক্ষণ করা দরকার তার সাথে কাজ করতে, strঅনুলিপি করতে হবে, তারপরে অনুলিপিটি তৈরি করা যেতে পারে চালিত করা

split_viewঅ-ধ্বংসাত্মক পদ্ধতিতে আমাদের টোকানাইজ স্ট্রিং সরবরাহ করে: https://topanswers.xyz/cplusplus?q=749#a874


পূর্ববর্তী পদ্ধতিগুলি টোকেনযুক্ত তৈরি করতে পারে না vector স্থানে , অর্থ্যাৎ তারা কোনও সাহায্যকারী ফাংশনে বিমূর্ত না করে তারা আরম্ভ করতে পারে না const vector<string> tokens। যে কার্যকারিতা এবং যে কোনও সাদা-স্থান ডিলিমিটার গ্রহণ করার ক্ষমতা একটি ব্যবহার করে ব্যবহার করা যেতে পারে istream_iterator। উদাহরণস্বরূপ দেওয়া: const string str{ "The quick \tbrown \nfox" }আমরা এটি করতে পারি:

istringstream is{ str };
const vector<string> tokens{ istream_iterator<string>(is), istream_iterator<string>() };

Live Example

istringstreamএই বিকল্পের জন্য প্রয়োজনীয় নির্মাণের পূর্ববর্তী 2 টি বিকল্পের তুলনায় অনেক বেশি ব্যয় রয়েছে, তবে এই ব্যয় সাধারণত stringবরাদ্দের ব্যয়ে লুকানো থাকে ।


উপরের বিকল্পগুলির মধ্যে কোনওটি যদি আপনার টোকেনাইজেশন প্রয়োজনের জন্য যথেষ্ট নমনীয় হয় না তবে সর্বাধিক নমনীয় বিকল্পটি হ'ল একটি regex_token_iterator অবশ্যই এই নমনীয়তার সাথে অবশ্যই আরও বেশি হয় তবে এটি সম্ভবত এটির মধ্যে লুকানো থাকেstring বরাদ্দ ব্যয়ের । উদাহরণস্বরূপ বলুন যে আমরা নীচের ইনপুটটি দিয়ে নিখরচায়িত অবিবাহিত কমাগুলির উপর ভিত্তি করে টোকনাইজ করতে চাই, সাদা স্থানও খাচ্ছি: const string str{ "The ,qu\\,ick ,\tbrown, fox" }আমরা এটি করতে পারি:

const regex re{ "\\s*((?:[^\\\\,]|\\\\.)*?)\\s*(?:,|$)" };
const vector<string> tokens{ sregex_token_iterator(cbegin(str), cend(str), re, 1), sregex_token_iterator() };

Live Example


strtok_sসি 11 মান, উপায় দ্বারা। strtok_rএকটি POSIX2001 মান। এই উভয়ের মধ্যেই strtokবেশিরভাগ প্ল্যাটফর্মগুলির জন্য একটি স্ট্যান্ডার্ড পুনরায় প্রবেশের সংস্করণ রয়েছে ।
অ্যান্ডন এম। কোলেম্যান

@ AndonM.Coleman তবে এটি একটি সি ++ প্রশ্ন এবং সি ++ এ #include <cstring>কেবলমাত্র c99 সংস্করণ অন্তর্ভুক্ত strtok। সুতরাং আমার ধারণাটি হ'ল আপনি strtokএক্সটেনশনের নির্দিষ্ট প্রাপ্যতা কার্যকরভাবে প্রদর্শন করে এই মন্তব্যটি সমর্থনকারী উপাদান হিসাবে সরবরাহ করছেন ?
জোনাথন মে

1
কেবল যে এটি মান-হিসাবে না অন্যথায় বিশ্বাস হতে পারে। strtok_sসি 11 এবং মাইক্রোসফ্ট এর সি রানটাইমের একক এক্সটেনশন হিসাবে উভয়ই সরবরাহ করেছেন। মাইক্রোসফ্টের _sফাংশনগুলি সি স্ট্যান্ডার্ড হয়ে উঠেছে এখানে ইতিহাসের একটি কৌতূহলজনক বিষয় রয়েছে ।
অ্যান্ডন এম। কোলেম্যান

@ অ্যান্ডন.কোলম্যান ঠিক আছে, আমি আপনার সাথে আছি। স্পষ্টতই যদি এটি সি 11 স্ট্যান্ডার্ডে থাকে তবে ইন্টারফেস এবং প্রয়োগের ক্ষেত্রে বাধা রয়েছে যা প্ল্যাটফর্মের বাইরে স্বতন্ত্র আচরণের প্রয়োজন। এখন কেবলমাত্র সমস্যাটি নিশ্চিত করে দেওয়া হচ্ছে যে সি 11 ফাংশনটি আমাদের কাছে প্ল্যাটফর্ম জুড়ে উপলব্ধ। আশা করি সি 11 স্ট্যান্ডার্ড এমন কিছু হবে যা সি ++ 17 বা সি ++ 20 টি বাছাইয়ের জন্য চয়ন করে।
জোনাথন মে

3

আমি জানি এই প্রশ্নের উত্তর ইতিমধ্যে দেওয়া হয়েছে তবে আমি অবদান রাখতে চাই। হতে পারে আমার সমাধানটি কিছুটা সহজ তবে এটিই আমি এনেছি:

vector<string> get_words(string const& text, string const& separator)
{
    vector<string> result;
    string tmp = text;

    size_t first_pos = 0;
    size_t second_pos = tmp.find(separator);

    while (second_pos != string::npos)
    {
        if (first_pos != second_pos)
        {
            string word = tmp.substr(first_pos, second_pos - first_pos);
            result.push_back(word);
        }
        tmp = tmp.substr(second_pos + separator.length());
        second_pos = tmp.find(separator);
    }

    result.push_back(tmp);

    return result;
}

আমার কোডে কোনও কিছুর আরও ভাল পন্থা আছে বা কিছু ভুল হলে দয়া করে মন্তব্য করুন।

আপডেট: জেনেরিক বিভাজক যুক্ত


ভিড় থেকে আপনার সমাধান ব্যবহার করা হয়েছে :) আমি কি কোনও বিভাজক যুক্ত করতে আপনার কোডটি সংশোধন করতে পারি?
জ্যাক

1
@ জ্যাক খুশি হলেন যে আপনি এটি পছন্দ করেছেন এবং আপনি এটি পরিবর্তন করতে পারবেন ... আমার উত্তরে কেবল একটি সাহসী আপডেট বিভাগ যুক্ত করুন ...
নটক্র্যাকার

2

এখানে এমন একটি দৃষ্টিভঙ্গি যা আপনাকে খালি টোকেন অন্তর্ভুক্ত (স্টার্সপের মতো) বা বাদ দেওয়া (স্ট্রটোকের মতো) নিয়ন্ত্রণ করতে দেয়।

#include <string.h> // for strchr and strlen

/*
 * want_empty_tokens==true  : include empty tokens, like strsep()
 * want_empty_tokens==false : exclude empty tokens, like strtok()
 */
std::vector<std::string> tokenize(const char* src,
                                  char delim,
                                  bool want_empty_tokens)
{
  std::vector<std::string> tokens;

  if (src and *src != '\0') // defensive
    while( true )  {
      const char* d = strchr(src, delim);
      size_t len = (d)? d-src : strlen(src);

      if (len or want_empty_tokens)
        tokens.push_back( std::string(src, len) ); // capture token

      if (d) src += len+1; else break;
    }

  return tokens;
}

2

আমার কাছে বেআইনি বলে মনে হচ্ছে যে আমরা সকলেই এখানে গতিশীল সচেতন নার্দের সাথে SO তে প্রত্যেকেই এমন সংস্করণ উপস্থাপন করতে পারি নি যা ডিলিমিটারের জন্য একটি সংকলন সময় উত্পন্ন লুক আপ টেবিল ব্যবহার করে (উদাহরণস্বরূপ আরও নীচে বাস্তবায়ন করা)। সন্ধানী টেবিল এবং পুনরুক্তি ব্যবহারকারীর দক্ষতাতে স্টাড :: রেজেক্সকে পরাজিত করা উচিত, যদি আপনার রেজেক্সকে বীট করার প্রয়োজন না হয় তবে কেবল এটি ব্যবহার করুন, এর মানটি সি ++ 11 এবং সুপার নমনীয়।

কেউ কেউ ইতিমধ্যে রেগেক্সের পরামর্শ দিয়েছেন তবে এখানে নুবসের জন্য একটি প্যাকেজড উদাহরণ যা ওপি প্রত্যাশা করে ঠিক এমনটি করা উচিত:

std::vector<std::string> split(std::string::const_iterator it, std::string::const_iterator end, std::regex e = std::regex{"\\w+"}){
    std::smatch m{};
    std::vector<std::string> ret{};
    while (std::regex_search (it,end,m,e)) {
        ret.emplace_back(m.str());              
        std::advance(it, m.position() + m.length()); //next start position = match position + match length
    }
    return ret;
}
std::vector<std::string> split(const std::string &s, std::regex e = std::regex{"\\w+"}){  //comfort version calls flexible version
    return split(s.cbegin(), s.cend(), std::move(e));
}
int main ()
{
    std::string str {"Some people, excluding those present, have been compile time constants - since puberty."};
    auto v = split(str);
    for(const auto&s:v){
        std::cout << s << std::endl;
    }
    std::cout << "crazy version:" << std::endl;
    v = split(str, std::regex{"[^e]+"});  //using e as delim shows flexibility
    for(const auto&s:v){
        std::cout << s << std::endl;
    }
    return 0;
}

আমাদের যদি দ্রুত হতে হবে এবং সমস্ত চরিত্র 8 টি বিট হতে হবে এমন প্রতিবন্ধকতাটি স্বীকার করতে হবে তবে আমরা রূপক ব্যবহার করে সংকলনের সময় টেবিল তৈরি করতে পারি:

template<bool...> struct BoolSequence{};        //just here to hold bools
template<char...> struct CharSequence{};        //just here to hold chars
template<typename T, char C> struct Contains;   //generic
template<char First, char... Cs, char Match>    //not first specialization
struct Contains<CharSequence<First, Cs...>,Match> :
    Contains<CharSequence<Cs...>, Match>{};     //strip first and increase index
template<char First, char... Cs>                //is first specialization
struct Contains<CharSequence<First, Cs...>,First>: std::true_type {}; 
template<char Match>                            //not found specialization
struct Contains<CharSequence<>,Match>: std::false_type{};

template<int I, typename T, typename U> 
struct MakeSequence;                            //generic
template<int I, bool... Bs, typename U> 
struct MakeSequence<I,BoolSequence<Bs...>, U>:  //not last
    MakeSequence<I-1, BoolSequence<Contains<U,I-1>::value,Bs...>, U>{};
template<bool... Bs, typename U> 
struct MakeSequence<0,BoolSequence<Bs...>,U>{   //last  
    using Type = BoolSequence<Bs...>;
};
template<typename T> struct BoolASCIITable;
template<bool... Bs> struct BoolASCIITable<BoolSequence<Bs...>>{
    /* could be made constexpr but not yet supported by MSVC */
    static bool isDelim(const char c){
        static const bool table[256] = {Bs...};
        return table[static_cast<int>(c)];
    }   
};
using Delims = CharSequence<'.',',',' ',':','\n'>;  //list your custom delimiters here
using Table = BoolASCIITable<typename MakeSequence<256,BoolSequence<>,Delims>::Type>;

এটির জায়গায় getNextTokenফাংশন তৈরি করা সহজ:

template<typename T_It>
std::pair<T_It,T_It> getNextToken(T_It begin,T_It end){
    begin = std::find_if(begin,end,std::not1(Table{})); //find first non delim or end
    auto second = std::find_if(begin,end,Table{});      //find first delim or end
    return std::make_pair(begin,second);
}

এটি ব্যবহার করাও সহজ:

int main() {
    std::string s{"Some people, excluding those present, have been compile time constants - since puberty."};
    auto it = std::begin(s);
    auto end = std::end(s);
    while(it != std::end(s)){
        auto token = getNextToken(it,end);
        std::cout << std::string(token.first,token.second) << std::endl;
        it = token.second;
    }
    return 0;
}

এখানে একটি সরাসরি উদাহরণ: http://ideone.com/GKtkLQ


1
স্ট্রিং ডিলিমিটার দিয়ে টোকেনাইজ করা কি সম্ভব?
গ্যালিগেটর

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

1

আপনি boost :: Make_find_iterator এর সুবিধা নিতে পারেন। এর মতো কিছু:

template<typename CH>
inline vector< basic_string<CH> > tokenize(
    const basic_string<CH> &Input,
    const basic_string<CH> &Delimiter,
    bool remove_empty_token
    ) {

    typedef typename basic_string<CH>::const_iterator string_iterator_t;
    typedef boost::find_iterator< string_iterator_t > string_find_iterator_t;

    vector< basic_string<CH> > Result;
    string_iterator_t it = Input.begin();
    string_iterator_t it_end = Input.end();
    for(string_find_iterator_t i = boost::make_find_iterator(Input, boost::first_finder(Delimiter, boost::is_equal()));
        i != string_find_iterator_t();
        ++i) {
        if(remove_empty_token){
            if(it != i->begin())
                Result.push_back(basic_string<CH>(it,i->begin()));
        }
        else
            Result.push_back(basic_string<CH>(it,i->begin()));
        it = i->end();
    }
    if(it != it_end)
        Result.push_back(basic_string<CH>(it,it_end));

    return Result;
}

1

হোয়াইটস্পেসে স্ট্রিং বিভক্ত করার জন্য স্ট্রিং-টোকেনাইজারগুলির আমার সুইস আর্মি নাইফ, একক এবং ডাবল-কোট মোড়ানো স্ট্রিংগুলির জন্য অ্যাকাউন্টিং করার পাশাপাশি ফলাফলগুলি থেকে এই অক্ষরগুলি কেটে ফেলার জন্য। আমি বেশিরভাগ কোড-স্নিপেট তৈরি করতে RegexBuddy 4.x ব্যবহার করেছি , তবে আমি স্ট্রিপিং কোট এবং অন্যান্য কয়েকটি বিষয় কাস্টম হ্যান্ডলিং যুক্ত করেছি।

#include <string>
#include <locale>
#include <regex>

std::vector<std::wstring> tokenize_string(std::wstring string_to_tokenize) {
    std::vector<std::wstring> tokens;

    std::wregex re(LR"(("[^"]*"|'[^']*'|[^"' ]+))", std::regex_constants::collate);

    std::wsregex_iterator next( string_to_tokenize.begin(),
                                string_to_tokenize.end(),
                                re,
                                std::regex_constants::match_not_null );

    std::wsregex_iterator end;
    const wchar_t single_quote = L'\'';
    const wchar_t double_quote = L'\"';
    while ( next != end ) {
        std::wsmatch match = *next;
        const std::wstring token = match.str( 0 );
        next++;

        if (token.length() > 2 && (token.front() == double_quote || token.front() == single_quote))
            tokens.emplace_back( std::wstring(token.begin()+1, token.begin()+token.length()-1) );
        else
            tokens.emplace_back(token);
    }
    return tokens;
}

1
(নিচে) ভোটগুলি উপভোগীদের মতোই গঠনমূলক হতে পারে তবে আপনি কেন মন্তব্য সম্পর্কে মন্তব্য করবেন না তা নয় ...
kayleeFrye_onDeck

1
আমি আপনাকে বের করে দিয়েছি তবে এটি এমন হতে পারে কারণ
কোডারটি

ধন্যবাদ @ ম্যাটশু! এটি কি রেজেক্স বিভাগগুলি এটিকে ভয়ঙ্কর করে তোলে বা অন্য কিছু করে?
kayleeFrye_onDeck

0

টোকেনাইজ করার জন্য যদি ইনপুট স্ট্রিংয়ের সর্বাধিক দৈর্ঘ্য জানা থাকে তবে যে কেউ এটি ব্যবহার করতে পারে এবং খুব দ্রুত সংস্করণটি প্রয়োগ করতে পারে। আমি নীচের মূল ধারণাটি স্কেচ করছি, যা স্ট্রোকক () এবং "প্রত্যয় অ্যারে" -ডাটা কাঠামোতে জন বেন্টলির "প্রোগ্রামিং পার্লস" ২ য় সংস্করণ, অধ্যায় 15 বর্ণিত হয়েছে দ্বারা অনুপ্রাণিত হয়েছিল। এই ক্ষেত্রে সি ++ শ্রেণি কেবল কিছু সংস্থা এবং সুবিধা দেয় ব্যবহার. টোকেনের শীর্ষস্থানীয় এবং পিছনের সাদা অংশের অক্ষরগুলি অপসারণের জন্য প্রদর্শিত বাস্তবায়নটি সহজেই বাড়ানো যেতে পারে।

মূলত কেউ স্ট্রিং-টার্মিনেটিং '\ 0'-অক্ষরের সাথে বিভাজনকারী অক্ষরগুলি প্রতিস্থাপন করতে পারে এবং পরিবর্তিত স্ট্রিং সহ টোকেনগুলিতে পয়েন্টার সেট করতে পারে। চূড়ান্ত ক্ষেত্রে যখন স্ট্রিংটিতে কেবল পৃথক পৃথক থাকে, তখন স্ট্রিং-দৈর্ঘ্য প্লাস 1 এর ফলে খালি টোকেন হয়। স্ট্রিংটি সংশোধন করার জন্য সদৃশ করা ব্যবহারিক

শিরোনাম ফাইল:

class TextLineSplitter
{
public:

    TextLineSplitter( const size_t max_line_len );

    ~TextLineSplitter();

    void            SplitLine( const char *line,
                               const char sep_char = ',',
                             );

    inline size_t   NumTokens( void ) const
    {
        return mNumTokens;
    }

    const char *    GetToken( const size_t token_idx ) const
    {
        assert( token_idx < mNumTokens );
        return mTokens[ token_idx ];
    }

private:
    const size_t    mStorageSize;

    char           *mBuff;
    char          **mTokens;
    size_t          mNumTokens;

    inline void     ResetContent( void )
    {
        memset( mBuff, 0, mStorageSize );
        // mark all items as empty:
        memset( mTokens, 0, mStorageSize * sizeof( char* ) );
        // reset counter for found items:
        mNumTokens = 0L;
    }
};

বাস্তবায়ন ফাইল:

TextLineSplitter::TextLineSplitter( const size_t max_line_len ):
    mStorageSize ( max_line_len + 1L )
{
    // allocate memory
    mBuff   = new char  [ mStorageSize ];
    mTokens = new char* [ mStorageSize ];

    ResetContent();
}

TextLineSplitter::~TextLineSplitter()
{
    delete [] mBuff;
    delete [] mTokens;
}


void TextLineSplitter::SplitLine( const char *line,
                                  const char sep_char   /* = ',' */,
                                )
{
    assert( sep_char != '\0' );

    ResetContent();
    strncpy( mBuff, line, mMaxLineLen );

    size_t idx       = 0L; // running index for characters

    do
    {
        assert( idx < mStorageSize );

        const char chr = line[ idx ]; // retrieve current character

        if( mTokens[ mNumTokens ] == NULL )
        {
            mTokens[ mNumTokens ] = &mBuff[ idx ];
        } // if

        if( chr == sep_char || chr == '\0' )
        { // item or line finished
            // overwrite separator with a 0-terminating character:
            mBuff[ idx ] = '\0';
            // count-up items:
            mNumTokens ++;
        } // if

    } while( line[ idx++ ] );
}

ব্যবহারের একটি দৃশ্য হবে:

// create an instance capable of splitting strings up to 1000 chars long:
TextLineSplitter spl( 1000 );
spl.SplitLine( "Item1,,Item2,Item3" );
for( size_t i = 0; i < spl.NumTokens(); i++ )
{
    printf( "%s\n", spl.GetToken( i ) );
}

আউটপুট:

Item1

Item2
Item3

0

boost::tokenizerআপনার বন্ধু, তবে উত্তরাধিকার / প্রকারের পরিবর্তে wstring/ ব্যবহার করে আন্তর্জাতিককরণের (আই 18 এন) ইস্যুগুলির সাথে আপনার কোডকে পোর্টেবল তৈরি করার বিষয়টি বিবেচনা করুন ।wchar_tstringchar

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

using namespace std;
using namespace boost;

typedef tokenizer<char_separator<wchar_t>,
                  wstring::const_iterator, wstring> Tok;

int main()
{
  wstring s;
  while (getline(wcin, s)) {
    char_separator<wchar_t> sep(L" "); // list of separator characters
    Tok tok(s, sep);
    for (Tok::iterator beg = tok.begin(); beg != tok.end(); ++beg) {
      wcout << *beg << L"\t"; // output (or store in vector)
    }
    wcout << L"\n";
  }
  return 0;
}

"উত্তরাধিকার" অবশ্যই স্পষ্টভাবে সঠিক নয় এবং wchar_tএটি একটি ভয়াবহ বাস্তবায়ন নির্ভর ধরন যা একেবারেই প্রয়োজনীয় না হলে কারও ব্যবহার করা উচিত নয়।
কফিঅ্যান্ডকোড

Wchar_t এর ব্যবহার কোনওভাবেই কোনও আই 18 এন সমস্যা সমাধান করে না solve আপনি সমস্যাটি সমাধান করতে এনকোডিংগুলি ব্যবহার করেন। আপনি যদি একটি ডিলিমিটার দ্বারা একটি স্ট্রিংকে বিভক্ত করে থাকেন তবে বোঝা যায় যে স্ট্রিমের ভিতরে কোনও টোকেনের এনকোডড সামগ্রীগুলির সাথে ডিলিমিটারটি সংঘর্ষে না। এস্কেপিংয়ের প্রয়োজন হতে পারে ইত্যাদি w wchar_t এটির কোনও যাদুকরী সমাধান নয়।
yonil

0

সাধারণ সি ++ কোড (স্ট্যান্ডার্ড সি ++ 98), একাধিক ডিলিমিটার গ্রহণ করে (একটি স্ট্যান্ড :: স্ট্রিংয়ে নির্দিষ্ট), কেবল ভেক্টর, স্ট্রিং এবং পুনরুক্তি ব্যবহার করে।

#include <iostream>
#include <vector>
#include <string>
#include <stdexcept> 

std::vector<std::string> 
split(const std::string& str, const std::string& delim){
    std::vector<std::string> result;
    if (str.empty())
        throw std::runtime_error("Can not tokenize an empty string!");
    std::string::const_iterator begin, str_it;
    begin = str_it = str.begin(); 
    do {
        while (delim.find(*str_it) == std::string::npos && str_it != str.end())
            str_it++; // find the position of the first delimiter in str
        std::string token = std::string(begin, str_it); // grab the token
        if (!token.empty()) // empty token only when str starts with a delimiter
            result.push_back(token); // push the token into a vector<string>
        while (delim.find(*str_it) != std::string::npos && str_it != str.end())
            str_it++; // ignore the additional consecutive delimiters
        begin = str_it; // process the remaining tokens
        } while (str_it != str.end());
    return result;
}

int main() {
    std::string test_string = ".this is.a.../.simple;;test;;;END";
    std::string delim = "; ./"; // string containing the delimiters
    std::vector<std::string> tokens = split(test_string, delim);           
    for (std::vector<std::string>::const_iterator it = tokens.begin(); 
        it != tokens.end(); it++)
            std::cout << *it << std::endl;
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.