मैं करूंगा एक पूरी तरह से अलग दृष्टिकोण की पेशकश करना: अपनी इनपुट स्ट्रिंग लें, इसे स्वयं टोकन करें, और फिर boost::lexical_cast<T>
का उपयोग करके अलग-अलग फ़ील्ड को परिवर्तित करें।
कारण: मैंने एक दोपहर बर्बाद कर दिया जिसमें दो int और 2 डबल फ़ील्ड होते हैं, जो रिक्त स्थान से अलग होते हैं।
int i, j;
double x, y;
std::istringstream ins{str};
ins >> i >> j >> x >> y;
// how to check errors???...
`"5 3 9.9e+01 5.5e+02"`
सही ढंग से के रूप में सही इनपुट ऐसे पार्स करता है, लेकिन इस के साथ समस्या यह पता नहीं लगा पाया:
`"5 9.6e+01 5.5e+02"`
क्या होता है कि i
सेट हो जाएगा निम्न कार्य 5 (ठीक), j
9 (??), x
से 6.0 (= 0.6e + 01), y
से 550 (ठीक) पर सेट किया जाएगा। मैं failbit
सेट नहीं होने के लिए आश्चर्यचकित था ... (मंच जानकारी: ओएस एक्स 10.9, ऐप्पल क्लैंग ++ 6.0, सी ++ 11 मोड)।
बेशक आप अब कह सकते हैं, "लेकिन प्रतीक्षा करें, मानक कहता है कि यह ऐसा होना चाहिए", और आप सही हो सकते हैं, लेकिन यह जानकर कि यह एक बग की बजाय एक विशेषता है, यदि आप चाहते हैं तो दर्द को कम नहीं करता है कोड के मील लिखने के बिना उचित त्रुटि जांच करने के लिए।
ओटीओएच, यदि आप "मारियस" उत्कृष्ट tokeniser function का उपयोग करते हैं और पहले व्हाइटस्पेस पर str
विभाजित करते हैं तो अचानक सब कुछ बहुत आसान हो जाता है। टोकनिसर का थोड़ा संशोधित संस्करण यहां दिया गया है। मैंने तारों के वेक्टर को वापस करने के लिए इसे फिर से लिखा; मूल एक टेम्पलेट है जो टोकन को एक कंटेनर में तारों में परिवर्तनीय तत्वों के साथ रखता है। (जो लोग इस तरह के एक सामान्य दृष्टिकोण की जरूरत के लिए ऊपर मूल लिंक से परामर्श लें।)
// \param str: the input string to be tokenized
// \param delimiters: string of delimiter characters
// \param trimEmpty: if true then empty tokens will be trimmed
// \return a vector of strings containing the tokens
std::vector<std::string> tokenizer(
const std::string& str,
const std::string& delimiters = " ",
const bool trimEmpty = false
) {
std::vector<std::string> tokens;
std::string::size_type pos, lastPos = 0;
const char* strdata = str.data();
while(true) {
pos = str.find_first_of(delimiters, lastPos);
if(pos == std::string::npos) {
// no more delimiters
pos = str.length();
if(pos != lastPos || !trimEmpty) {
tokens.emplace_back(strdata + lastPos, pos - lastPos);
}
break;
} else {
if(pos != lastPos || !trimEmpty) {
tokens.emplace_back(strdata + lastPos, pos - lastPos);
}
}
lastPos = pos + 1;
}
return tokens;
}
और उसके बाद सिर्फ इस तरह इसका इस्तेमाल (ParseError
कुछ अपवाद वस्तु है):
std::vector<std::string> tokens = tokenizer(str, " \t", true);
if (tokens.size() < 4)
throw ParseError{"Too few fields in " + str};
try {
unsigned int i{ boost::lexical_cast<unsigned int>(tokens[0]) },
j{ boost::lexical_cast<unsigned int>(tokens[1]) };
double x{ boost::lexical_cast<double>(tokens[2]) },
y{ boost::lexical_cast<double>(tokens[3]) };
// print or process i, j, x, y ...
} catch(const boost::bad_lexical_cast& error) {
throw ParseError{"Could not parse " + str};
}
नोट: आप कर सकते हैं यदि आप चाहें तो Boost split या tokenizer का उपयोग करें, लेकिन वे Marius 'टोकनिसर (कम से कम मेरे पर्यावरण में) से धीमे थे।
अद्यतन: boost::lexical_cast<T>
के बजाय आप सी ++ 11 "std::sto*
" कार्यों का उपयोग कर सकते हैं (उदाहरण के लिए stoi
किसी पूर्णांक के लिए एक स्ट्रिंग टोकन कन्वर्ट करने के लिए)। ये दो प्रकार के अपवाद फेंकते हैं: std::invalid_argument
यदि रूपांतरण नहीं किया जा सका और std::out_of_range
यदि परिवर्तित मूल्य का प्रतिनिधित्व नहीं किया जा सकता है। आप या तो इन अलग-अलग या उनके माता-पिता std::runtime_error
को पकड़ सकते हैं। उपर्युक्त उदाहरण कोड में संशोधन पाठक के लिए एक अभ्यास के रूप में छोड़ा गया है :-)
कोई जवाब नहीं, केवल एक नोट: टाइप करें 'टी' के टीएमपी-वेरिएबल का उपयोग करने पर विचार करें क्योंकि आप 'टी' में भी ओवरराइड करेंगे मामला 'e.eof()' गलत है। – Mene
यदि आप 'i.peek()' करते हैं तो आपको 'EOF' वापस मिल जाता है –