এমন কি একটি সি ++ স্ট্যান্ডার্ড টেম্পলেট লাইব্রেরি ক্লাস যা দক্ষ স্ট্রিং কনটেনটেশন কার্যকারিতা সরবরাহ করে, সি # এর স্ট্রিংবিল্ডার বা জাভার স্ট্রিংবফারের মতো ?
এমন কি একটি সি ++ স্ট্যান্ডার্ড টেম্পলেট লাইব্রেরি ক্লাস যা দক্ষ স্ট্রিং কনটেনটেশন কার্যকারিতা সরবরাহ করে, সি # এর স্ট্রিংবিল্ডার বা জাভার স্ট্রিংবফারের মতো ?
উত্তর:
দ্রষ্টব্য এই উত্তরটি সম্প্রতি কিছু মনোযোগ পেয়েছে। আমি এটিকে সমাধান হিসাবে পরামর্শ দিচ্ছি না (এটি একটি সমাধান যা আমি অতীতে দেখেছি, এসটিএলের আগে)। এটি একটি আকর্ষণীয় দৃষ্টিভঙ্গি এবং কেবলমাত্র আপনার কোডটি প্রোফাইলের পরে প্রয়োগ করা উচিত std::string
বা আপনি std::stringstream
যদি আবিষ্কার করেন যে এটি একটি উন্নতি করে।
আমি সাধারণত std::string
বা হয় ব্যবহার std::stringstream
। এগুলি নিয়ে আমার কোনও সমস্যা হয়নি। আমি যদি আগে স্ট্রিংয়ের রুক্ষ আকার জানতাম তবে আমি প্রথমে কিছু কক্ষ সংরক্ষণ করি।
আমি অন্যান্য লোককে তাদের অতীত অতীতে নিজেরাই অনুকূলিত স্ট্রিং বিল্ডার তৈরি করতে দেখেছি।
class StringBuilder {
private:
std::string main;
std::string scratch;
const std::string::size_type ScratchSize = 1024; // or some other arbitrary number
public:
StringBuilder & append(const std::string & str) {
scratch.append(str);
if (scratch.size() > ScratchSize) {
main.append(scratch);
scratch.resize(0);
}
return *this;
}
const std::string & str() {
if (scratch.size() > 0) {
main.append(scratch);
scratch.resize(0);
}
return main;
}
};
এটি দুটি স্ট্রিংয়ের বেশিরভাগ স্ট্রিংয়ের জন্য এবং অন্যটি সংক্ষিপ্ত স্ট্রিংগুলি সংক্ষেপণের জন্য স্ক্র্যাচ অঞ্চল হিসাবে ব্যবহার করে। এটি একটি ছোট স্ট্রিংয়ের মধ্যে সংক্ষিপ্ত সংযোজন ক্রিয়াকলাপগুলিকে ব্যাচ করে তারপরে এটি অনুকূল করে তোলে মূল স্ট্রিংয়ের সাথে এটি যুক্ত করে, ফলে এটি বড় হওয়ার সাথে সাথে মূল স্ট্রিংয়ে প্রয়োজনীয় পুনর্বিবেচনার সংখ্যা হ্রাস করে।
আমার সাথে std::string
বা এই কৌশলটি প্রয়োজন হয়নি std::stringstream
। আমার মনে হয় এটি স্ট্যান্ড :: স্ট্রিংয়ের আগে একটি তৃতীয় পক্ষের স্ট্রিং লাইব্রেরি সহ ব্যবহৃত হয়েছিল, এটি ছিল অনেক আগে। আপনি যদি এই প্রোফাইলের মতো কৌশল গ্রহণ করেন তবে প্রথমে আপনার অ্যাপ্লিকেশনটি।
scratch
স্ট্রিংটি এখানে সত্যিই কিছু সম্পাদন করে। মূল স্ট্রিংয়ের পুনঃনির্ধারণের সংখ্যাটি মূলত এটি চূড়ান্ত আকারের একটি ফাংশন হতে চলেছে, সংযোজন পরিচালনের সংখ্যা নয়, যদি না string
বাস্তবায়নটি খুব কম হয় (যেমন, তাত্পর্যপূর্ণ বৃদ্ধি ব্যবহার করে না)। সুতরাং "ব্যাচিং" সাহায্য append
করে না কারণ অন্তর্নিহিত একবার string
বড় হয়ে গেলে এটি কেবল মাঝে মধ্যেই দুভাবেই বাড়বে। এর এটি অপ্রয়োজনীয় কপি অপারেশন একটি গুচ্ছ যোগ করে, ও মে উপরে আরো reallocations (অত: পর কল new
/ delete
) যেহেতু আপনি একটি ছোট স্ট্রিং সংযোজন করা হয়।
str.reserve(1024);
যে এই জিনিসটির চেয়ে দ্রুততর হবে
সি ++ উপায়টি হল std :: স্ট্রিংস্ট্রিম বা কেবল সরল স্ট্রিং কনট্যাঙ্কেশন ব্যবহার করা । সি ++ স্ট্রিংগুলি পারস্পরিক পরিবর্তনযোগ্য তাই কনক্যাটেনেশনের পারফরম্যান্স বিবেচনার বিষয়টি কম উদ্বেগের বিষয়।
ফর্ম্যাট করার ক্ষেত্রে আপনি একই স্ট্রিমিংটিতে কোনও স্ট্রিমে একই রকম করতে পারেন তবে ভিন্ন উপায়ে করতে পারেনcout
। অথবা আপনি একটি দৃ strongly়ভাবে টাইপ করা ফান্টর ব্যবহার করতে পারেন যা এটি এনপ্যাপুলেট করে এবং একটি স্ট্রিং সরবরাহ করে interfaceএর জন্য ইন্টারফেসের মতো ফর্ম্যাট যেমন বুস্ট :: ফর্ম্যাট
StringBuilder
বিদ্যমান জাভা অপরিবর্তনীয় বেসিক স্ট্রিং ধরণের অদক্ষতা আবরণ । অন্য কথায় StringBuilder
প্যাচওয়ার্ক, তাই আমাদের খুশী হওয়া উচিত যে আমাদের সি ++ তে এই জাতীয় শ্রেণির দরকার নেই।
O(n)
সাধারণ হিসাবে শেষ হয় ।
std::string.append
ফাংশন একটি ভাল বিকল্প কারণ এটা ডেটার নানা রূপে গ্রহণ করে না নয়। আরও কার্যকর বিকল্প হ'ল ব্যবহার করা std::stringstream
; তাই ভালো:
#include <sstream>
// ...
std::stringstream ss;
//put arbitrary formatted data into the stream
ss << 4.5 << ", " << 4 << " whatever";
//convert the stream buffer into a string
std::string str = ss.str();
আপনি সহজভাবে স্ট্রিং স্ট্রিংয়ের জন্য .append () ব্যবহার করতে পারেন।
std::string s = "string1";
s.append("string2");
আমি মনে করি আপনি এমনকি করতে সক্ষম হতে পারে:
std::string s = "string1";
s += "string2";
সি # এর বিন্যাসকরণ ক্রিয়াকলাপ হিসাবে StringBuilder
, আমি বিশ্বাস করি snprintf
(বা sprintf
আপনি যদি বগি কোড লেখার ঝুঁকি নিতে চান ;-)) একটি অক্ষর অ্যারে রূপান্তর করুন এবং স্ট্রিংয়ে ফিরে রূপান্তর একমাত্র বিকল্প সম্পর্কে about
যেহেতু std::string
সি ++ তে পরিবর্তনযোগ্য আপনি এটি ব্যবহার করতে পারেন। এটি একটি += operator
এবং একটি append
ফাংশন আছে।
আপনার যদি সংখ্যার তথ্য সংযোজন করতে হয় তবে std::to_string
ফাংশনগুলি ব্যবহার করুন ।
আপনি যদি কোনও স্ট্রিংয়ে কোনও বস্তু সিরিয়াল করতে সক্ষম হয়ে থাকেন তবে আরও ক্লাসিকটি চাইলে std::stringstream
ক্লাসটি ব্যবহার করুন । তবে এটি আপনার নিজস্ব কাস্টম ক্লাসগুলির সাথে কাজ করার জন্য আপনার নিজের স্ট্রিমিং অপারেটর ফাংশনগুলি প্রয়োগ করতে হবে।
সি ++ এর জন্য একটি সুবিধাজনক স্ট্রিং বিল্ডার
আগে উত্তর দেওয়া অনেক লোকের মতো, std :: স্ট্রিংস্ট্রিম হল পছন্দের পদ্ধতি। এটি ভাল কাজ করে এবং প্রচুর রূপান্তর এবং ফর্ম্যাটিং বিকল্প রয়েছে। আইএমওতে এটির একটির অসুবিধাজনক ত্রুটি রয়েছে: আপনি এটি ওয়ান লাইনার বা এক্সপ্রেশন হিসাবে ব্যবহার করতে পারবেন না। আপনাকে সর্বদা লিখতে হবে:
std::stringstream ss;
ss << "my data " << 42;
std::string myString( ss.str() );
যা বেশ বিরক্তিকর, বিশেষত যখন আপনি কনস্ট্রাক্টরের স্ট্রিংগুলি শুরু করতে চান।
কারণটি হ'ল, ক) স্টাডি :: স্ট্রিংস্ট্রিম স্ট্যান্ড :: স্ট্রিং এবং বি তে কোনও রূপান্তর অপারেটর নেই) স্ট্রিং স্ট্রিমের অপারেটর << () এর স্ট্রিংস্ট্রিম রেফারেন্সটি ফেরত দেয় না, তবে একটি এসটিডি :: অস্ট্রি রেফারেন্স পরিবর্তে দেয় - যা স্ট্রিং স্ট্রিম হিসাবে আরও গণনা করা যাবে না।
সমাধানটি হল std :: স্ট্রিংস্ট্রিমকে ওভাররাইড করা এবং এটি আরও ভাল মিলে যাওয়া অপারেটরগুলি দেওয়া:
namespace NsStringBuilder {
template<typename T> class basic_stringstream : public std::basic_stringstream<T>
{
public:
basic_stringstream() {}
operator const std::basic_string<T> () const { return std::basic_stringstream<T>::str(); }
basic_stringstream<T>& operator<< (bool _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (char _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (signed char _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (unsigned char _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (short _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (unsigned short _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (int _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (unsigned int _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (long _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (unsigned long _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (long long _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (unsigned long long _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (float _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (double _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (long double _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (void* _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (std::streambuf* _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (std::ostream& (*_val)(std::ostream&)) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (std::ios& (*_val)(std::ios&)) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (std::ios_base& (*_val)(std::ios_base&)){ std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (const T* _val) { return static_cast<basic_stringstream<T>&>(std::operator << (*this,_val)); }
basic_stringstream<T>& operator<< (const std::basic_string<T>& _val) { return static_cast<basic_stringstream<T>&>(std::operator << (*this,_val.c_str())); }
};
typedef basic_stringstream<char> stringstream;
typedef basic_stringstream<wchar_t> wstringstream;
}
এটির সাহায্যে আপনি পছন্দ মতো জিনিস লিখতে পারেন
std::string myString( NsStringBuilder::stringstream() << "my data " << 42 )
এমনকি নির্মাণকারী মধ্যে।
আমাকে স্বীকার করতে হবে যে আমি পারফরম্যান্সটি পরিমাপ করিনি, যেহেতু আমি এটি এমন পরিবেশে ব্যবহার করি নি যা স্ট্রিং বিল্ডিংয়ের এখনও ভারী ব্যবহার করে, তবে আমি ধরে নিচ্ছি যে এটি স্ট্যান্ড :: স্ট্রিংস্ট্রিমের চেয়ে বেশি খারাপ হবে না, যেহেতু সবকিছু সম্পন্ন হয়েছে রেফারেন্সের মাধ্যমে (স্ট্রিংয়ে রূপান্তর ব্যতীত, তবে স্ট্যান্ড স্ট্রিং স্ট্রিম স্ট্রিমেও একটি অনুলিপি অপারেশন চালিয়ে যায়)
std::stringstream
দেখছি না যে এইভাবে আচরণ করে না।
দড়ি যদি গন্তব্য স্ট্রিং এর র্যান্ডম স্থানে বা একটি দীর্ঘ গৃহস্থালির কাজ সিকোয়েন্স জন্য সন্নিবেশ করতে / মুছুন স্ট্রিং আছে ধারক মূল্য হতে পারে। এসজিআই এর বাস্তবায়ন থেকে এখানে একটি উদাহরণ দেওয়া হল:
crope r(1000000, 'x'); // crope is rope<char>. wrope is rope<wchar_t>
// Builds a rope containing a million 'x's.
// Takes much less than a MB, since the
// different pieces are shared.
crope r2 = r + "abc" + r; // concatenation; takes on the order of 100s
// of machine instructions; fast
crope r3 = r2.substr(1000000, 3); // yields "abc"; fast.
crope r4 = r2.substr(1000000, 1000000); // also fast.
reverse(r2.mutable_begin(), r2.mutable_end());
// correct, but slow; may take a
// minute or more.
নিম্নলিখিতগুলির কারণে আমি নতুন কিছু যুক্ত করতে চেয়েছিলাম:
প্রথম প্রয়াসে আমি মারতে ব্যর্থ হয়েছি
std::ostringstream
এর operator<<
দক্ষতা, কিন্তু আরও প্রচেষ্টার সাহায্যে আমি একটি স্ট্রিংবিল্ডার তৈরি করতে সক্ষম হয়েছি যা কিছু ক্ষেত্রে দ্রুত।
আমি যখনই কোনও স্ট্রিং যুক্ত করি আমি কেবল এটির কোনও রেফারেন্স সঞ্চয় করি এবং মোট আকারের কাউন্টার বাড়িয়ে তুলি।
অবশেষে আমি এটি বাস্তবায়ন করার জন্য (হরর!) একটি অস্বচ্ছ বাফার (স্ট্যান্ড :: ভেক্টর <চার>) ব্যবহার করা:
বাইট জন্য []
সরানো স্ট্রিংগুলির জন্য (স্ট্রিংগুলি যুক্ত করা হয় std::move
)
std::string
বস্তুর পয়েন্টার (আমাদের মালিকানা রয়েছে)স্ট্রিং জন্য
std::string
বস্তু (কোন মালিকানা)একটি ছোট অপ্টিমাইজেশন রয়েছে, যদি সর্বশেষ stringোকানো স্ট্রিংটি মুভ করে দেওয়া হত, এটি নিখরচায় বাফার ব্যবহার না করে নিখরচায় তবে অব্যবহৃত বাইটগুলি পরীক্ষা করে এবং সেখানে আরও বাইট সংরক্ষণ করে (এটি কিছু স্মৃতি সঞ্চয় করতে পারে, এটি এটি এটিকে কিছুটা ধীর করে তোলে , সম্ভবত সিপিইউতেও নির্ভর করে এবং যেভাবেই হোক অতিরিক্ত সংরক্ষিত জায়গার সাথে স্ট্রিং দেখা বিরল)
এটি শেষ পর্যন্ত তুলনায় কিছুটা দ্রুত ছিল std::ostringstream
তবে এর কয়েকটি ডাউনসাইড রয়েছে:
ostringstream
উপসংহার? ব্যবহার
std::ostringstream
এটি ইতিমধ্যে বৃহত্তম বাধা স্থির করে যখন খনি বাস্তবায়নের সাথে গতিতে কয়েক% পয়েন্ট গ্যান করে তোলা ডাউনসাইডগুলির পক্ষে উপযুক্ত নয়।
std::ostringstream
।