কোন স্ট্রিং (চর * হিসাবে দেওয়া) কে কোন আন্তঃকে পার্স করার সি ++ উপায় কী? দৃust় এবং স্পষ্ট ত্রুটি হ্যান্ডলিং একটি প্লাস ( শূন্য ফিরে আসার পরিবর্তে) )।
কোন স্ট্রিং (চর * হিসাবে দেওয়া) কে কোন আন্তঃকে পার্স করার সি ++ উপায় কী? দৃust় এবং স্পষ্ট ত্রুটি হ্যান্ডলিং একটি প্লাস ( শূন্য ফিরে আসার পরিবর্তে) )।
উত্তর:
নতুন সি ++ 11 এ এর জন্য ফাংশন রয়েছে: স্টোই, স্টল, স্টল, স্টুল এবং আরও অনেক কিছু।
int myNr = std::stoi(myString);
এটি রূপান্তর ত্রুটিতে একটি ব্যতিক্রম ছুঁড়ে দেবে।
এমনকি এই নতুন ফাংশনগুলিতে এখনও ড্যান দ্বারা উল্লিখিত একই সমস্যা রয়েছে : তারা আনন্দের সাথে "11x" স্ট্রিংটিকে পূর্ণসংখ্যা "11" তে রূপান্তর করবে।
আরও দেখুন: http://en.cppreferences.com/w/cpp/string/basic_string/stol
আমার পরামর্শের প্রথম অংশটি এখানে: এটির জন্য স্ট্রিংস্ট্রিম ব্যবহার করবেন না । প্রথমদিকে এটি ব্যবহার করা সহজ বলে মনে হচ্ছে, আপনি দৃust়তা এবং ভাল ত্রুটি পরিচালনা করতে চাইলে আপনাকে অনেক অতিরিক্ত কাজ করতে হবে।
এটি এমন একটি পদ্ধতির যা স্বজ্ঞাতভাবে মনে হয় এটির কাজ করা উচিত:
bool str2int (int &i, char const *s)
{
std::stringstream ss(s);
ss >> i;
if (ss.fail()) {
// not an integer
return false;
}
return true;
}
এটি একটি বড় সমস্যা রয়েছে: str2int(i, "1337h4x0r")
আনন্দের সাথে ফিরে আসবে true
এবং i
মান পাবে 1337
। stringstream
রূপান্তর পরবর্তী কোনও অক্ষর নেই তা নিশ্চিত করে আমরা এই সমস্যাটি নিয়ে কাজ করতে পারি :
bool str2int (int &i, char const *s)
{
char c;
std::stringstream ss(s);
ss >> i;
if (ss.fail() || ss.get(c)) {
// not an integer
return false;
}
return true;
}
আমরা একটি সমস্যা সমাধান করেছি, তবে এখনও আরও কয়েকটি সমস্যা রয়েছে।
স্ট্রিংয়ের সংখ্যাটি যদি বেস 10 না হয়? স্ট্রিমটিকে সঠিক মোডে সেট করে আমরা অন্যান্য ঘাঁটিগুলিকে সমন্বিত করার চেষ্টা করতে পারি (উদাঃss << std::hex
রূপান্তরটি চেষ্টা করার আগে আমরা ) করার চেষ্টা করতে পারি। তবে এর অর্থ হ'ল কলকারীকে অবশ্যই একটি প্রাইমারি জানতে হবে যে নম্বরটি কী তা - এবং কলকারী কীভাবে এটি জানতে পারে? কলকারী এখনও জানে না নম্বরটি কী। এমনকি তারা জানে না যে হয়একটি সংখ্যা! কীভাবে তারা জানতে পারে যে এটি কী বেস? আমরা কেবলমাত্র আদেশ দিতে পারি যে আমাদের প্রোগ্রামগুলিতে সমস্ত সংখ্যার ইনপুটটি বেস 10 হতে হবে এবং হেক্সাডেসিমাল বা অষ্টাল ইনপুটটিকে অবৈধ হিসাবে প্রত্যাখ্যান করতে হবে। তবে এটি খুব নমনীয় বা মজবুত নয়। এই সমস্যার কোনও সহজ সমাধান নেই। আপনি প্রতিটি বেসের জন্য একবার রূপান্তর চেষ্টা করতে পারবেন না, কারণ দশমিক রূপান্তরটি সর্বদা অষ্টাল সংখ্যার (অগ্রণী শূন্যের সাথে) সফল হবে এবং অষ্টাল রূপান্তরটি কিছু দশমিক সংখ্যার জন্য সফল হতে পারে। সুতরাং এখন আপনাকে একটি শীর্ষস্থানীয় শূন্যের জন্য পরীক্ষা করতে হবে। কিন্তু অপেক্ষা করো! হেক্সাডেসিমাল সংখ্যাগুলি একটি শূন্য শূন্যের সাথেও শুরু করতে পারে (0x ...)। দীর্ঘশ্বাস.
আপনি যদি উপরোক্ত সমস্যাগুলি মোকাবেলা করতে সফল হন, তবুও আরও একটি বড় সমস্যা রয়েছে: যদি কলকারীকে খারাপ ইনপুট (যেমন "123foo") এবং যে কোনও সংখ্যার int
(যেমন "4000000000" এর সীমার বাইরে থাকে তার মধ্যে পার্থক্য করার প্রয়োজন হয় তবে কী হবে? 32-বিট int
)? সাথে stringstream
, এই পার্থক্য করার কোনও উপায় নেই। রূপান্তরটি সফল হয়েছে কি ব্যর্থ হয়েছে তা আমরা কেবল জানি। যদি এটি ব্যর্থ হয় তবে কেন এটি ব্যর্থ হয়েছিল তা আমাদের জানার উপায় নেই । আপনি দেখতে পাচ্ছেন, stringstream
যদি আপনি দৃust়তা এবং স্পষ্ট ত্রুটি পরিচালনা করতে চান তবে অনেকগুলি পছন্দ করতে পারা যায়।
এটি আমার দ্বিতীয় পরামর্শের দিকে নিয়ে যায়: এর lexical_cast
জন্য বুস্টের কোনও ব্যবহার করবেন না । lexical_cast
ডকুমেন্টেশনটি কী বলে তা বিবেচনা করুন :
যেখানে রূপান্তরগুলির উপর একটি উচ্চতর ডিগ্রি নিয়ন্ত্রণ প্রয়োজন, স্ট্যান্ড স্ট্রিংস্ট্রিম এবং স্ট্যান্ড :: ডাব্লুস্ট্রিংস্ট্রিম আরও উপযুক্ত পথ সরবরাহ করে। যেখানে অ-স্ট্রিম-ভিত্তিক রূপান্তরগুলি প্রয়োজন, লেক্সিক্যাল_কাস্ট কাজের জন্য ভুল সরঞ্জাম এবং এই জাতীয় পরিস্থিতিতে special
কি?? আমরা ইতিমধ্যে দেখেছি যে stringstream
নিয়ন্ত্রণের একটি নিম্ন স্তরের নিয়ন্ত্রণ রয়েছে, এবং এখনও আপনার "নিয়ন্ত্রণের উচ্চ স্তরের" প্রয়োজন হলে stringstream
এটি ব্যবহার করা উচিত বলে মনে করে lexical_cast
। এছাড়াও, কারণ lexical_cast
কেবল একটি মোড়কের চারপাশে stringstream
, এটি একই সমস্যাগুলি ভোগ stringstream
করে: একাধিক সংখ্যা ঘাঁটি এবং দুর্বল ত্রুটি পরিচালনার জন্য দুর্বল সমর্থন।
ভাগ্যক্রমে, ইতিমধ্যে কেউ উপরের সমস্ত সমস্যার সমাধান করেছেন। সি স্ট্যান্ডার্ড লাইব্রেরিতে strtol
এবং পরিবার রয়েছে যার মধ্যে এই সমস্যাগুলির কোনওটিই নেই।
enum STR2INT_ERROR { SUCCESS, OVERFLOW, UNDERFLOW, INCONVERTIBLE };
STR2INT_ERROR str2int (int &i, char const *s, int base = 0)
{
char *end;
long l;
errno = 0;
l = strtol(s, &end, base);
if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX) {
return OVERFLOW;
}
if ((errno == ERANGE && l == LONG_MIN) || l < INT_MIN) {
return UNDERFLOW;
}
if (*s == '\0' || *end != '\0') {
return INCONVERTIBLE;
}
i = l;
return SUCCESS;
}
এমন কোনও কিছুর জন্য অত্যন্ত সহজ যা সমস্ত ত্রুটির কেসগুলি পরিচালনা করে এবং 2 থেকে 36 পর্যন্ত যে কোনও সংখ্যা বেসকে সমর্থন করে। যদি base
শূন্য হয় (ডিফল্ট) এটি কোনও বেস থেকে রূপান্তর করার চেষ্টা করবে। অথবা কলার তৃতীয় যুক্তি সরবরাহ করতে পারে এবং নির্দিষ্ট করে যে রূপান্তরটি কেবলমাত্র একটি নির্দিষ্ট বেসের জন্য চেষ্টা করা উচিত। এটি শক্তিশালী এবং সর্বনিম্ন পরিশ্রমের সাথে সমস্ত ত্রুটি পরিচালনা করে।
পছন্দ করার অন্যান্য কারণ strtol
(এবং পরিবার):
অন্য কোনও পদ্ধতি ব্যবহারের জন্য একেবারে ভাল কারণ নেই।
strtol
থ্রেড-সেফ থাকা দরকার। পসিক্সেরও errno
থ্রেড-লোকাল স্টোরেজ ব্যবহার করা দরকার । এমনকি নন-পসিক্স সিস্টেমে, errno
মাল্টিথ্রেডেড সিস্টেমে প্রায় সমস্ত বাস্তবায়ন থ্রেড-লোকাল স্টোরেজ ব্যবহার করে। সর্বশেষতম সি ++ স্ট্যান্ডার্ডের জন্য errno
পসিক্স অনুগত হওয়া দরকার । সর্বশেষতম সি স্ট্যান্ডার্ডে errno
থ্রেড-লোকাল স্টোরেজ থাকাও দরকার । এমনকি উইন্ডোজেও, যা অবশ্যই পসিক্সের অনুগত নয়, errno
এটি থ্রেড-সেফ এবং এক্সটেনশনের মাধ্যমেও তাই strtol
।
std::stol
জন্য রয়েছে , যা সঠিকভাবে প্রত্যাবর্তনের চেয়ে ব্যতিক্রম ছুঁড়ে ফেলবে।
std::stol
এমনকি সি ++ ভাষাতে যুক্ত করা হয়েছিল। এটি বলেছিল, আমি এটি "সি সি ++ এর মধ্যে সি কোডিং" বলা ঠিক না বলে মনে করি না। এটি নির্বোধভাবে বলা যায় যে std::strtol
সি কোডিং যখন এটি স্পষ্টভাবে সি ++ ভাষার অংশ হয়। আমার উত্তরটি সি ++ তে পুরোপুরি প্রয়োগ হয়েছিল যখন এটি লেখা হয়েছিল এবং এটি এখনও নতুনটির সাথে প্রযোজ্য std::stol
। ব্যতিক্রমগুলি ডেকে আনে এমন ফাংশনগুলি কল করা প্রতিটি প্রোগ্রামিং পরিস্থিতিতে সর্বদা সেরা না।
এটি আটোয়ার চেয়ে নিরাপদ সি ()
const char* str = "123";
int i;
if(sscanf(str, "%d", &i) == EOF )
{
/* error */
}
স্ট্যান্ডার্ড স্ট্রিমস্ট্রিম সহ সি ++ : (ধন্যবাদ সিএমএস )
int str2int (const string &str) {
stringstream ss(str);
int num;
if((ss >> num).fail())
{
//ERROR
}
return num;
}
সঙ্গে বুস্ট গ্রন্থাগার: (ধন্যবাদ জে )
#include <boost/lexical_cast.hpp>
#include <string>
try
{
std::string str = "123";
int number = boost::lexical_cast< int >( str );
}
catch( const boost::bad_lexical_cast & )
{
// Error
}
সম্পাদনা: স্ট্রিংস্ট্রিম সংস্করণটি ঠিক করা হয়েছে যাতে এটি ত্রুটিগুলি পরিচালনা করে। (মূল পোস্টে সিএমএস এবং জেকের মন্তব্যে ধন্যবাদ)
ভাল 'পুরানো সি উপায় এখনও কাজ করে। আমি স্ট্র্টল বা স্ট্র্টল সুপারিশ করি। রিটার্নের স্থিতি এবং 'এন্ডপ্রিটার' এর মধ্যে আপনি ভাল ডায়াগনস্টিক আউটপুট দিতে পারেন। এটি একাধিক ঘাঁটিও সুন্দরভাবে পরিচালনা করে।
আপনি বুস্টlexical_cast
ব্যবহার করতে পারেন , এটি এটি আরও জেনেরিক ইন্টারফেসে আবৃত করে।
ব্যর্থতার দিকে lexical_cast<Target>(Source)
ছুড়ে ফেলেbad_lexical_cast
আপনি সি ++ স্ট্যান্ডার্ড লাইব্রেরি থেকে স্ট্রিংস্ট্রিম ব্যবহার করতে পারেন:
stringstream ss(str);
int x;
ss >> x;
if(ss) { // <-- error handling
// use x
} else {
// not a number
}
পূর্ণসংখ্যা পড়ার চেষ্টা করার সময় অ-অঙ্কের সম্মুখীন হলে স্ট্রিমের স্টেটটি ব্যর্থ হয়ে সেট করা হবে।
দেখুন স্ট্রিম ফাঁদ এবং C ++ errorhandling এর ফাঁদ স্ট্রিম জন্য।
আপনি স্ট্রিংস্ট্রিম ব্যবহার করতে পারেন
int str2int (const string &str) {
stringstream ss(str);
int num;
ss >> num;
return num;
}
আমি মনে করি এই তিনটি লিঙ্কের সমষ্টি:
স্ট্রিংস্ট্রিম এবং লেজিক্যাল_কাস্ট সলিউশনগুলির প্রায় একইরকম লেসিকাল কাস্ট স্ট্রিংস্ট্রিম ব্যবহার করছে।
লেক্সিকাল কাস্টের কিছু বিশেষীকরণ বিভিন্ন পদ্ধতির ব্যবহারের জন্য বিশদ জানতে http://www.boost.org/doc/libs/re कृपया/boost/lexical_cast.hpp দেখুন । পূর্ণসংখ্যা এবং ফ্লোটগুলি এখন স্ট্রিং রূপান্তরকরণের জন্য বিশেষীকরণ করা হয়।
কেউ তার নিজের প্রয়োজনের জন্য লেক্সিক্যাল_কাস্ট বিশেষায়িত করতে এবং এটিকে দ্রুত তৈরি করতে পারে। এটি চূড়ান্ত সমাধান হবে সমস্ত পক্ষকে সন্তুষ্ট করে, পরিষ্কার এবং সহজ।
ইতিমধ্যে উল্লিখিত নিবন্ধগুলি পূর্ণসংখ্যার <-> স্ট্রিংকে রূপান্তর করার বিভিন্ন পদ্ধতির মধ্যে তুলনা দেখায়। নিম্নলিখিত পদ্ধতিগুলি বোঝায়: পুরানো সি-ওয়ে, স্পিরিটি.কর্মা, ফাস্টফর্ম্যাট, সহজ সরল লুপ।
লেক্সিক্যাল_কাস্ট কিছু ক্ষেত্রে যেমন ইন্ট টু স্ট্রিং রূপান্তরটির জন্য ঠিক আছে।
লেক্সিকাল কাস্ট ব্যবহার করে স্ট্রিংকে ইনটে রূপান্তর করা ভাল ধারণা নয় কারণ এটি ব্যবহৃত প্ল্যাটফর্ম / সংকলকটির উপর নির্ভর করে আটয়ের চেয়ে 10-40 গুণ কম ধীর।
বুস্ট.স্প্রিট.কর্মা পূর্ণসংখ্যাকে স্ট্রিংয়ে রূপান্তর করার জন্য দ্রুততম গ্রন্থাগার বলে মনে হচ্ছে।
ex.: generate(ptr_char, int_, integer_number);
এবং উপরে উল্লিখিত নিবন্ধের মৌলিক সরল লুপটি স্ট্রিংকে ইনটিতে রূপান্তরিত করার দ্রুততম উপায়, সম্ভবত নিরাপদ নয়, স্ট্রটল () নিরাপদ সমাধানের মতো বলে মনে হচ্ছে
int naive_char_2_int(const char *p) {
int x = 0;
bool neg = false;
if (*p == '-') {
neg = true;
++p;
}
while (*p >= '0' && *p <= '9') {
x = (x*10) + (*p - '0');
++p;
}
if (neg) {
x = -x;
}
return x;
}
সি ++ স্ট্রিং টুলকিট লাইব্রেরি (StrTk) নিম্নলিখিত সমাধান আছে:
static const std::size_t digit_table_symbol_count = 256;
static const unsigned char digit_table[digit_table_symbol_count] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF - 0x07
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x08 - 0x0F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x10 - 0x17
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x18 - 0x1F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x20 - 0x27
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x28 - 0x2F
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 0x30 - 0x37
0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x38 - 0x3F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x40 - 0x47
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x48 - 0x4F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x50 - 0x57
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x58 - 0x5F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x60 - 0x67
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x68 - 0x6F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x70 - 0x77
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x78 - 0x7F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x80 - 0x87
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x88 - 0x8F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x90 - 0x97
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x98 - 0x9F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xA0 - 0xA7
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xA8 - 0xAF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xB0 - 0xB7
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xB8 - 0xBF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xC0 - 0xC7
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xC8 - 0xCF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xD0 - 0xD7
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xD8 - 0xDF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xE0 - 0xE7
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xE8 - 0xEF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xF0 - 0xF7
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF // 0xF8 - 0xFF
};
template<typename InputIterator, typename T>
inline bool string_to_signed_type_converter_impl_itr(InputIterator begin, InputIterator end, T& v)
{
if (0 == std::distance(begin,end))
return false;
v = 0;
InputIterator it = begin;
bool negative = false;
if ('+' == *it)
++it;
else if ('-' == *it)
{
++it;
negative = true;
}
if (end == it)
return false;
while(end != it)
{
const T digit = static_cast<T>(digit_table[static_cast<unsigned int>(*it++)]);
if (0xFF == digit)
return false;
v = (10 * v) + digit;
}
if (negative)
v *= -1;
return true;
}
ইনপুটআইটিরেটর স্বাক্ষরযুক্ত চর *, চর * বা স্টাডি :: স্ট্রিং পুনরাবৃত্তকারীগুলির হতে পারে এবং টি প্রত্যাশিত একটি স্বাক্ষরপ্রাপ্ত, যেমন স্বাক্ষরযুক্ত ইন্ট, ইনট বা দীর্ঘ
v = (10 * v) + digit;
এর পাঠ্যের মান সহ স্ট্রিং ইনপুটটি অযথা ওভারফ্লো হয় INT_MIN
। টেবিলটি প্রশ্নোত্তর মূল্য বনাম কেবলdigit >= '0' && digit <= '9'
আপনি সি ++ 11 থেকে থাকে, তাহলে উপযুক্ত সমাধান আজকাল সি ++ এ রূপান্তর ফাংশন পূর্ণসংখ্যা হয় <string>
: stoi
, stol
, stoul
, stoll
, stoull
। ভুল ইনপুট দেওয়া হলে তারা উপযুক্ত ব্যতিক্রম ছুঁড়ে দেয় এবং দ্রুত এবং ছোট ব্যবহার করেstrto*
ফণীর নীচে ফাংশন ।
আপনি যদি সি ++ এর পূর্ববর্তী পুনর্বিবেচনায় আটকে থাকেন তবে আপনার প্রয়োগে এই ফাংশনগুলি নকল করা আপনার পক্ষে ফরওয়ার্ডযোগ্য would
সি ++ 17 থেকে আপনি এখানে নথির মতো শিরোনাম std::from_chars
থেকে ব্যবহার করতে পারেন ।<charconv>
উদাহরণ স্বরূপ:
#include <iostream>
#include <charconv>
#include <array>
int main()
{
char const * str = "42";
int value = 0;
std::from_chars_result result = std::from_chars(std::begin(str), std::end(str), value);
if(result.error == std::errc::invalid_argument)
{
std::cout << "Error, invalid format";
}
else if(result.error == std::errc::result_out_of_range)
{
std::cout << "Error, value too big for int range";
}
else
{
std::cout << "Success: " << result;
}
}
বোনাস হিসাবে এটি হেক্সাডেসিমালের মতো অন্যান্য ঘাঁটিগুলিও পরিচালনা করতে পারে।
আমি ড্যান মোল্ডিংয়ের উত্তরটি পছন্দ করি , আমি এটিতে কিছুটা সি ++ স্টাইল যুক্ত করব:
#include <cstdlib>
#include <cerrno>
#include <climits>
#include <stdexcept>
int to_int(const std::string &s, int base = 0)
{
char *end;
errno = 0;
long result = std::strtol(s.c_str(), &end, base);
if (errno == ERANGE || result > INT_MAX || result < INT_MIN)
throw std::out_of_range("toint: string is out of range");
if (s.length() == 0 || *end != '\0')
throw std::invalid_argument("toint: invalid string");
return result;
}
এটি অন্তর্নিহিত রূপান্তর মাধ্যমে std :: স্ট্রিং এবং কনস্ট চর * উভয়ের পক্ষে কাজ করে। এটি বেস রূপান্তরকরণের জন্যও কার্যকর, যেমন সমস্ত to_int("0x7b")
এবং to_int("0173")
এবং to_int("01111011", 2)
এবং to_int("0000007B", 16)
এবং to_int("11120", 3)
এবং to_int("3L", 34);
123 ফেরত আসবে।
ভিন্ন std::stoi
এটা প্রাক সি ++ 11 কাজ করে। এছাড়াও বিপরীত std::stoi
, boost::lexical_cast
এবংstringstream
এটি "123hohoho" এর মতো অদ্ভুত স্ট্রিংগুলির ব্যতিক্রম ছুঁড়ে।
এনবি: এই ফাংশনটি নেতৃস্থানীয় স্পেসগুলি সহ্য করে তবে পিছনে স্থানগুলি নয়, অর্থাত্ ব্যতিক্রম ছোঁড়ে to_int(" 123")
123 ফেরত to_int("123 ")
দেয়। আপনার ব্যবহারের ক্ষেত্রে এটি কোড গ্রহণযোগ্য বা কোডটি সামঞ্জস্য করুন তা নিশ্চিত করুন।
এই জাতীয় অনুষ্ঠানটি এসটিএলের অংশ হতে পারে ...
আমি স্ট্রিংকে ইনটে রূপান্তর করার তিনটি উপায় জানি:
হয় স্টোই (স্ট্রিং টু ইনট) ফাংশনটি ব্যবহার করুন বা স্ট্রিংস্ট্রিমের সাথে চলুন, পৃথক রূপান্তরকরণের তৃতীয় উপায়, কোডটি নীচে রয়েছে:
1 ম পদ্ধতি
std::string s1 = "4533";
std::string s2 = "3.010101";
std::string s3 = "31337 with some string";
int myint1 = std::stoi(s1);
int myint2 = std::stoi(s2);
int myint3 = std::stoi(s3);
std::cout << s1 <<"=" << myint1 << '\n';
std::cout << s2 <<"=" << myint2 << '\n';
std::cout << s3 <<"=" << myint3 << '\n';
২ য় পদ্ধতি
#include <string.h>
#include <sstream>
#include <iostream>
#include <cstring>
using namespace std;
int StringToInteger(string NumberAsString)
{
int NumberAsInteger;
stringstream ss;
ss << NumberAsString;
ss >> NumberAsInteger;
return NumberAsInteger;
}
int main()
{
string NumberAsString;
cin >> NumberAsString;
cout << StringToInteger(NumberAsString) << endl;
return 0;
}
তৃতীয় পদ্ধতি - তবে পৃথক রূপান্তরকরণের জন্য নয়
std::string str4 = "453";
int i = 0, in=0; // 453 as on
for ( i = 0; i < str4.length(); i++)
{
in = str4[i];
cout <<in-48 ;
}
আমি ড্যানের উত্তর পছন্দ করি , ব্যতিক্রমগুলি এড়ানোর কারণে sp এম্বেড থাকা সিস্টেম বিকাশ এবং অন্যান্য নিম্ন স্তরের সিস্টেম বিকাশের জন্য, উপযুক্ত ব্যতিক্রম কাঠামো উপলব্ধ নাও থাকতে পারে।
একটি বৈধ স্ট্রিংয়ের পরে সাদা-স্পেসের জন্য একটি চেক যুক্ত করা হয়েছে ... এই তিনটি লাইনের
while (isspace(*end)) {
end++;
}
ত্রুটি পার্সিংয়ের জন্য একটি চেক যোগ করা হয়েছে।
if ((errno != 0) || (s == end)) {
return INCONVERTIBLE;
}
এখানে সম্পূর্ণ ফাংশন ..
#include <cstdlib>
#include <cerrno>
#include <climits>
#include <stdexcept>
enum STR2INT_ERROR { SUCCESS, OVERFLOW, UNDERFLOW, INCONVERTIBLE };
STR2INT_ERROR str2long (long &l, char const *s, int base = 0)
{
char *end = (char *)s;
errno = 0;
l = strtol(s, &end, base);
if ((errno == ERANGE) && (l == LONG_MAX)) {
return OVERFLOW;
}
if ((errno == ERANGE) && (l == LONG_MIN)) {
return UNDERFLOW;
}
if ((errno != 0) || (s == end)) {
return INCONVERTIBLE;
}
while (isspace((unsigned char)*end)) {
end++;
}
if (*s == '\0' || *end != '\0') {
return INCONVERTIBLE;
}
return SUCCESS;
}
" "
। কোনও রূপান্তর ঘটে না তখন strtol()
সেট করতে নির্দিষ্ট করা হয় না errno
। if (s == end) return INCONVERTIBLE;
কোনও রূপান্তর সনাক্ত করতে ব্যবহার করা ভাল । এবং তারপরে 2 এ if (*s == '\0' || *end != '\0')
সরলীকরণ করতে পারে এবং কোনও উদ্দেশ্য কার্যকর করতে পারে - এগুলি কখনই সত্য হয় না। if (*end)
|| l > LONG_MAX
|| l < LONG_MIN
আপনি এই সংজ্ঞায়িত পদ্ধতিটি ব্যবহার করতে পারেন।
#define toInt(x) {atoi(x.c_str())};
এবং যদি আপনি স্ট্রিং থেকে একটি পূর্ণসংখ্যায় রূপান্তর করতে চান তবে আপনি কেবল নিম্নলিখিতটি করবেন।
int main()
{
string test = "46", test2 = "56";
int a = toInt(test);
int b = toInt(test2);
cout<<a+b<<endl;
}
আউটপুট হবে 102।
atoi
গ্রহণযোগ্য যেমন উত্তরগুলির আলোকে "সি ++ উপায়" বলে মনে হচ্ছে না std::stoi()
।
আমি জানি এটি একটি পুরানো প্রশ্ন, তবে আমি এটি বহুবার এসে পৌঁছেছি এবং আজ পর্যন্ত, নিম্নলিখিত বৈশিষ্ট্যগুলির সাথে একটি সুন্দর টেম্পলেটযুক্ত সমাধান এখনও খুঁজে পাইনি:
সুতরাং, পরীক্ষার স্ট্র্যাপ সহ এটি আমার mine যেহেতু এটি হুডের নীচে সি ফাংশনগুলি স্ট্র্টল / স্ট্র্টল ব্যবহার করে, এটি সর্বদা সর্বদা উপলভ্য বৃহত্তম ধরণের রূপান্তর করে। তারপরে, আপনি যদি বৃহত্তম ধরণটি ব্যবহার না করে থাকেন তবে এটি আপনার ধরণের প্রবাহ (অধীন) প্রবাহিত হয়নি তা যাচাই করতে অতিরিক্ত পরিসর পরীক্ষা করে। এর জন্য, যদি কেউ সঠিকভাবে স্ট্র্টল / স্ট্র্টল বেছে নেয় তবে তার চেয়ে একটু পারফরম্যান্ট। যাইহোক, এটি শর্টস / চরগুলির জন্যও কাজ করে এবং আমার জ্ঞানের সেরা দিক থেকে এমন কোনও স্ট্যান্ডার্ড লাইব্রেরি ফাংশন উপস্থিত নেই যা তা করে।
উপভোগ করুন; আশা করি কেউ এটি দরকারী বলে মনে করেন।
#include <cstdlib>
#include <cerrno>
#include <limits>
#include <stdexcept>
#include <sstream>
static const int DefaultBase = 10;
template<typename T>
static inline T CstrtoxllWrapper(const char *str, int base = DefaultBase)
{
while (isspace(*str)) str++; // remove leading spaces; verify there's data
if (*str == '\0') { throw std::invalid_argument("str; no data"); } // nothing to convert
// NOTE: for some reason strtoull allows a negative sign, we don't; if
// converting to an unsigned then it must always be positive!
if (!std::numeric_limits<T>::is_signed && *str == '-')
{ throw std::invalid_argument("str; negative"); }
// reset errno and call fn (either strtoll or strtoull)
errno = 0;
char *ePtr;
T tmp = std::numeric_limits<T>::is_signed ? strtoll(str, &ePtr, base)
: strtoull(str, &ePtr, base);
// check for any C errors -- note these are range errors on T, which may
// still be out of the range of the actual type we're using; the caller
// may need to perform additional range checks.
if (errno != 0)
{
if (errno == ERANGE) { throw std::range_error("str; out of range"); }
else if (errno == EINVAL) { throw std::invalid_argument("str; EINVAL"); }
else { throw std::invalid_argument("str; unknown errno"); }
}
// verify everything converted -- extraneous spaces are allowed
if (ePtr != NULL)
{
while (isspace(*ePtr)) ePtr++;
if (*ePtr != '\0') { throw std::invalid_argument("str; bad data"); }
}
return tmp;
}
template<typename T>
T StringToSigned(const char *str, int base = DefaultBase)
{
static const long long max = std::numeric_limits<T>::max();
static const long long min = std::numeric_limits<T>::min();
long long tmp = CstrtoxllWrapper<typeof(tmp)>(str, base); // use largest type
// final range check -- only needed if not long long type; a smart compiler
// should optimize this whole thing out
if (sizeof(T) == sizeof(tmp)) { return tmp; }
if (tmp < min || tmp > max)
{
std::ostringstream err;
err << "str; value " << tmp << " out of " << sizeof(T) * 8
<< "-bit signed range (";
if (sizeof(T) != 1) err << min << ".." << max;
else err << (int) min << ".." << (int) max; // don't print garbage chars
err << ")";
throw std::range_error(err.str());
}
return tmp;
}
template<typename T>
T StringToUnsigned(const char *str, int base = DefaultBase)
{
static const unsigned long long max = std::numeric_limits<T>::max();
unsigned long long tmp = CstrtoxllWrapper<typeof(tmp)>(str, base); // use largest type
// final range check -- only needed if not long long type; a smart compiler
// should optimize this whole thing out
if (sizeof(T) == sizeof(tmp)) { return tmp; }
if (tmp > max)
{
std::ostringstream err;
err << "str; value " << tmp << " out of " << sizeof(T) * 8
<< "-bit unsigned range (0..";
if (sizeof(T) != 1) err << max;
else err << (int) max; // don't print garbage chars
err << ")";
throw std::range_error(err.str());
}
return tmp;
}
template<typename T>
inline T
StringToDecimal(const char *str, int base = DefaultBase)
{
return std::numeric_limits<T>::is_signed ? StringToSigned<T>(str, base)
: StringToUnsigned<T>(str, base);
}
template<typename T>
inline T
StringToDecimal(T &out_convertedVal, const char *str, int base = DefaultBase)
{
return out_convertedVal = StringToDecimal<T>(str, base);
}
/*============================== [ Test Strap ] ==============================*/
#include <inttypes.h>
#include <iostream>
static bool _g_anyFailed = false;
template<typename T>
void TestIt(const char *tName,
const char *s, int base,
bool successExpected = false, T expectedValue = 0)
{
#define FAIL(s) { _g_anyFailed = true; std::cout << s; }
T x;
std::cout << "converting<" << tName << ">b:" << base << " [" << s << "]";
try
{
StringToDecimal<T>(x, s, base);
// get here on success only
if (!successExpected)
{
FAIL(" -- TEST FAILED; SUCCESS NOT EXPECTED!" << std::endl);
}
else
{
std::cout << " -> ";
if (sizeof(T) != 1) std::cout << x;
else std::cout << (int) x; // don't print garbage chars
if (x != expectedValue)
{
FAIL("; FAILED (expected value:" << expectedValue << ")!");
}
std::cout << std::endl;
}
}
catch (std::exception &e)
{
if (successExpected)
{
FAIL( " -- TEST FAILED; EXPECTED SUCCESS!"
<< " (got:" << e.what() << ")" << std::endl);
}
else
{
std::cout << "; expected exception encounterd: [" << e.what() << "]" << std::endl;
}
}
}
#define TEST(t, s, ...) \
TestIt<t>(#t, s, __VA_ARGS__);
int main()
{
std::cout << "============ variable base tests ============" << std::endl;
TEST(int, "-0xF", 0, true, -0xF);
TEST(int, "+0xF", 0, true, 0xF);
TEST(int, "0xF", 0, true, 0xF);
TEST(int, "-010", 0, true, -010);
TEST(int, "+010", 0, true, 010);
TEST(int, "010", 0, true, 010);
TEST(int, "-10", 0, true, -10);
TEST(int, "+10", 0, true, 10);
TEST(int, "10", 0, true, 10);
std::cout << "============ base-10 tests ============" << std::endl;
TEST(int, "-010", 10, true, -10);
TEST(int, "+010", 10, true, 10);
TEST(int, "010", 10, true, 10);
TEST(int, "-10", 10, true, -10);
TEST(int, "+10", 10, true, 10);
TEST(int, "10", 10, true, 10);
TEST(int, "00010", 10, true, 10);
std::cout << "============ base-8 tests ============" << std::endl;
TEST(int, "777", 8, true, 0777);
TEST(int, "-0111 ", 8, true, -0111);
TEST(int, "+0010 ", 8, true, 010);
std::cout << "============ base-16 tests ============" << std::endl;
TEST(int, "DEAD", 16, true, 0xDEAD);
TEST(int, "-BEEF", 16, true, -0xBEEF);
TEST(int, "+C30", 16, true, 0xC30);
std::cout << "============ base-2 tests ============" << std::endl;
TEST(int, "-10011001", 2, true, -153);
TEST(int, "10011001", 2, true, 153);
std::cout << "============ irregular base tests ============" << std::endl;
TEST(int, "Z", 36, true, 35);
TEST(int, "ZZTOP", 36, true, 60457993);
TEST(int, "G", 17, true, 16);
TEST(int, "H", 17);
std::cout << "============ space deliminated tests ============" << std::endl;
TEST(int, "1337 ", 10, true, 1337);
TEST(int, " FEAD", 16, true, 0xFEAD);
TEST(int, " 0711 ", 0, true, 0711);
std::cout << "============ bad data tests ============" << std::endl;
TEST(int, "FEAD", 10);
TEST(int, "1234 asdfklj", 10);
TEST(int, "-0xF", 10);
TEST(int, "+0xF", 10);
TEST(int, "0xF", 10);
TEST(int, "-F", 10);
TEST(int, "+F", 10);
TEST(int, "12.4", 10);
TEST(int, "ABG", 16);
TEST(int, "10011002", 2);
std::cout << "============ int8_t range tests ============" << std::endl;
TEST(int8_t, "7F", 16, true, std::numeric_limits<int8_t>::max());
TEST(int8_t, "80", 16);
TEST(int8_t, "-80", 16, true, std::numeric_limits<int8_t>::min());
TEST(int8_t, "-81", 16);
TEST(int8_t, "FF", 16);
TEST(int8_t, "100", 16);
std::cout << "============ uint8_t range tests ============" << std::endl;
TEST(uint8_t, "7F", 16, true, std::numeric_limits<int8_t>::max());
TEST(uint8_t, "80", 16, true, std::numeric_limits<int8_t>::max()+1);
TEST(uint8_t, "-80", 16);
TEST(uint8_t, "-81", 16);
TEST(uint8_t, "FF", 16, true, std::numeric_limits<uint8_t>::max());
TEST(uint8_t, "100", 16);
std::cout << "============ int16_t range tests ============" << std::endl;
TEST(int16_t, "7FFF", 16, true, std::numeric_limits<int16_t>::max());
TEST(int16_t, "8000", 16);
TEST(int16_t, "-8000", 16, true, std::numeric_limits<int16_t>::min());
TEST(int16_t, "-8001", 16);
TEST(int16_t, "FFFF", 16);
TEST(int16_t, "10000", 16);
std::cout << "============ uint16_t range tests ============" << std::endl;
TEST(uint16_t, "7FFF", 16, true, std::numeric_limits<int16_t>::max());
TEST(uint16_t, "8000", 16, true, std::numeric_limits<int16_t>::max()+1);
TEST(uint16_t, "-8000", 16);
TEST(uint16_t, "-8001", 16);
TEST(uint16_t, "FFFF", 16, true, std::numeric_limits<uint16_t>::max());
TEST(uint16_t, "10000", 16);
std::cout << "============ int32_t range tests ============" << std::endl;
TEST(int32_t, "7FFFFFFF", 16, true, std::numeric_limits<int32_t>::max());
TEST(int32_t, "80000000", 16);
TEST(int32_t, "-80000000", 16, true, std::numeric_limits<int32_t>::min());
TEST(int32_t, "-80000001", 16);
TEST(int32_t, "FFFFFFFF", 16);
TEST(int32_t, "100000000", 16);
std::cout << "============ uint32_t range tests ============" << std::endl;
TEST(uint32_t, "7FFFFFFF", 16, true, std::numeric_limits<int32_t>::max());
TEST(uint32_t, "80000000", 16, true, std::numeric_limits<int32_t>::max()+1);
TEST(uint32_t, "-80000000", 16);
TEST(uint32_t, "-80000001", 16);
TEST(uint32_t, "FFFFFFFF", 16, true, std::numeric_limits<uint32_t>::max());
TEST(uint32_t, "100000000", 16);
std::cout << "============ int64_t range tests ============" << std::endl;
TEST(int64_t, "7FFFFFFFFFFFFFFF", 16, true, std::numeric_limits<int64_t>::max());
TEST(int64_t, "8000000000000000", 16);
TEST(int64_t, "-8000000000000000", 16, true, std::numeric_limits<int64_t>::min());
TEST(int64_t, "-8000000000000001", 16);
TEST(int64_t, "FFFFFFFFFFFFFFFF", 16);
TEST(int64_t, "10000000000000000", 16);
std::cout << "============ uint64_t range tests ============" << std::endl;
TEST(uint64_t, "7FFFFFFFFFFFFFFF", 16, true, std::numeric_limits<int64_t>::max());
TEST(uint64_t, "8000000000000000", 16, true, std::numeric_limits<int64_t>::max()+1);
TEST(uint64_t, "-8000000000000000", 16);
TEST(uint64_t, "-8000000000000001", 16);
TEST(uint64_t, "FFFFFFFFFFFFFFFF", 16, true, std::numeric_limits<uint64_t>::max());
TEST(uint64_t, "10000000000000000", 16);
std::cout << std::endl << std::endl
<< (_g_anyFailed ? "!! SOME TESTS FAILED !!" : "ALL TESTS PASSED")
<< std::endl;
return _g_anyFailed;
}
StringToDecimal
ব্যবহারকারী-ভূমি পদ্ধতি; এটি অত্যধিক লোড হয়েছে যাতে এটি এর মতো হয়:
int a; a = StringToDecimal<int>("100");
অথবা এটা:
int a; StringToDecimal(a, "100");
আমি int টাইপ পুনরাবৃত্তি ঘৃণা করি, তাই পরে পছন্দ। এটি নিশ্চিত করে যে 'ক' এর ধরণের পরিবর্তন হলে খারাপ ফলাফল না পাওয়া যায়। আমি আশা করি সংকলকটি এটির মতো নির্ধারণ করতে পারে:
int a; a = StringToDecimal("100");
... তবে, সি ++ টেম্পলেট রিটার্নের ধরণগুলি হ্রাস করে না, তাই এটি আমার পক্ষে সেরা।
বাস্তবায়ন বেশ সহজ:
CstrtoxllWrapper
উভয়কে মোড়ানো strtoull
এবং strtoll
, টেমপ্লেট টাইপের স্বাক্ষরিত নেসের উপর ভিত্তি করে যা কিছু প্রয়োজন তা কল করা এবং কিছু অতিরিক্ত গ্যারান্টি সরবরাহ করার জন্য (যেমন স্বাক্ষরিত না হলে নেতিবাচক ইনপুটটি অনুমোদিত নয় এবং এটি নিশ্চিত করে যে পুরো স্ট্রিংটি রূপান্তরিত হয়েছিল)।
CstrtoxllWrapper
সংকলকটিতে উপলব্ধ বৃহত্তম ধরণের (দীর্ঘ দীর্ঘ / স্বাক্ষরযুক্ত দীর্ঘ দীর্ঘ) ব্যবহার করে StringToSigned
এবং এর StringToUnsigned
সাথে ব্যবহৃত হয় ; এটি সর্বাধিক রূপান্তর সম্পাদন করতে দেয়। তারপরে, যদি এটি প্রয়োজন হয়, StringToSigned
/ StringToUnsigned
অন্তর্নিহিত ধরণের উপর চূড়ান্ত পরিসীমা চেক করে। পরিশেষে, শেষ-পয়েন্ট পদ্ধতি,StringToDecimal
সিদ্ধান্ত নেয় যে অন্তর্নিহিত ধরণের স্বাক্ষরিত নেসের উপর ভিত্তি করে স্ট্রিংটো * টেম্পলেট পদ্ধতিগুলির মধ্যে কোনটি কল করতে হবে।
আমি মনে করি সংকলক দ্বারা বেশিরভাগ জাঙ্কটি অপ্টিমাইজ করা যেতে পারে; প্রায় সবই সংকলন-সময় নির্বাহী হওয়া উচিত। এই দিক সম্পর্কে যে কোনও মন্তব্য আমার কাছে আকর্ষণীয় হবে!
long long
পরিবর্তে কেন intmax_t
?
if (ePtr != str)
। আরও, এর isspace((unsigned char) *ePtr)
নেতিবাচক মানগুলি সঠিকভাবে পরিচালনা করতে ব্যবহার করুন *ePtr
।
সি তে, আপনি ব্যবহার করতে পারেন int atoi (const char * str)
,
সি-স্ট্রিং স্ট্রাস্ট করে এর সামগ্রীটিকে একটি অবিচ্ছেদ্য সংখ্যা হিসাবে ব্যাখ্যা করে, যা টাইপ ইন্টের মান হিসাবে ফিরে আসে।
atoi
প্রশ্নের সাথে লিঙ্ক করেছি , আমি এটি সম্পর্কে অবহিত। প্রশ্নটি পরিষ্কারভাবে সি সম্পর্কে নয়, সি ++ সম্পর্কে। -1