2012-01-21 14 views
7

मेरा कोड टेक्स्ट फ़ाइल Input_File_Name से हस्ताक्षरित int चर को पढ़ता है।ifstream का उपयोग कर, फ़ाइल से सही ढंग से हस्ताक्षरित int चर को कैसे पढ़ा जाए?

unsigned int Column_Count; //Cols 
unsigned int Row_Count;//Rows 

try { 
    ifstream input_stream; 
    input_stream.open(Input_File_Name,ios_base::in); 
    if (input_stream) { 
     //if file is opened 
     input_stream.exceptions(ios::badbit | ios::failbit); 
     input_stream>>Row_Count; 
     input_stream>>Column_Count; 


    } else { 
     throw std::ios::failure("Can't open input file"); 
     //cout << "Error: Can't open input file" << endl; 
    } 

} catch (const ios::failure& error) { 
    cout << "Oh No!!" << error.what() << endl;   
} catch (const exception& error) { 
    cout << error.what() <<"Oh No!!" << endl; 
} catch (...) { 
    cout << "Unknown exception" << endl; 
} 

यह उत्कृष्ट काम करता है। लेकिन जब मैं एक गलत डेटा

33abcd4 567fg8 

यह इस तरह से काम करता है के साथ पाठ फ़ाइल को भरने:

input_stream>>Row_Count; //Row_Count = 33; 
input_stream>>Column_Count; // throws an ios::failure exception 

क्यों नहीं इस लाइन input_stream>>Row_Count; फेंक अपवाद? जैसा कि मैंने समझा, इनपुट_स्ट्रीम किसी भी गैर-संख्यात्मक प्रतीक को डेलीमीटर के रूप में मानता है, और अगले चरण पर यह "abcd" पढ़ने की कोशिश करता है। ऐसा है क्या? कैसे जबकि "33abcd4" पढ़ने सीमांकक कोड input_stream>>Row_Count; की इस पंक्ति से एक ios::failure अपवाद के रूप में एक अंतरिक्ष प्रतीक स्थापित करने के लिए?

iter_type do_get(iter_type, iter_type, ios_base&, ios_base::iostate&, T& v) const 

जहां टी में से एक है:

#include <iostream> 
#include <locale> 

class my_num_get : public std::num_get<char> { 
protected: 
    iter_type do_get(iter_type in, iter_type end, std::ios_base& str, std::ios_base::iostate& err, unsigned int& v) const 
    { 
     in = std::num_get<char>::do_get(in, end, str, err, v); 
     if(in != end && !std::isspace(*in, str.getloc())) 
      err |= std::ios_base::failbit; 
     return in; 
    } 
}; 

int main() { 
    using namespace std; 
    cin.imbue(std::locale(cin.getloc(), new my_num_get)); 
    cin.exceptions(ios_base::badbit | ios_base::failbit); 
    try { 
     unsigned int x; 
     cin >> x; 
    } catch(const std::exception &e) { 
     cerr << e.what() << "\n"; 
    } 
} 

आप इस अन्य प्रकारों के लिए भी काम करने के लिए चाहते हैं, तो एक ही तरह से निम्नलिखित को लागू:

+1

यह सिर्फ 'ऑपरेटर >>' काम करता है; यह '33' निकालेगा और फिर रुक जाएगा, 'abcd' अगली कॉल के लिए 'ऑपरेटर >>' पर स्ट्रीम में रहता है। आप इसके बजाय एक स्ट्रिंग में '33abcd4' पढ़ सकते हैं और फिर इसमें गैर-संख्यात्मक वर्णों की जांच कर सकते हैं। साथ ही, यदि आपके पास हालिया कंपाइलर है जो C++ 11 का समर्थन करता है, तो जांचें कि मानक लाइब्रेरी 'std :: stoull' प्रदान करती है या नहीं। – jrok

उत्तर

4

एक पूर्णांक मूल्य के सामान्य निष्कर्षण सफल होता है स्ट्रीम में कोई भी पूर्णांक मान पढ़ सकते हैं। यही है, अगर एक पूर्णांक के पढ़ने के बाद वैकल्पिक रूप से कम से कम एक अंक होता है तो सफल होता है। सामान्य निष्कर्षण संचालन नहीं कोशिश अधिक पढ़ने के लिए करते हैं, विशेष रूप से वे अगले खाली स्थान के खोजने की कोशिश नहीं करते।

यह की आवाज़ से, आप अगर वहाँ नहीं है यकीन है कि एक खाली स्थान के अपना नंबर निम्नलिखित है कि वहाँ हो सकता है और असफल करना चाहते हैं।

  1. एक सरल जोड़तोड़ जो धारा एक खाली स्थान के चरित्र पर होने के लिए जाँच करता है बनाएँ: मैं दो अलग-अलग दृष्टिकोण यह करने के लिए के बारे में सोच सकते हैं। हालांकि, इसका मतलब है कि आप in >> value >> is_space जैसे कुछ का उपयोग करके अपने मूल्यों को पढ़ेंगे।
  2. एक कस्टम std::num_get<char> पहलू बनाएं, इसे std::locale में स्थापित करें, और imbue() इस std::locale को अपनी स्ट्रीम में स्थापित करें। यह थोड़ा और अधिक शामिल है लेकिन पूर्णांक पढ़ने के तरीके में किसी भी बदलाव की आवश्यकता नहीं है।

    std::istream& is_space(std::istream& in) 
    { 
        if (!std::isspace(in.peek())) 
        { 
         in.setstate(std::ios_base::failbit); 
        } 
        return in; 
    } 
    

    अब, और अधिक दिलचस्प तरीके से नंबर बदल पाठ किया जाता है और मैं मैं सिर्फ मानक पुस्तकालय वर्गों के एक नंबर ज्यादातर लोगों को काफी हैं नाम दिया था पर शक:

इस तरह एक जोड़तोड़ बनाना काफी तुच्छ है अनभिज्ञ है। तो, आइए इसके लिए एक उदाहरण भी जल्दी से टाइप करें। मैं पहलू को केवल unsigned int से निपटने के लिए बदल दूंगा: अन्य अभिन्न प्रकारों के लिए ऐसा करने के लिए इसे और अधिक कार्यों को ओवरराइड करना आवश्यक है।

class num_get: 
    public std::num_get<char> 
{ 
    iter_type do_get(iter_type it, iter_type end, 
        std::ios_base& ios, std::ios_base::iostate& err, 
        unsigned int& value) const 
    { 
     it = std::num_get<char>::do_get(it, end, ios, err, value); 
     if (it != end && !isspace(static_cast<unsigned char>(*it))) 
     { 
      err |= std::ios_base::failbit; 
     } 
     return it; 
    } 
}; 

यह सब करता है std::num_get<char> से एक वर्ग निकाले जाते हैं और इसकी आभासी कार्यों में से एक ओवरराइड करने के लिए है: तो, यहाँ std::num_get<char> पहलू के लिए एक स्थानापन्न है। इस समारोह का कार्यान्वयन काफी सीधे आगे है: बेस क्लास को प्रतिनिधि द्वारा मूल्य पढ़ने के साथ शुरू करें (मुझे अभी एहसास हुआ है कि वर्चुअल फ़ंक्शंस वास्तव में निजी की बजाय सुरक्षित रखना चाहते हैं जैसा कि मैंने पहले किया था लेकिन यह एक पूरी तरह से अलग चर्चा है) । यह सफल होने के बावजूद (यदि यह नहीं था, तो यह गलती में एक त्रुटि स्थिति स्थापित करेगा) ओवरराइड जांच करता है कि क्या कोई अन्य चरित्र उपलब्ध है और यदि ऐसा है, तो यह जांचता है कि यह एक जगह है और यदि std::ios_base::failbit सेट नहीं है त्रुटि परिणाम err

क्या रहता है एक std::locale में इस विशेष पहलू का उपयोग करें और एक धारा में नया std::locale हुक करने धारा स्थापित करने के लिए है:

std::locale loc(std::locale(), new num_get); 
in.imbue(loc); 

std::locale रों और उसके पहलुओं आंतरिक संदर्भ में गिने जाते हैं, यानी आप shouldn संकेतक को पॉकेट पर ट्रैक न रखें और आपको std::locale को या तो रखने की आवश्यकता नहीं है। यदि imbue() को बनाया गया है या आप इस संशोधित तर्क का हर जगह उपयोग करना चाहते हैं, तो आप वैश्विक std::locale सेट कर सकते हैं जिसका उपयोग कस्टम std::num_get<char> पहलू का उपयोग करने के लिए किसी भी नव निर्मित स्ट्रीम को प्रारंभ करने के लिए किया जाता है।

2

आप इसे इस तरह से कर सकते हैं bool, long, long long, unsigned short, unsigned long, unsigned long long, float, double, long double और void*

संबंधित मुद्दे