सारांश
यह पाठ पाठ्यक्रम की सातवीं इकाई, टेक्स्ट और फ़ाइलें, को समाप्त करता है। यह परिचय के उस प्रोग्राम को, जो बिना किसी चेतावनी के डेटा खो देता था और ASCII से बाहर के वर्णों वाले नामों को गलत मापता था, सीखी गई बातों से फिर लिखता है; स्ट्रिंग से फ़ाइल के फ़ॉर्मेट तक अवधारणाओं की शृंखला को फिर से बनाता है; उसमें से जो किसी भी भाषा में लागू होता है उसे C++ की अपनी बातों से अलग करता है; इकाई के अपरिभाषित व्यवहार को, जिसे डिटेक्टर रोकता है और जिसे कोई नहीं देखता उसके साथ, एकत्र करता है; समापन मूल्यांकन में प्रवेश मूल्यांकन की क्षमताओं को दोहराता है; और इकाई को जोड़ने वाली छह चुनौतियों के साथ समाप्त होता है।
अधिगम उद्देश्य
- वास्तविक टेक्स्ट को उसकी एन्कोडिंग के साथ संसाधित करना: किसी स्ट्रिंग के बाइटों का पूर्वानुमान लगाना, उसके वर्ण गिनना और UTF-8 को तोड़ने वाली संक्रियाओं से बचना।
- इनपुट और फ़ाइलों को मज़बूती से पढ़ना, अमान्य डेटा को डेटा के अंत से अलग पहचानना और हर डेटा को पूरे टेक्स्ट के रूप में परखना।
- निर्धारित फ़ॉर्मेट वाली परिणाम-फ़ाइलें बनाना, और हर अमान्य पंक्ति की उसकी संख्या के साथ रिपोर्ट करना।
- इकाई के अपरिभाषित व्यवहार (लटकता व्यू, स्ट्रिंग से बाहर का सूचकांक) को पहचानना और उसे उन परिभाषित विफलताओं से अलग करना जो उतनी ही चुपचाप निकल जाती हैं।
- इकाई की सीख में से जो किसी भी भाषा में लागू होता है उसे C++ की अपनी बातों से अलग करना।
इकाई की उपलब्धियाँ
इस इकाई ने टेक्स्ट को डेटा के रूप में बरतना सिखाने और ऐसे प्रोग्राम बनाने का लक्ष्य रखा था जो खराब फ़ॉर्मेट वाले इनपुट के सामने ढहे बिना फ़ाइलें पढ़ें और लिखें। यह लक्ष्य केवल उसी के सहारे हासिल हुआ जिसे पाठ परिचय ने पहले से ज्ञात घोषित किया था: इकाई 2 से कोड के रूप में वर्ण, इकाई 3 से बिट, इकाई 6 से वेक्टर और रिकॉर्ड, और इकाई 5 से अनुबंध वाले फ़ंक्शन। अंकों की सूची का वह प्रोग्राम, जो >> ऑपरेटर से पढ़ने के कारण अनु शर्मा और विकास को खो देता था और “राजेश” को “Carmen” से लंबा मानता था, अब इस तरह लिखा जाता है: वह फ़ाइल की पंक्तियाँ पढ़ता है, अंतिम रिक्त स्थान पर अंक को अलग करता है, उसे parseInt फ़ंक्शन (पाठ इनपुट को सही ढंग से पढ़ना वाला) से परखता है, अमान्य पंक्तियों की रिपोर्ट त्रुटि-स्ट्रीम में करता है, नामों को वर्णों में मापता है और सूची को दूसरी फ़ाइल में छोड़ता है। ताकि उदाहरण अपने आप में पूरा रहे, प्रोग्राम पहले डेटा-फ़ाइल लिखता है; वास्तविक उपयोग में वह फ़ाइल पहले से मौजूद होगी।
#include <charconv>#include <cstddef>#include <fstream>#include <iostream>#include <print>#include <string>#include <string_view>// परखता है कि टेक्स्ट ठीक-ठीक एक पूर्णांक है या नहीं।// पूर्व-शर्त: कोई नहीं।// पश्च-शर्त: वही जो पाठ “इनपुट को सही ढंग से पढ़ना” में है।bool parseInt(std::string_view text, int& value){ int result{}; const auto last{text.data() + text.size()}; const auto [stop, error]{std::from_chars(text.data(), last, result)}; if (error != std::errc{} || stop != last) { return false; } value = result; return true;}// UTF-8 टेक्स्ट के वर्णों की संख्या।// पूर्व-शर्त: text मान्य UTF-8 है।// पश्च-शर्त: text के वर्णों (बाइटों नहीं) की संख्या लौटाता है।std::size_t letterCount(std::string_view text){ std::size_t count{0}; for (const char c : text) { if ((c & 0xC0) != 0x80) { ++count; } } return count;}int main(){ { std::ofstream out{"grades.txt"}; std::println(out, "Carmen 65\nराजेश 70\nअनु शर्मा 58\nविकास छह\nसुनील 61"); } std::ifstream in{"grades.txt"}; std::ofstream report{"report.txt"}; if (!in || !report) { std::println(std::cerr, "फ़ाइलें खोली नहीं जा सकीं"); return 1; } std::string line{}; std::string longest{}; int lineNumber{0}; while (std::getline(in, line)) { ++lineNumber; const std::size_t space{line.rfind(' ')}; int grade{}; if (space == std::string::npos || !parseInt(std::string_view{line}.substr(space + 1), grade)) { std::println(std::cerr, "पंक्ति {} अमान्य: “{}”", lineNumber, line); continue; } const std::string name{line.substr(0, space)}; std::println(report, "{:<10}{:>3}", name, grade); if (letterCount(name) > letterCount(longest)) { longest = name; } } std::println("सबसे लंबा नाम: {} ({} वर्ण)", longest, letterCount(longest));}पंक्ति 4 अमान्य: “विकास छह”सबसे लंबा नाम: अनु शर्मा (9 वर्ण)स्क्रीन पर केवल त्रुटि-संदेश और निष्कर्ष दिखाई देते हैं। सूची फ़ाइल में है, और प्रोग्राम चलाने के बाद उसे cat कमांड से (PowerShell में Get-Content कमांड से) देखा जा सकता है:
$ cat report.txtCarmen 65राजेश 70अनु शर्मा 58सुनील 61हर भाग परिचय की किसी एक कमी का उत्तर देता है। पंक्ति-दर-पंक्ति पढ़ना और rfind फ़ंक्शन रिक्त स्थान वाले नामों को संभव बनाते हैं; npos मान और parseInt फ़ंक्शन विकास की पंक्ति को अस्वीकार करते हैं, उसकी संख्या के साथ रिपोर्ट करते हैं और सुनील की पंक्ति पर आगे बढ़ते हैं; letterCount फ़ंक्शन वर्ण गिनता है, इसलिए नौ वर्णों (कोड पॉइंट) और पच्चीस बाइटों वाला “अनु शर्मा” उचित रूप से जीतता है; और report.txt फ़ाइल तब पूरी होती है जब main फ़ंक्शन समाप्त होता है और उसकी स्ट्रीम बंद होती है।
स्ट्रिंग
पाठ स्ट्रिंग ने std::string टाइप को टेक्स्ट-संक्रियाओं वाले char मानों के अनुक्रम के रूप में प्रस्तुत किया। उसने find फ़ंक्शन से खोजना (जो एक स्थिति या npos मान लौटाता है) और उस मान की तुलना हमेशा स्पष्ट रूप से करना, तथा substr फ़ंक्शन से निकालना (जो मान्य स्थिति माँगता है) सिखाया, और std::string_view टाइप प्रस्तुत किया, जो पैरामीटर के रूप में सुरक्षित है पर जिस टेक्स्ट को देखता है उससे अधिक जीवित रहे तो खतरनाक है, और तुलना के लिए C स्ट्रिंगें भी।
टेक्स्ट ASCII नहीं है
पाठ टेक्स्ट ASCII नहीं है ने वर्ण, उसके कोड पॉइंट और उसके बाइटों में भेद किया, और समझाया कि UTF-8 बिटों को एक से चार बाइटों में कैसे बाँटता है। इससे उसने निकाला कि size फ़ंक्शन बाइट गिनता है, कि वर्ण (c & 0xC0) != 0x80 शर्त से गिने जाते हैं, कि बाइट-दर-बाइट उलटना, बड़े अक्षरों में बदलना या काटना टेक्स्ट को तोड़ता है जबकि खोजना और जोड़ना नहीं तोड़ते, और कि मानक लाइब्रेरी क्या नहीं करती।
इनपुट को सही ढंग से पढ़ना
पाठ इनपुट को सही ढंग से पढ़ना ने इनपुट को एक अविश्वसनीय सीमा के रूप में बरता: उसने std::getline फ़ंक्शन से पंक्तियाँ पढ़ना, fail() और eof() फ़ंक्शनों से अमान्य डेटा, न समाने वाली संख्या और डेटा के अंत में भेद करना, clear और ignore फ़ंक्शनों से उबरना, और std::from_chars फ़ंक्शन से संख्याओं को टेक्स्ट के रूप में परखना, यह माँगते हुए कि पूरा टेक्स्ट उपभुक्त हो, सिखाया, और अनुबंध वाले सीमा-फ़ंक्शनों parseInt और readInt के साथ समाप्त किया।
टेक्स्ट फ़ाइलें
पाठ टेक्स्ट फ़ाइलें ने दिखाया कि फ़ाइल एक स्ट्रीम है जिसकी अवस्था std::cin ऑब्जेक्ट जैसी ही होती है। उसने खुलने की जाँच को नियम बनाया, सिद्ध किया कि while (!in.eof()) लूप एक डेटा अधिक क्यों संसाधित करता है, std::println(out, …) कॉल से लिखना (बदलते हुए या जोड़ते हुए) और std::cerr स्ट्रीम से संदेशों को परिणामों से अलग करना सिखाया, और सब कुछ एक निर्धारित और परखे हुए पंक्ति-फ़ॉर्मेट में ले आया।
सामग्री लोड हो रही है…