স্ট্যান্ড :: স্ট্রিং ট্রিম করার সর্বোত্তম উপায় কী?


812

আমি বর্তমানে std::stringsআমার প্রোগ্রামগুলিতে সমস্ত রাইট ট্রিম করতে নিম্নলিখিত কোডটি ব্যবহার করছি :

std::string s;
s.erase(s.find_last_not_of(" \n\r\t")+1);

এটি দুর্দান্ত কাজ করে, তবে আমি ভাবছি যদি এমন কোনও শেষ-কেস থাকে যেখানে এটি ব্যর্থ হয়?

অবশ্যই, মার্জিত বিকল্পগুলির উত্তর এবং বাম-ট্রিম সমাধানটি স্বাগত।


549
এই প্রশ্নের উত্তরগুলি সি ++ স্ট্যান্ডার্ড লাইব্রেরির অভাবে কীভাবে হয় তার একটি প্রমাণ are
ইডান কে

83
@ ইদানকে এবং এটি এখনও সি ++ 11 এ এই ফাংশনটি নেই।
কোয়ান্টাম

44
@ ইদানকে: দুর্দান্ত, তাই না! আমাদের এখন যে সমস্ত প্রতিযোগিতামূলক বিকল্প রয়েছে তা দেখুন, " আমাদের কীভাবে এটি করতে হবে " এমন একক ব্যক্তির ধারণার দ্বারা নিরবচ্ছিন্ন !
30:40

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

27
আপনি প্রশ্ন করতে পারেন কেন ট্রিমিং ফাংশনগুলি std::stringশ্রেণিতে অন্তর্নির্মিত হয় না , যখন এটি এর মতো ফাংশনগুলি হয় যা অন্যান্য ভাষাগুলি ব্যবহার করতে এত সুন্দর করে তোলে (উদাহরণস্বরূপ পাইথন)।
হ্যালো গুডবাই

উত্তর:


648

সম্পাদনা সি ++ 17 সাল থেকে স্ট্যান্ডার্ড লাইব্রেরির কিছু অংশ সরানো হয়েছে। ভাগ্যক্রমে, সি ++ 11 দিয়ে শুরু করে, আমাদের ল্যাম্বডাস রয়েছে যা একটি উচ্চতর সমাধান।

#include <algorithm> 
#include <cctype>
#include <locale>

// trim from start (in place)
static inline void ltrim(std::string &s) {
    s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) {
        return !std::isspace(ch);
    }));
}

// trim from end (in place)
static inline void rtrim(std::string &s) {
    s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) {
        return !std::isspace(ch);
    }).base(), s.end());
}

// trim from both ends (in place)
static inline void trim(std::string &s) {
    ltrim(s);
    rtrim(s);
}

// trim from start (copying)
static inline std::string ltrim_copy(std::string s) {
    ltrim(s);
    return s;
}

// trim from end (copying)
static inline std::string rtrim_copy(std::string s) {
    rtrim(s);
    return s;
}

// trim from both ends (copying)
static inline std::string trim_copy(std::string s) {
    trim(s);
    return s;
}

আধুনিক সমাধান আনার জন্য https://stackoverflow.com/a/44973498/524503 ধন্যবাদ

আসল উত্তর:

আমি আমার ছাঁটাই প্রয়োজনীয়তার জন্য এই 3 টির মধ্যে একটির ব্যবহার করতে চাই:

#include <algorithm> 
#include <functional> 
#include <cctype>
#include <locale>

// trim from start
static inline std::string &ltrim(std::string &s) {
    s.erase(s.begin(), std::find_if(s.begin(), s.end(),
            std::not1(std::ptr_fun<int, int>(std::isspace))));
    return s;
}

// trim from end
static inline std::string &rtrim(std::string &s) {
    s.erase(std::find_if(s.rbegin(), s.rend(),
            std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
    return s;
}

// trim from both ends
static inline std::string &trim(std::string &s) {
    return ltrim(rtrim(s));
}

এগুলি মোটামুটি স্ব-বর্ণনামূলক এবং খুব ভালভাবে কাজ করে।

সম্পাদনা : বিটিডাব্লু, আমি std::ptr_funসেখানে অসম্পূর্ণ সাহায্য করতে পারি std::isspaceকারণ সেখানে একটি দ্বিতীয় সংজ্ঞা রয়েছে যা লোকালগুলিকে সমর্থন করে। এটি ঠিক একইরকম castালাই হতে পারে তবে আমি এটি আরও ভাল পছন্দ করি।

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

#include <algorithm> 
#include <functional> 
#include <cctype>
#include <locale>

// trim from start (in place)
static inline void ltrim(std::string &s) {
    s.erase(s.begin(), std::find_if(s.begin(), s.end(),
            std::not1(std::ptr_fun<int, int>(std::isspace))));
}

// trim from end (in place)
static inline void rtrim(std::string &s) {
    s.erase(std::find_if(s.rbegin(), s.rend(),
            std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
}

// trim from both ends (in place)
static inline void trim(std::string &s) {
    ltrim(s);
    rtrim(s);
}

// trim from start (copying)
static inline std::string ltrim_copy(std::string s) {
    ltrim(s);
    return s;
}

// trim from end (copying)
static inline std::string rtrim_copy(std::string s) {
    rtrim(s);
    return s;
}

// trim from both ends (copying)
static inline std::string trim_copy(std::string s) {
    trim(s);
    return s;
}

প্রসঙ্গের জন্য এবং উচ্চ ভোটের উত্তরটি এখনও উপলব্ধ রাখার স্বার্থে আমি মূল উত্তরটি উপরে রাখছি।


28
এই কোডটি কিছু আন্তর্জাতিক স্ট্রিংয়ে ব্যর্থ হয়েছিল (আমার ক্ষেত্রে শিফট-জিস, একটি স্ট্যান্ড :: স্ট্রিংয়ে সঞ্চিত); boost::trimসমস্যাটি সমাধান করার জন্য আমি শেষ করেছি ।
টম

5
আমি রেফারেন্সের পরিবর্তে পয়েন্টার ব্যবহার করব, যাতে কলপয়েন্ট থেকে বোঝা সহজ হয় যে এই ফাংশনগুলি একটি কপি তৈরি না করে পরিবর্তে স্ট্রিংটি সম্পাদন করে।
মার্কো লিওগ্র্যান্ডে

3
নোট করুন যে আইস স্পেসের সাহায্যে আপনি অন-এএসসিআইআই অক্ষরগুলি স্ট্যাকড
.

10
স্থির কেন? এখানেই কি কোনও নামবিহীন নাম স্থান পছন্দ করা হবে?
ট্রেভর হিকি

3
@ ট্র্যাভের হিক্কি, আপনি যদি পছন্দ করেন তবে আপনি তার পরিবর্তে একটি বেনামে নেমস্পেস ব্যবহার করতে পারেন।
ইভান তেরান

417

বুস্টের স্ট্রিং অ্যালগোরিদম ব্যবহার করা সবচেয়ে সহজ হবে:

#include <boost/algorithm/string.hpp>

std::string str("hello world! ");
boost::trim_right(str);

strএখন "hello world!"। উভয় পক্ষকে ছাঁটাই করে দেয় trim_leftএবং এটিও trimরয়েছে।


যদি আপনি _copyউপরের কোনও ফাংশন নামেরে প্রত্যয় যুক্ত করেন তবে trim_copy, ফাংশনটি কোনও রেফারেন্সের মাধ্যমে পরিবর্তনের পরিবর্তে স্ট্রিংয়ের ছাঁটা অনুলিপি প্রদান করবে।

যদি আপনি _ifউপরের কোনও ফাংশন নামের সাথে প্রত্যয় যুক্ত করেন trim_copy_if, যেমন আপনি কেবল কাস্টম স্পেসের বিপরীতে আপনার পছন্দসই প্রাকটিকেট সন্তুষ্ট করে সমস্ত অক্ষর ছাঁটাতে পারেন।


7
এটি লোকেলের উপর নির্ভর করে। আমার ডিফল্ট লোকেল (VS2005, এন) অর্থ ট্যাব, স্পেসস, ক্যারেজ রিটার্ন, নিউলাইনস, উল্লম্ব ট্যাব এবং ফর্ম ফিডগুলি ছাঁটা হয়েছে।
ম্যাটিটি

117
বুস্ট এমন ক্ষুদ্র সমস্যার জন্য এত বড় একটি হাতুড়ি।
কেসি রোডারমোর

143
@ রডরমার: বুস্ট অনেক ক্ষুদ্র সমস্যা সমাধান করে। এটি একটি বিশাল হাতুড়ি যা অনেকগুলি সমাধান করে।
নিকোল বোলাস

123
বুস্ট হ'ল বিভিন্ন মাপের হাতুড়িগুলির একটি সেট যা বিভিন্ন বিভিন্ন সমস্যা সমাধান করে।
ইব্রাহিম

11
@ রডরমার আপনি বলেছেন যে বুস্ট হ'ল এক সর্বাত্মক কিছু না, যেখানে এর একটি শিরোনাম সহ কোনওরকমে কোনও ব্যক্তির প্রোগ্রামে পুরো বিষয়টি আক্রান্ত করে। যা স্পষ্টভাবে কেস নয়। বিটিডব্লিউ, আমি কখনই বুস্ট ব্যবহার করিনি,
আন্ডারস্কোর_

61

std::strings( আইডোন ) থেকে ডান ট্রিম ( ট্রেলিং ) স্পেস এবং ট্যাব অক্ষরগুলির জন্য নিম্নলিখিত কোডটি ব্যবহার করুন :

// trim trailing spaces
size_t endpos = str.find_last_not_of(" \t");
size_t startpos = str.find_first_not_of(" \t");
if( std::string::npos != endpos )
{
    str = str.substr( 0, endpos+1 );
    str = str.substr( startpos );
}
else {
    str.erase(std::remove(std::begin(str), std::end(str), ' '), std::end(str));
}

এবং কেবল জিনিসগুলিতে ভারসাম্য বজায় রাখতে আমি বাম ট্রিম কোডটিও অন্তর্ভুক্ত করব ( আদর্শ ):

// trim leading spaces
size_t startpos = str.find_first_not_of(" \t");
if( string::npos != startpos )
{
    str = str.substr( startpos );
}

4
এটি হোয়াইটস্পেসের অন্যান্য রূপগুলি সনাক্ত করতে পারে না ... বিশেষত নিউলাইন, লাইন ফিড, ক্যারেজ রিটার্ন।
টম

1
ঠিক। আপনি যে সাদা স্থানটি ছাঁটাচ্ছেন তার জন্য আপনাকে এটি কাস্টমাইজ করতে হবে। আমার নির্দিষ্ট অ্যাপ্লিকেশনটি কেবল ফাঁকা স্থান এবং ট্যাবগুলির প্রত্যাশা করেছিল, তবে আপনি অন্যগুলি ধরতে \ n \ r যুক্ত করতে পারেন।
বিল করুন

5
str.substr(...).swap(str)ভাল. একটি কাজ সংরক্ষণ করুন।
আপডেটগ্লিউ

4
@ updogliu এটি সরানো অ্যাসাইনমেন্টটি ব্যবহার করবে না basic_string& operator= (basic_string&& str) noexcept;?
নুরেটিন

8
এই উত্তরটি সমস্ত ফাঁকা স্ট্রিংগুলিকে পরিবর্তন করে না। যা একটি ব্যর্থতা।
টম অ্যান্ডারসন

56

আপনি যা করছেন তা ভাল এবং মজবুত। আমি দীর্ঘদিন ধরে একই পদ্ধতি ব্যবহার করেছি এবং এখনও একটি দ্রুত পদ্ধতি খুঁজে পাইনি:

const char* ws = " \t\n\r\f\v";

// trim from end of string (right)
inline std::string& rtrim(std::string& s, const char* t = ws)
{
    s.erase(s.find_last_not_of(t) + 1);
    return s;
}

// trim from beginning of string (left)
inline std::string& ltrim(std::string& s, const char* t = ws)
{
    s.erase(0, s.find_first_not_of(t));
    return s;
}

// trim from both ends of string (right then left)
inline std::string& trim(std::string& s, const char* t = ws)
{
    return ltrim(rtrim(s, t), t);
}

চরিত্রগুলি ছাঁটাই করার জন্য সরবরাহ করে আপনার অ-হোয়াইটস্পেস অক্ষরগুলি ছাঁটাই করার নমনীয়তা এবং কেবলমাত্র আপনি ছাঁটাই করতে চান এমন অক্ষরগুলি ছাঁটাই করার দক্ষতা পাবেন।


আপনি যদি অর্ডারটি পরিবর্তন করেন trim, অর্থাত্ এটি rtrim(ltrim(s, t), t)কিছুটা দক্ষ হয়ে
উঠুন

1
@ সিআইটিবিএল অভ্যন্তরীণ ফাংশনটি প্রথমে সম্পাদিত হয় যাতে আপনার পথটি ডান থেকে ছাঁটাইয়ের আগে বাম থেকে ছাঁটা যায় । আমি মনে করি যে কম দক্ষ হবে না তাই না?
গালিক

যথাযথভাবে। আমার ভুল
সিআইটিবিএল

আপনি যদি চার্টে বেসিক_স্ট্রিং এবং টেম্পলেট ব্যবহার করেন তবে আপনি সমস্ত স্ট্রিংয়ের জন্য এটি করতে পারেন, কেবল সাদা স্থানের জন্য একটি টেম্পলেট ভেরিয়েবল ব্যবহার করুন যাতে আপনি এটি ws <CharT> এর মতো ব্যবহার করেন। টেকনিক্যালি যে সময়ে আপনি এটা C ++ জন্য 20 প্রস্তুত কর এবং মার্ক এটা খুব constexpr এই ইনলাইন বোঝা যেমন পারে
beached

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

55

দেরিতে পার্টিতে বিট করুন, কিন্তু কিছু মনে করবেন না। এখন সি ++ 11 এখানে রয়েছে, আমাদের ল্যাম্বডাস এবং অটো ভেরিয়েবল রয়েছে। সুতরাং আমার সংস্করণটি, যা সমস্ত-শ্বেতস্থান এবং খালি স্ট্রিংগুলিও পরিচালনা করে তা হ'ল:

#include <cctype>
#include <string>
#include <algorithm>

inline std::string trim(const std::string &s)
{
   auto wsfront=std::find_if_not(s.begin(),s.end(),[](int c){return std::isspace(c);});
   auto wsback=std::find_if_not(s.rbegin(),s.rend(),[](int c){return std::isspace(c);}).base();
   return (wsback<=wsfront ? std::string() : std::string(wsfront,wsback));
}

আমরা এর থেকে একটি বিপরীত পুনরুক্তি তৈরি করতে পারি wsfrontএবং দ্বিতীয়টিতে এটি সমাপ্তির শর্ত হিসাবে ব্যবহার করতে পারি find_if_notতবে এটি কেবল সর্বমোট সাদা রঙের স্ট্রিংয়ের ক্ষেত্রেই কার্যকর এবং জিসিসি ৪.৮ কমপক্ষে বিপরীত পুনরুক্তিটির ধরণের অনুমান করতে যথেষ্ট স্মার্ট নয় ( std::string::const_reverse_iterator) সহ auto। আমি জানি না যে বিপরীত পুনরুক্তি নির্মাণ করা কত ব্যয়বহুল, তাই এখানে ওয়াইএমএমভি। এই পরিবর্তনের সাথে কোডটি এর মতো দেখাচ্ছে:

inline std::string trim(const std::string &s)
{
   auto  wsfront=std::find_if_not(s.begin(),s.end(),[](int c){return std::isspace(c);});
   return std::string(wsfront,std::find_if_not(s.rbegin(),std::string::const_reverse_iterator(wsfront),[](int c){return std::isspace(c);}).base());
}

9
খুশী হলাম। আমার কাছ থেকে +1 খুব খারাপ সি ++ 11 স্ট্রিম :: স্ট্রিংয়ের মধ্যে ট্রিম () প্রবর্তন করেনি এবং প্রত্যেকের জীবনকে সহজ করে তুলেছে।
মিলান বাবুস্কভ

3
আমি সর্বদা একটি ফাংশন কলটি প্রয়োগ করার পরিবর্তে
স্ট্রিমটি ছাঁটাই

22
এর মূল্য কী, সেই ল্যাম্বদা ব্যবহার করার দরকার নেই। আপনি কেবল পাস করতে পারেন std::isspace:auto wsfront=std::find_if_not(s.begin(),s.end(),std::isspace);
vmrob

4
বাস্তবায়নের সাথে সম্ভবত একমাত্র উত্তরের জন্য +1 যা কেবলমাত্র একটি ও (এন) স্ট্রিং অনুলিপি করে।
আলেক্সি আভেরচেঙ্কো

4
@vmrob সংকলকগুলি অগত্যা স্মার্ট নয়। আপনি যা বলছেন তা করা অস্পষ্ট:candidate template ignored: couldn't infer template argument '_Predicate' find_if_not(_InputIterator __first, _InputIterator __last, _Predicate __pred)
জনবেকার

42

এটি চেষ্টা করুন, এটি আমার পক্ষে কাজ করে।

inline std::string trim(std::string& str)
{
    str.erase(0, str.find_first_not_of(' '));       //prefixing spaces
    str.erase(str.find_last_not_of(' ')+1);         //surfixing spaces
    return str;
}

12
যদি আপনার স্ট্রিংটিতে কোনও প্রত্যয়যুক্ত স্পেস না থাকে তবে এটি npos + 1 == 0 থেকে শুরু হয়ে মুছে যাবে এবং আপনি পুরো স্ট্রিংটি মুছবেন।
মহিষ্মিত

3
@rgove দয়া করে ব্যাখ্যা করুন। str.find_last_not_of(x)x এর সমান নয় প্রথম অক্ষরের অবস্থান প্রদান করে। কোনও অক্ষর x এর সাথে মেলে না তবে এটি কেবল এনপোস প্রদান করে। উদাহরণস্বরূপ, যদি কোনও প্রত্যয়যুক্ত স্থান না থাকে তবে এটি সমানভাবে ফিরে আসবে str.length() - 1, মূলত ফলন হবে str.erase((str.length() - 1) + 1).তা হ'ল যদি আমি মারাত্মক ভুল না করি।
ট্র্যাভিস

5
এটি স্ট্যান্ড :: স্ট্রিংয়ে ফিরে আসবে এবং অনুলিপি অনুলিপিটি অনুলিপি করতে এড়াতে।
হেকসেসং

7
আমি বিভ্রান্ত হয়েছি কেন এটি রিটার্ন প্যারামিটার সংশোধন করার পরে একটি অনুলিপি দেয়?
গালিক

3
@ মিলোডিসি আমার বিভ্রান্তি কেন রেফারেন্সের পরিবর্তে একটি অনুলিপি ফেরত দেয় । আমার কাছে ফিরে আসার বিষয়টি আরও বোধগম্য std::string&
গালিক

25

আমি তাজমানের সমাধানটি পছন্দ করি, এটির সাথে একমাত্র সমস্যাটি হ'ল এটি কেবল ফাঁকা স্থানযুক্ত স্ট্রিংটি ছাঁটাই করে না।

1 টি ত্রুটিটি সংশোধন করতে, 2 টি ট্রিমার লাইনের মধ্যে একটি স্ট্রোক্লায়ার () যোগ করুন

std::stringstream trimmer;
trimmer << str;
str.clear();
trimmer >> str;

চমৎকার :) আমাদের উভয় সমাধানের সাথে সমস্যাটি হ'ল তারা উভয় প্রান্তটি ছাঁটাইবে; একটি ltrimবা rtrimএই মত করতে পারে না ।
তাজমান

44
ভাল, তবে অভ্যন্তরীণ সাদা স্থানের সাথে স্ট্রিংয়ের সাথে ডিল করতে পারে না। উদাহরণস্বরূপ ট্রিম (এবিসি
ডিএফ

একটি ভাল সমাধান যদি আপনি জানেন যে কোনও অভ্যন্তরীণ সাদা জায়গা থাকবে না!
এলিয়ট গোরোকভস্কি

এটি দুর্দান্ত এবং সহজ তবে স্ট্রিংটি অনুলিপি করা এবং আউট হওয়ার পরেও এটি বেশ ধীর std::stringstream
গালিক

23

http://ideone.com/nFVtEo

std::string trim(const std::string &s)
{
    std::string::const_iterator it = s.begin();
    while (it != s.end() && isspace(*it))
        it++;

    std::string::const_reverse_iterator rit = s.rbegin();
    while (rit.base() != it && isspace(*rit))
        rit++;

    return std::string(it, rit.base());
}

1
অবশেষে বেসিক স্পেস ট্রিমের জন্য মার্জিত সমাধান ... :)
jave.web

এটি কীভাবে কাজ করে: এটি একটি অনুলিপি মত সমাধান - এটি প্রথম অক্ষরের অবস্থান খুঁজে পায় যা স্থান নয় (it ) এবং বিপরীত: অক্ষরের অবস্থান যার পরে কেবলমাত্র ফাঁকা স্থান রয়েছে ( rit) - এর পরে এটি একটি নতুন নির্মিত স্ট্রিং == ফেরায় মূল স্ট্রিংয়ের অংশটির একটি অনুলিপি - সেই
অংশগুলির

আপনাকে ধন্যবাদ, আমার জন্য কাজ করেছেন: std: string s = "ওহ নয়েজ: স্পেস \ r \ n"; std :: স্ট্রিং ক্লিন = ট্রিম (গুলি);
অ্যালেক্সেক্স রোচে

15

একটি খালি স্ট্রিংয়ের ক্ষেত্রে, আপনার কোড ধরে নেয় যে 1 যোগ করে string::npos0 দেয় 0 string::nposপ্রকারের string::size_type, যা স্বাক্ষরবিহীন। সুতরাং, আপনি সংযোজনের ওভারফ্লো আচরণের উপর নির্ভর করছেন।


23
আপনি যে শব্দ এটি খারাপ হিসাবে। স্বাক্ষরযুক্ত পূর্ণসংখ্যার ওভারফ্লো আচরণ খারাপ।
এমসাল্টাররা

2
যোগ করার পদ্ধতি 1থেকে std::string::npos নয় দিতে 0অনুযায়ী C++ Standard। সুতরাং এটি একটি সম্পূর্ণ অনুমান যা একেবারে নির্ভর করা যেতে পারে।
গালিক

13

সিপিপ্লসপ্লাস ডটকমের হ্যাক অফ

std::string choppa(const std::string &t, const std::string &ws)
{
    std::string str = t;
    size_t found;
    found = str.find_last_not_of(ws);
    if (found != std::string::npos)
        str.erase(found+1);
    else
        str.clear();            // str is all whitespace

    return str;
}

এটি নাল মামলার ক্ষেত্রেও কাজ করে। :-)


4
এটি ঠিক rtrim, নয়ltrim
ub3rst4r

1
find আপনার কী_পরিচালনা_প্রথম_নোট ব্যবহার করে আপত্তি আছে? এটি সংশোধন করা তুলনামূলকভাবে সহজ।
অভিনব গৌনিয়াল

13

সি ++ 17 এর সাহায্যে আপনি বেসিক_ স্ট্রিং_ভিউ :: অপসারণ_প্রিফিক্স এবং বেসিক_স্ট্রিং_ভিউ :: অপসারণ_সফিক্স :

std::string_view trim(std::string_view s)
{
    s.remove_prefix(std::min(s.find_first_not_of(" \t\r\v\n"), s.size()));
    s.remove_suffix(std::min(s.size() - s.find_last_not_of(" \t\r\v\n") - 1, s.size()));

    return s;
}

একটি দুর্দান্ত বিকল্প:

std::string_view ltrim(std::string_view s)
{
    s.remove_prefix(std::distance(s.cbegin(), std::find_if(s.cbegin(), s.cend(),
         [](int c) {return !std::isspace(c);})));

    return s;
}

std::string_view rtrim(std::string_view s)
{
    s.remove_suffix(std::distance(s.crbegin(), std::find_if(s.crbegin(), s.crend(),
        [](int c) {return !std::isspace(c);})));

    return s;
}

std::string_view trim(std::string_view s)
{
    return ltrim(rtrim(s));
}

আমি নিশ্চিত তুমি কি না পরীক্ষা করছি, কিন্তু আপনার উদাহরণে এসটিডি :: find_first_not_of ফিরে আসবে এসটিডি :: স্ট্রিং :: npos এবং এসটিডি :: string_view :: আকার 4. ফিরে আসবে ন্যূনতম স্পষ্টত চার হয়, উপাদানের সংখ্যা হতে স্টাডি :: স্ট্রিং_ভিউ :: অপসারণ_প্রিফিক্স দ্বারা সরানো হয়েছে । জিসিসি
ফিডেলাক্স

1
ধন্যবাদ! আমার কাছে ভালই মনে হচ্ছে.
কনটাঙ্গো

11

@ বিলটি দ্য টিকটিকি দ্বারা উত্তরের ভিত্তিতে আমার সমাধান

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

const std::string StringUtils::WHITESPACE = " \n\r\t";

std::string StringUtils::Trim(const std::string& s)
{
    return TrimRight(TrimLeft(s));
}

std::string StringUtils::TrimLeft(const std::string& s)
{
    size_t startpos = s.find_first_not_of(StringUtils::WHITESPACE);
    return (startpos == std::string::npos) ? "" : s.substr(startpos);
}

std::string StringUtils::TrimRight(const std::string& s)
{
    size_t endpos = s.find_last_not_of(StringUtils::WHITESPACE);
    return (endpos == std::string::npos) ? "" : s.substr(0, endpos+1);
}

9

আমার উত্তরটি এই পোস্টের শীর্ষস্থানীয় উত্তরের একটি উন্নতি যা নিয়ন্ত্রণ অক্ষর পাশাপাশি ফাঁকা স্থানগুলিকে ( ASCII টেবিলে 0-32 এবং 127 ) ছাঁটাই করে ।

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

#include <algorithm>
#include <functional>
#include <string>

/**
 * @brief Left Trim
 *
 * Trims whitespace from the left end of the provided std::string
 *
 * @param[out] s The std::string to trim
 *
 * @return The modified std::string&
 */
std::string& ltrim(std::string& s) {
  s.erase(s.begin(), std::find_if(s.begin(), s.end(),
    std::ptr_fun<int, int>(std::isgraph)));
  return s;
}

/**
 * @brief Right Trim
 *
 * Trims whitespace from the right end of the provided std::string
 *
 * @param[out] s The std::string to trim
 *
 * @return The modified std::string&
 */
std::string& rtrim(std::string& s) {
  s.erase(std::find_if(s.rbegin(), s.rend(),
    std::ptr_fun<int, int>(std::isgraph)).base(), s.end());
  return s;
}

/**
 * @brief Trim
 *
 * Trims whitespace from both ends of the provided std::string
 *
 * @param[out] s The std::string to trim
 *
 * @return The modified std::string&
 */
std::string& trim(std::string& s) {
  return ltrim(rtrim(s));
}

দ্রষ্টব্য: বিকল্পভাবে আপনার std::iswgraphযদি বিস্তৃত অক্ষরের জন্য সমর্থন প্রয়োজন হয় তবে আপনি ব্যবহার করতে সক্ষম হবেন , তবে std::wstringম্যানিপুলেশন সক্ষম করতে আপনাকে এই কোডটিও সম্পাদনা করতে হবে , যা আমি পরীক্ষা করে দেখিনি ( std::basic_stringএই বিকল্পটি অন্বেষণ করার জন্য রেফারেন্স পৃষ্ঠাটি দেখুন ) ।


3
std :: ptr_fun অবচয় করা হয়েছে
জনবেকার্স

8

সি ++ এর সাথে একটি নিয়মিত এক্সপ্রেশন মডিউলও এসেছিল , অবশ্যই কোনটি অবশ্যই শীর্ষস্থানীয় বা পিছনের জায়গাগুলি ছাঁটাইতে ব্যবহার করা যেতে পারে।

এরকম কিছু হতে পারে:

std::string ltrim(const std::string& s)
{
    static const std::regex lws{"^[[:space:]]*", std::regex_constants::extended};
    return std::regex_replace(s, lws, "");
}

std::string rtrim(const std::string& s)
{
    static const std::regex tws{"[[:space:]]*$", std::regex_constants::extended};
    return std::regex_replace(s, tws, "");
}

std::string trim(const std::string& s)
{
    return ltrim(rtrim(s));
}

8

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

void trim(string& s) {
    while(s.compare(0,1," ")==0)
        s.erase(s.begin()); // remove leading whitespaces
    while(s.size()>0 && s.compare(s.size()-1,1," ")==0)
        s.erase(s.end()-1); // remove trailing whitespaces
}

8
s.erase(0, s.find_first_not_of(" \n\r\t"));                                                                                               
s.erase(s.find_last_not_of(" \n\r\t")+1);   

2
আপনি যদি বিপরীত ক্রমে এটি করেন এবং বামটি ছাঁটাইয়ের মাধ্যমে একটি শিফট ডাকার আগে ডান থেকে প্রথমে ট্রিম করেন তবে এটি কিছুটা দক্ষ হবে।
গালিক

7

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

void TrimString(std::string & str)
{ 
    if(str.empty())
        return;

    const auto pStr = str.c_str();

    size_t front = 0;
    while(front < str.length() && std::isspace(int(pStr[front]))) {++front;}

    size_t back = str.length();
    while(back > front && std::isspace(int(pStr[back-1]))) {--back;}

    if(0 == front)
    {
        if(back < str.length())
        {
            str.resize(back - front);
        }
    }
    else if(back <= front)
    {
        str.clear();
    }
    else
    {
        str = std::move(std::string(str.begin()+front, str.begin()+back));
    }
}

@ বিএমজিডিএ সম্ভবত তাত্ত্বিকভাবে দ্রুততম সংস্করণটিতে এই স্বাক্ষর রয়েছে: বহিরাগত "সি" শূন্য স্ট্রিং_ট্রিম (চর ** শুরু_, চর ** শেষ_) ... আমার বামনা ধরবেন?

6

এটি করার একটি মার্জিত উপায় এর মতো হতে পারে

std::string & trim(std::string & str)
{
   return ltrim(rtrim(str));
}

এবং সহায়ক কার্যগুলি হিসাবে প্রয়োগ করা হয়:

std::string & ltrim(std::string & str)
{
  auto it =  std::find_if( str.begin() , str.end() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
  str.erase( str.begin() , it);
  return str;   
}

std::string & rtrim(std::string & str)
{
  auto it =  std::find_if( str.rbegin() , str.rend() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
  str.erase( it.base() , str.end() );
  return str;   
}

এবং একবার আপনি এই সমস্ত জায়গায় হয়ে গেলে আপনি এটি আরও লিখতে পারেন:

std::string trim_copy(std::string const & str)
{
   auto s = str;
   return ltrim(rtrim(s));
}

6

ট্রিম সি ++ 11 বাস্তবায়ন:

static void trim(std::string &s) {
     s.erase(s.begin(), std::find_if_not(s.begin(), s.end(), [](char c){ return std::isspace(c); }));
     s.erase(std::find_if_not(s.rbegin(), s.rend(), [](char c){ return std::isspace(c); }).base(), s.end());
}

5

আমার ধারণা, আপনি যদি কোনও স্ট্রিং ছাঁটাইতে "সেরা উপায়" জিজ্ঞাসা শুরু করেন, আমি বলব একটি ভাল বাস্তবায়ন হবে যা:

  1. অস্থায়ী স্ট্রিং বরাদ্দ দেয় না
  2. ইন-প্লেস ট্রিম এবং কপি ট্রিমের জন্য ওভারলোড রয়েছে
  3. বিভিন্ন বৈধতা ক্রম / যুক্তি গ্রহণ করতে সহজেই কাস্টমাইজ করা যায়

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

inline const char* trim_start(const char* str)
{
    while (memchr(" \t\n\r", *str, 4))  ++str;
    return str;
}
inline const char* trim_end(const char* end)
{
    while (memchr(" \t\n\r", end[-1], 4)) --end;
    return end;
}
inline std::string trim(const char* buffer, int len) // trim a buffer (input?)
{
    return std::string(trim_start(buffer), trim_end(buffer + len));
}
inline void trim_inplace(std::string& str)
{
    str.assign(trim_start(str.c_str()),
        trim_end(str.c_str() + str.length()));
}

int main()
{
    char str [] = "\t \nhello\r \t \n";

    string trimmed = trim(str, strlen(str));
    cout << "'" << trimmed << "'" << endl;

    system("pause");
    return 0;
}

3

আমি নিশ্চিত না যে আপনার পরিবেশটি একই রকম কিনা তবে আমার মতে, খালি স্ট্রিং কেসটি প্রোগ্রামটি বাতিল করে দেবে। আমি হয় যদি সেই মুছা কলটিকে একটি if (! S.empty ()) দিয়ে মুড়িয়ে দেব বা বুস্টটি ইতিমধ্যে উল্লিখিত হিসাবে ব্যবহার করব।


3

আমি এখানে যা এলাম তা এখানে:

std::stringstream trimmer;
trimmer << str;
trimmer >> str;

স্ট্রিম এক্সট্রাকশন হ'ল হোয়াইটস্পেসকে স্বয়ংক্রিয়ভাবে সরিয়ে দেয়, তাই এটি একটি কবজির মতো কাজ করে।
খুব পরিষ্কার এবং মার্জিত, আমি যদি নিজেই তাই বলি। ;)


15
হুম; এটি ধরে নিয়েছে যে স্ট্রিংটির কোনও অভ্যন্তরীণ শ্বেত স্থান নেই (যেমন স্পেস)। ওপি কেবল বলেছিল যে তিনি বাম বা ডানদিকে সাদা স্থান ট্রিম করতে চেয়েছিলেন।
ইলেকট্রিক

3

গোলমাল থেকে আমার সমাধান অবদান। trimএকটি নতুন স্ট্রিং তৈরি করতে এবং পরিবর্তিত trim_in_placeস্ট্রিংটি এতে পরিবর্তনিত পরিবর্তনের ক্ষেত্রে ডিফল্ট থাকে it trimফাংশন সমর্থন C ++ 11 পদক্ষেপ শব্দার্থবিদ্যা।

#include <string>

// modifies input string, returns input

std::string& trim_left_in_place(std::string& str) {
    size_t i = 0;
    while(i < str.size() && isspace(str[i])) { ++i; };
    return str.erase(0, i);
}

std::string& trim_right_in_place(std::string& str) {
    size_t i = str.size();
    while(i > 0 && isspace(str[i - 1])) { --i; };
    return str.erase(i, str.size());
}

std::string& trim_in_place(std::string& str) {
    return trim_left_in_place(trim_right_in_place(str));
}

// returns newly created strings

std::string trim_right(std::string str) {
    return trim_right_in_place(str);
}

std::string trim_left(std::string str) {
    return trim_left_in_place(str);
}

std::string trim(std::string str) {
    return trim_left_in_place(trim_right_in_place(str));
}

#include <cassert>

int main() {

    std::string s1(" \t\r\n  ");
    std::string s2("  \r\nc");
    std::string s3("c \t");
    std::string s4("  \rc ");

    assert(trim(s1) == "");
    assert(trim(s2) == "c");
    assert(trim(s3) == "c");
    assert(trim(s4) == "c");

    assert(s1 == " \t\r\n  ");
    assert(s2 == "  \r\nc");
    assert(s3 == "c \t");
    assert(s4 == "  \rc ");

    assert(trim_in_place(s1) == "");
    assert(trim_in_place(s2) == "c");
    assert(trim_in_place(s3) == "c");
    assert(trim_in_place(s4) == "c");

    assert(s1 == "");
    assert(s2 == "c");
    assert(s3 == "c");
    assert(s4 == "c");  
}

3

এই সি ++ 11 আরও সহজভাবে যোগে কারণে কাজ করা যেতে পারে back()এবং pop_back()

while ( !s.empty() && isspace(s.back()) ) s.pop_back();

ওপি কর্তৃক প্রস্তাবিত পদ্ধতিটিও খারাপ নয় - অনুসরণ করা কিছুটা শক্ত।
নোবার

3

আমার সংস্করণটি এখানে:

size_t beg = s.find_first_not_of(" \r\n");
return (beg == string::npos) ? "" : in.substr(beg, s.find_last_not_of(" \r\n") - beg);

আপনি শেষ চরিত্রটি অনুপস্থিত। দৈর্ঘ্যের একটি +1 এটি সমাধান করে
গ্যালেনিট

2

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

string trim(char const *str)
{
  // Trim leading non-letters
  while(!isalnum(*str)) str++;

  // Trim trailing non-letters
  end = str + strlen(str) - 1;
  while(end > str && !isalnum(*end)) end--;

  return string(str, end+1);
}

2

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

string trimSpace(const string &str) {
   if (str.empty()) return str;
   string::size_type i,j;
   i=0;
   while (i<str.size() && isspace(str[i])) ++i;
   if (i == str.size())
      return string(); // empty string
   j = str.size() - 1;
   //while (j>0 && isspace(str[j])) --j; // the j>0 check is not needed
   while (isspace(str[j])) --j
   return str.substr(i, j-i+1);
}

2

এখানে যে সমাধানটি std::সর্বত্র লিখতে ব্যবহৃত হয় না এবং এখনও constসঠিকতা, iteratorএস, এসটিএল algorithm, ইত্যাদির সাথে পরিচিত না হন তাদের পক্ষে বোঝার জন্য সহজ সমাধান এখানে ...

#include <string>
#include <cctype> // for isspace
using namespace std;


// Left trim the given string ("  hello!  " --> "hello!  ")
string left_trim(string str) {
    int numStartSpaces = 0;
    for (int i = 0; i < str.length(); i++) {
        if (!isspace(str[i])) break;
        numStartSpaces++;
    }
    return str.substr(numStartSpaces);
}

// Right trim the given string ("  hello!  " --> "  hello!")
string right_trim(string str) {
    int numEndSpaces = 0;
    for (int i = str.length() - 1; i >= 0; i--) {
        if (!isspace(str[i])) break;
        numEndSpaces++;
    }
    return str.substr(0, str.length() - numEndSpaces);
}

// Left and right trim the given string ("  hello!  " --> "hello!")
string trim(string str) {
    return right_trim(left_trim(str));
}

আশা করি এটা সাহায্য করবে...


1

এই সংস্করণটি অভ্যন্তরীণ সাদা স্থান এবং অ-অক্ষরগুলিকে ছাঁটাই করে:

static inline std::string &trimAll(std::string &s)
{   
    if(s.size() == 0)
    {
        return s;
    }

    int val = 0;
    for (int cur = 0; cur < s.size(); cur++)
    {
        if(s[cur] != ' ' && std::isalnum(s[cur]))
        {
            s[val] = s[cur];
            val++;
        }
    }
    s.resize(val);
    return s;
}

1

তবুও অন্য বিকল্প - উভয় প্রান্ত থেকে এক বা একাধিক অক্ষর সরিয়ে দেয়।

string strip(const string& s, const string& chars=" ") {
    size_t begin = 0;
    size_t end = s.size()-1;
    for(; begin < s.size(); begin++)
        if(chars.find_first_of(s[begin]) == string::npos)
            break;
    for(; end > begin; end--)
        if(chars.find_first_of(s[end]) == string::npos)
            break;
    return s.substr(begin, end-begin+1);
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.