2012-01-16 13 views
6

मैं एक समारोह है से पढ़ने में ifstream में एक पंक्ति पर एक चर (पूर्णांक, डबल, या बुलियन) का मूल्य को पढ़ने के लिए:सी में बाइट-क्रम के निशान पर ध्यान न दें ++, एक धारा

template <typename Type> 
void readFromFile (ifstream &in, Type &val) 
{ 
    string str; 
    getline (in, str); 
    stringstream ss(str); 
    ss >> val; 
} 

हालांकि , यह पहली पंक्ति की शुरुआत में बीओएम (byte order mark) डालने वाले संपादकों के साथ बनाई गई टेक्स्ट फ़ाइलों पर विफल रहता है, दुर्भाग्य से {नोट, वर्ड} पैड शामिल है। str की शुरुआत में उपस्थित होने पर बाइट-ऑर्डर चिह्न को अनदेखा करने के लिए मैं इस फ़ंक्शन को कैसे संशोधित कर सकता हूं?

+0

आप UTF-8 बीओएम मतलब है? यह बहुत आर्केन है ... –

उत्तर

11

(मैं यह सोचते कर रहा हूँ आप Windows पर हैं, U + FEFF UTF-8 फ़ाइलों में एक हस्ताक्षर के रूप में प्रयोग के बाद से ज्यादातर एक Windows बात है और बस कहीं और बचा जाना चाहिए)

आप के रूप में फ़ाइल को खोलने सकता है एक यूटीएफ -8 फ़ाइल और फिर यह देखने के लिए जांचें कि पहला अक्षर यू + एफईएफएफ है या नहीं। आप सामान्य char आधारित fstream खोलकर ऐसा कर सकते हैं और फिर wbuffer_convert का उपयोग किसी अन्य एन्कोडिंग में कोड इकाइयों की एक श्रृंखला के रूप में करने के लिए कर सकते हैं। VS2010 को अभी तक char32_t के लिए बहुत अच्छा समर्थन नहीं है, इसलिए निम्नलिखित wchar_t में यूटीएफ -16 का उपयोग करता है।

std::fstream fs(filename); 
std::wbuffer_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t> wb(fs.rdbuf()); 
std::wistream is(&wb); 
// if you don't do this on the stack remember to destroy the objects in reverse order of creation. is, then wb, then fs. 
std::wistream::int_type ch = is.get(); 
const std::wistream::int_type ZERO_WIDTH_NO_BREAK_SPACE = 0xFEFF 
if(ZERO_WIDTH_NO_BREAK_SPACE != ch) 
    is.putback(ch); 

// now the stream can be passed around and used without worrying about the extra character in the stream. 

int i; 
readFromStream<int>(is,i); 

याद रखें कि यह, अपने stringstream पर एक समग्र रूप से फ़ाइल धारा पर किया जाना चाहिए, readFromFile अंदर नहीं अनदेखी U + FEFF केवल अगर यह पूरी फ़ाइल में बहुत पहले चरित्र है किया जाना चाहिए, पर यदि क्योंकि सब। यह कहीं और नहीं किया जाना चाहिए।

std::fstream fs(filename); 
char a,b,c; 
a = fs.get(); 
b = fs.get(); 
c = fs.get(); 
if(a!=(char)0xEF || b!=(char)0xBB || c!=(char)0xBF) { 
    fs.seekg(0); 
} else { 
    std::cerr << "Warning: file contains the so-called 'UTF-8 signature'\n" 
} 

:

दूसरी ओर, यदि आप एक चार आधारित धारा का उपयोग कर खुश हैं और बस को छोड़ U + FEFF वर्तमान तो जेम्स Kanze सुझाव इसलिए यहाँ अच्छा लगता है, तो चाहते हैं एक कार्यान्वयन है इसके अतिरिक्त यदि आप wchar_t आंतरिक रूप से codecvt_utf8_utf16 और codecvt_utf8 पहलुओं का उपयोग करना चाहते हैं तो एक मोड है जो आपके लिए 'बीओएम' का उपभोग कर सकता है। एकमात्र समस्या यह है कि wchar_t व्यापक रूप से इन दिनों बेकार होने के लिए मान्यता प्राप्त है * और इसलिए आपको शायद ऐसा नहीं करना चाहिए। क्योंकि यह सिर्फ एक बात करने के लिए निर्दिष्ट किया जाता है

std::wifstream fin(filename); 
fin.imbue(std::locale(fin.getloc(), new std::codecvt_utf8_utf16<wchar_t, 0x10FFFF, std::consume_header)); 

* wchar_t बेकार है, एक निश्चित आकार डेटा प्रकार प्रदान करें जो लोकेल के चरित्र प्रदर्शन में किसी भी कोड बिंदु का प्रतिनिधित्व कर सकता है। यह एक आम प्रतिनिधित्व प्रदान नहीं करता है के बीच स्थानों (यानी, एक ही wchar_t मूल्य अलग अलग स्थानों में विभिन्न चरित्रों ताकि आप जरूरी wchar_t में बदल सकते हैं नहीं, एक और स्थान पर स्विच, और फिर आदेश iconv करने के लिए char वापस करने के लिए परिवर्तित किया जा सकता है - एन्कोडिंग रूपांतरण की तरह।)

निश्चित आकार का प्रतिनिधित्व स्वयं दो कारणों से बेकार है; सबसे पहले, कई कोड बिंदुओं का अर्थपूर्ण अर्थ होता है और इसलिए पाठ को समझने का अर्थ है कि आपको कई कोड बिंदुओं को संसाधित करना होगा।दूसरा, विंडोज जैसे कुछ प्लेटफॉर्म यूटीएफ -16 को wchar_t एन्कोडिंग के रूप में उपयोग करते हैं, जिसका अर्थ है कि एक wchar_t भी एक कोड बिंदु मान भी आवश्यक नहीं है। (UTF-16 का उपयोग करते हुए चाहे इस तरह से भी अधिक अनुरूप करने के लिए मानक अस्पष्ट है मानक है कि एक स्थान द्वारा समर्थित हर चरित्र एक भी wchar_t मूल्य के रूप में प्रदर्शनीय हो की आवश्यकता है,। कोई स्थान बीएमपी के बाहर किसी भी चरित्र का समर्थन करता है, तो UTF-16 के हो सकता है अनुरूप के रूप में देखा।)

4

आपको पहले बाइट या दो स्ट्रीम को पढ़ना शुरू करना है, और यह तय करना है कि यह बीओएम का हिस्सा है या नहीं। यह दर्द का थोड़ा सा है, क्योंकि आप केवल putback एक बाइट कर सकते हैं, जबकि आप आमतौर पर चार पढ़ना चाहते हैं। फ़ाइल को खोलने का सबसे आसान समाधान है, प्रारंभिक बाइट्स को पढ़ें, याद रखें कि आपको कितने छोड़ने की आवश्यकता है, फिर पर वापस जाएं और उन्हें छोड़ दें।

+2

यूटीएफ 8 बीओएम * तीन * बाइट लंबा है। मुझे लगता है कि स्ट्रीम बाइट-साइज्ड है, क्योंकि यह 'char'-stream है, इसलिए यह वास्तव में यूटीएफ 16 या यूटीएफ 32 नहीं हो सकता है। –

+0

@ केरेकस्क एसबी आप यूटीएफ -16 और यूटीएफ -32 को 'चार' धाराओं के रूप में पढ़ सकते हैं, बशर्ते आपके पास उपयुक्त लोकेल हो। दूसरी तरफ, मुझे नहीं पता कि वे बीओएम के साथ क्या करेंगे। (आईएमएचओ, बीओएम वास्तव में स्ट्रीम की ज़िम्मेदारी होनी चाहिए या इसके बजाय 'कोडेकैट' पहलू का उपयोग करना चाहिए।) –

+0

मैं स्थानीय लोगों के बारे में भूल गया था। क्या आपको अपना खुद का लिखना है, या मानक में यूटीएफ -16 है? –

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