مجرى الدخل الخاص بالمستخدم ومجرى الخرج القياسي (user input and standard output)
#include <iostream> int main() { int value; std::cout << "Enter a value: " << std::endl; std::cin >> value; std::cout << "The square of entered value is: " << value * value << std::endl; return 0; }
مجاري التدفق النصية (String streams)
std::ostringstream
هو صنف كائناته تبدو كمجرى خرْج (output stream)، أي يمكنك الكتابة فيه عبر العامل operator<<
، ولكنّه في الواقع يخزّن نتائج الكتابة، ويُتيحها على هيئة مجرى.
انظر هذا المثال:
#include <sstream> #include <string> using namespace std; int main() { ostringstream ss; ss << "the answer to everything is " << 42; const string result = ss.str(); }
ينشئ ;ostringstream ss
كائنًا مثل هذا الكائن، ويُعامل الكائن أولًا كمجرى عادي:
ss << "the answer to everything is " << 42;
ثم يمكن الحصول على المجرى الناتج كما يلي:
const string result = ss.str();
(السّلسلة النصّية result
ستساوي "the answer to everything is 42"
). ذلك مفيد في حال أردنا التمثيل النصّي لصنف سبق تعريف تسلسلِ مجراه (stream serialization). على سبيل المثال، لنفترض أنّ لدينا الصنف التالي:
class foo { // التعليمات والأوامر البرمجية ستكون هنا. }; ostream &operator<<(ostream &os, const foo &f);
للحصول على التمثيل النصي للكائن foo
:
foo f;
يمكننا استخدام:
ostringstream ss; ss << f; const string result = ss.str();
وعليه ستحتوي result
التمثيل النصّي للكائن foo
.
طباعة المجموعات باستخدام iostream
الطباعة الأساسية (Basic printing)
تتيح std::ostream_iterator
طباعة محتويات حاويات مكتبة القوالب القياسية STL في أيّ مَجرى خرج دون الحاجة إلى استخدام الحلقات، والوسيط الثاني المُمرَّر إلى مُنشِئ std::ostream_iterator
يعين المحدِّد (delimiter). انظر المثال التالي:
std::vector<int> v = {1,2,3,4}; std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " ! "));
سوف يطبع:
1 ! 2 ! 3 ! 4 !
التحويل الضمني للأنواع (Implicit type cast)
تتيح std::ostream_iterator
تحويل (casting) نوع محتوى الحاوية ضمنيًا. في المثال التالي، ستطبع std::cout
أعدادًا عشريّة ذات ثلاث منازل عشرية:
std::cout << std::setprecision(3); std::fixed(std::cout);
وستستنسخ std::ostream_iterator
باستخدام النوع float
، بينما ستظلّ القيم المُضمّنة قيمًا عددية صحيحة (int
):
std::vector<int> v = {1,2,3,4}; std::copy(v.begin(), v.end(), std::ostream_iterator<float>(std::cout, " ! "));
تعيد الشّيفرة أعلاه النتيجة التالية على الرغم من أنّ المتجهة (std::vector
) تحتوي أعدادًا صحيحة.
1.000 ! 2.000 ! 3.000 ! 4.000 !
التوليد والتحويل
تشكّل دّوال std::generate
و std::generate_n
و std::transform
أداة فعّالة لمعالجة البيانات، فمثلًا، انظر المتجهة التالية:
std::vector<int> v = {1,2,3,4,8,16};
نستطيع باستخدامها أن نطبع القيمة البوليانية لتعليمة x is even
للأعداد الزوجية بسهولة، كما يلي:
std::boolalpha(std::cout); // طباعة القيم البوليانية أبجديًا std::transform(v.begin(), v.end(), std::ostream_iterator<bool>(std::cout, " "), [](int val) { return (val % 2) == 0; });
أو طباعة مربعات العناصر:
std::transform(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "), [](int val) { return val * val; });
أو طباعة N عدد عشوائي تفصلهم مسافة فارغة:
const int N = 10; std::generate_n(std::ostream_iterator<int>(std::cout, " "), N, std::rand);
المصفوفات
يمكن تطبيق جميع هذه الاعتبارات تقريبًا على المصفوفات الأصلية، تمامًا كما هو الحال في القسم الخاص بقراءة الملفات النصية. انظر المثال التالي حيث نطبع القيم التربيعيّة لعناصِر مصفوفة أصلية:
int v[] = {1,2,3,4,8,16}; std::transform(v, std::end(v), std::ostream_iterator<int>(std::cout, " "), [](int val) { return val * val; });
معالِجات مجاري التدفق
معالِجات مجاري التدفق (Stream manipulators) هي دوال خاصّة مساعِدة للتحكّم في مجاري الدخل والخرج باستخدام العاملين operator >>
و operator<<
. ويمكن تضمينها عبر #include <iomanip>
. تُبادِل std::boolalpha
و std::noboolalpha
بين التمثيل النصي والعددي للقيَم البوليانية. انظر المثال التالي:
std::cout << std::boolalpha << 1; // true الخرج std::cout << std::noboolalpha << false; // 0 الخرج bool boolValue; std::cin >> std::boolalpha >> boolValue; std::cout << "Value \"" << std::boolalpha << boolValue << "\" was parsed as " << std::noboolalpha << boolValue; // true الدخل // تحليل قيمة الدخل على أنها 0
-
تحدد كل من
std::showbase
وstd::noshowbase
إن تم استخدام السابقة (Prefix) التي تشير إلى الأساس العادي. -
تُستخدم كل من
std::dec
(عشري) وstd::hex
(ست عشري) وstd::oct
(ثماني) من أجل تغيير الأساس العددي للأعداد الصحيحة.
#include <sstream> std::cout << std::dec << 29 << ' - ' << std::hex << 29 << ' - ' << std::showbase << std::oct << 29 << ' - ' << std::noshowbase << 29 '\n'; int number; std::istringstream("3B") >> std::hex >> number; std::cout << std::dec << 10; // الخرج // 22 - 1D - 35 - 035 // 59
القيم الافتراضية هي std::ios_base::noshowbase
و std::ios_base::dec
. يمكنك معرفة المزيد حول std::istringstream
من الترويسة <sstream>
-
تحدد كل من
std::uppercase
وstd::nouppercase
ما إذا كانت الأحرف الكبيرة ستُستخدم في خرْج الأعداد العشريّة والأعداد الست عشرية، وليس لها أيّ تأثير على مجاري الدخل.
std::cout << std::hex << std::showbase << "0x2a with nouppercase: " << std::nouppercase << 0x2a << '\n' << "1e-10 with uppercase: " << std::uppercase << 1e-10 << '\n'; // الخرج: // 0x2a with nouppercase: 0x2a // 1e-10 with uppercase: 1E-10
القيمة الافتراضيّة هي std::nouppercase
.
-
تغيّر
std::setw(n)
- عرض (width) حقل الدخل/الخرج التالي إلى القيمةn
، وتتم إعادة تعيين خاصية العرضn
إلى0
عند استدعاء بعض الدّوال (انظر القائمة الكاملة).
std::cout << "no setw:" << 51 << '\n' << "setw(7): " << std::setw(7) << 51 << '\n' << "setw(7), more output: " << 13 << std::setw(7) << std::setfill('*') << 67 << ' ' << 94 << '\n'; char* input = "Hello, world!"; char arr[10]; std::cin >> std::setw(6) >> arr; std::cout << "Input from \"Hello, world!\" with setw(6) gave \"" << arr << "\"\n"; // الخرج: // 51 // setw(7): 51 // setw(7): more output: 13*****67 94 // Hello, world! :الدخل // "Hello" تعيد setw(6) حيث "Hello, world!" الخرج: الدخل من
لاحظ أن الخرج في الشيفرة السابقة سيكون ("Input from "Hello, world!" with setw(6) gave "Hello). وتكون القيمة الافتراضية std::setw(0)
.
-
تُعدِّل كل من
std::left
وstd::right
وstd::internal
الموضعَ الافتراضي لمحارف الملء (fill characters) من خلال ضبطstd::ios_base::adjustfield
إلىstd::ios_base::left
وstd::ios_base::right
وstd::ios_base::internal
على الترتيب. كذلك، تُطبَّقstd::left
وstd::right
على أيّ خرج، كما تُطبّقstd::internal
على الأعداد الصحيحة والعشرية والنقديّة، وليس لها أيّ تأثير على مجاري الدخل.
#include <locale> ... std::cout << std::left << std::showbase << std::setfill('*') << "flt: " << std::setw(15) << -9.87 << '\n' << "hex: " << std::setw(15) << 41 << '\n' << " $: " << std::setw(15) << std::put_money(367, false) << '\n' << "usd: " << std::setw(15) << std::put_money(367, true) << '\n' << "usd: " << std::setw(15) << std::setfill(' ') << std::put_money(367, false) << '\n'; // :الخرج // flt: -9.87********** // hex: 41************* // $: $3.67********** // usd: USD *3.67****** // usd: $3.67 std::cout << std::internal << std::showbase << std::setfill('*') << "flt: " << std::setw(15) << -9.87 << '\n' << "hex: " << std::setw(15) << 41 << '\n' << " $: " << std::setw(15) << std::put_money(367, false) << '\n' << "usd: " << std::setw(15) << std::put_money(367, true) << '\n' << "usd: " << std::setw(15) << std::setfill(' ') << std::put_money(367, true) << '\n'; // الخرج // flt: -**********9.87 // hex: *************41 // $: $3.67********** // usd: USD *******3.67 // usd: USD 3.67 std::cout << std::right << std::showbase << std::setfill('*') << "flt: " << std::setw(15) << -9.87 << '\n' << "hex: " << std::setw(15) << 41 << '\n' << " $: " << std::setw(15) << std::put_money(367, false) << '\n' << "usd: " << std::setw(15) << std::put_money(367, true) << '\n' << "usd: " << std::setw(15) << std::setfill(' ') << std::put_money(367, true) << '\n'; // الخرج // flt: **********-9.87 // hex: *************41 // $: **********$3.67 // usd: ******USD *3.67 // usd: USD 3.67
القيمة الافتراضية هي std::left
.
-
تغير كل من
std::fixed
وstd::scientific
وstd::hexfloat
[C++11] وstd::defaultfloat
[C++11] تنسيقَ الدخل والخرج للأعداد العشريّة. -
std::fixed
تعيّنstd::ios_base::floatfield
إلىstd::ios_base::fixed
. -
تعيّن
std::scientific
إلىstd::ios_base::scientific
. -
تعيّن
std::hexfloat
إلىstd::ios_base::fixed | std::ios_base::scientific
وتعيّنstd::defaultfloat
إلىstd::ios_base::fmtflags(0)
.
إليك الشيفرة التالية:
#include <sstream> ... std::cout << '\n' << "The number 0.07 in fixed: " << std::fixed << 0.01 << '\n' << "The number 0.07 in scientific: " << std::scientific << 0.01 << '\n' << "The number 0.07 in hexfloat: " << std::hexfloat << 0.01 << '\n' << "The number 0.07 in default: " << std::defaultfloat << 0.01 << '\n'; double f; std::istringstream is("0x1P-1022"); double f = std::strtod(is.str().c_str(), NULL); std::cout << "Parsing 0x1P-1022 as hex gives " << f << '\n'; // الخرج // 0.070000 // 7.000000e-02 // 0x1.1eb851eb851ecp-4 // 0.07 // 2.22507e-308
القيمة الافتراضية هي std::ios_base::fmtflags(0)
.
هناك خلل في بعض المصرّفات يؤدي إلى النتيجة التالية:
double f; std::istringstream("0x1P-1022") >> std::hexfloat >> f; std::cout << "Parsing 0x1P-1022 as hex gives " << f << '\n'; // الخرج: // Parsing 0x1P-1022 as hex gives 0
-
تتحكم كل من
std::showpoint
وstd::noshowpoint
فيما إذا كانت الفاصلة العشرية ستُضمَّن دائمًا في تمثيل الفاصلة العائمة (floating-point representation)، وهما ليس لهما أي تأثير على مجاري الدخل.
std::cout << "7.0 with showpoint: " << std::showpoint << 7.0 << '\n' << "7.0 with noshowpoint: " << std::noshowpoint << 7.0 << '\n';
النّاتج سيكون:
1.0 with showpoint: 7.00000 1.0 with noshowpoint: 7
القيمة الافتراضية هي std::showpoint
.
-
تتحكم كل من
std::showpos
وstd::noshowpos
فيما إذا كانت العلامة+
ستُعرض في الخرج عند عرض الأعداد الموجبة، وهما كذلك ليس لهما أيّ تأثير على مجاري الدخل.
std::cout << "With showpos: " << std::showpos << 0 << ' ' << -2.718 << ' ' << 17 << '\n' << "Without showpos: " << std::noshowpos << 0 << ' ' << -2.718 << ' ' << 17 << '\n'; // الخرج: // With showpos: +0 -2.718 +17 // Without showpos: 0 -2.718 17
القيمة الافتراضية std::noshowpos
.
-
تتحكم كل من
std::unitbuf
وstd::nounitbuf
في تفريغ مجرى الخرج بعد كل عملية، وهما كذلك ليس لهما أي تأثير على مجاري الدخل. تنفّذstd::unitbuf
عمليّة التفريغ. -
يحدّد
std::setbase(base)
الأساس العددي (numeric base) للمجرى. -
std::setbase(8)
تكافئ تعيينstd::ios_base::basefield
إلى std::ios_base::oct
وتعيينstd::setbase(16)
إلىstd::ios_base::hex
وتعيينstd::setbase(10)
إلى std::ios_base::dec
.
إن كان الأساس العدديّ مخالفًا لـ 8 و10 و 16، فستُعيَّن std::ios_base::basefield
إلى std::ios_base::fmtflags(0)
، وذلك يعني أنّ الخرج سيكون عشريًا، أمّا الدخل فسيتعلّق بالأساس العددي (prefix-dependent).
القيمة الافتراضيّة لـ std::ios_base::basefield
هي std::ios_base::dec
، لذلك، فافتراضيًا سيكون لدينا الأساس العشري std::setbase(10)
-
تغيّر
std::setprecision(n)
دقةَ الأعداد العشرية.
#include <cmath> #include <limits> ... typedef std::numeric_limits < long double > ld; const long double pi = std::acos(-1. L); std::cout << '\n' << "default precision (6): pi: " << pi << '\n' << " 10pi: " << 10 * pi << '\n' << "std::setprecision(4): 10pi: " << std::setprecision(4) << 10 * pi << '\n' << " 10000pi: " << 10000 * pi << '\n' << "std::fixed: 10000pi: " << std::fixed << 10000 * pi << std::defaultfloat << '\n' << "std::setprecision(10): pi: " << std::setprecision(10) << pi << '\n' << "max-1 radix precicion: pi: " << std::setprecision(ld::digits - 1) << pi << '\n' << "max+1 radix precision: pi: " << std::setprecision(ld::digits + 1) << pi << '\n' << "significant digits prec: pi: " << std::setprecision(ld::digits10) << pi << '\n'; // الخرج // pi: 3.14159 // 10pi: 31.4159 // 10pi: 31.42 // 10000pi: 3.142e+04 // std::fixed: 10000pi: 31415.9265 // std::setprecision(10): pi: 3.141592654 // max-1 radix precicion: pi: 3.14159265358979323851280895940618620443274267017841339111328125 // max+1 radix precision: pi: 3.14159265358979323851280895940618620443274267017841339111328125 // pi: 3.14159265358979324
القيمة الافتراضية هي std::setprecision(6)
.
-
تعين كل من
std::setiosflags(mask)
وstd::resetiosflags(mask)
- الرايات (flags) المحدّدة في العنصرmask
ذي النّوعstd::ios_base::fmtflags
، وتمسحها كذلك.
#include <sstream> ... std::istringstream in("10 010 10 010 10 010"); int num1, num2; in >> std::oct >> num1 >> num2; std::cout << "Parsing \"10 010\" with std::oct gives: " << num1 << ' ' << num2 << '\n'; // الخرج: // Parsing "10 010" with std::oct gives: 8 8 in >> std::dec >> num1 >> num2; std::cout << "Parsing \"10 010\" with std::dec gives: " << num1 << ' ' << num2 << '\n'; // الخرج: // Parsing "10 010" with std::oct gives: 10 10 in >> std::resetiosflags(std::ios_base::basefield) >> num1 >> num2; std::cout << "Parsing \"10 010\" with autodetect gives: " << num1 << ' ' << num2 << '\n'; // الخرج: // Parsing "10 010" with std::oct gives: 10 8 std::cout << std::setiosflags(std::ios_base::hex | std::ios_base::uppercase | std::ios_base::showbase) << 42 << '\n'; // الخرج: OX2A
-
تحدد كل من
std::skipws
وstd::noskipws
ما إذا كانت دوال الدّخل المُنسّق (formatted input functions) ستتجاوز المسافة البادئة الفارغة. وليس لهما أي تأثير على مجاري الخرج.
#include <sstream> ... char c1, c2, c3; std::istringstream("a b c") >> c1 >> c2 >> c3; std::cout << "Default behavior: c1 = " << c1 << " c2 = " << c2 << " c3 = " << c3 << '\n'; std::istringstream("a b c") >> std::noskipws >> c1 >> c2 >> c3; std::cout << "noskipws behavior: c1 = " << c1 << " c2 = " << c2 << " c3 = " << c3 << '\n'; // الخرج: // Default behaviour: c1 = a c2 = b c3 = c // noskipws behavior: c1 = a c2 = c3 = b
القيمة الافتراضية هي std::ios_base::skipws
.
-
std::quoted(s[, delim[, escape]])
[C++14] تدرج أو تستخرج السّلاسل النصية المُقتبسة (quoted) ذات المسافات الفارغة المُدمجة. -
s
- السّلسلة النصية المرادُ إدراجها أو استخلاصها. -
delim
- المحرف المراد استخدامه كمحدّد (delimiter)، القيمة الافتراضية هي"
. -
escape
- المحرف المستخدم كحرف تهريب (escape character) ، القيمة الافتراضيّة هي\
.
#include <sstream> ... std::stringstream ss; std::string in = "String with spaces, and embedded \"quotes\" too"; std::string out; ss << std::quoted( in ); std::cout << "read in [" << in << "]\n" << "stored as [" << ss.str() << "]\n"; ss >> std::quoted(out); std::cout << "written out [" << out << "]\n"; // الخرج // [String with spaces, and embedded "quotes" too] تُقرأ كـ // ["String with spaces, and embedded \"quotes\" too"] تُخزّن كـ // [String with spaces, and embedded "quotes" too] تُكتب كـ
معالِجات مجاري الخرج
-
std::ends
- تُدرج محرفًا فارغًا '\0' في مجرى الخرْج. تبدو الصيغة الرسمية لهذا المعالِج كالتالي:
template <class charT, class traits> std::basic_ostream<charT, traits>& ends(std::basic_ostream<charT, traits>& os);
هذا المعالِجُ يُدرج المحرفَ الفارغَ عبر استدعاء os.put(charT())
عند استخدامه في تعبير os << std::ends;
-
يفرِّغ كلا من
std::endl
وstd::flush
مجرى الإخراجout
عن طريق استدعاءout.flush()
، ممّا يؤدّي إلى عرض الخرج على الفور. لكنّstd::endl
تدرج رمز نهاية السّطر'\n'
قبل التفريغ. انظر:
std::cout << "First line." << std::endl << "Second line. " << std::flush << "Still second line.";
الناتج:
First line. Second line. Still second line.
-
std::setfill(c)
- تغيّر محرف الملء (fill character) إلىc
، تُستخدم غالبًا معstd::setw
.
std::cout << "\nDefault fill: " << std::setw(10) << 79 << '\n' << "setfill('#'): " << std::setfill('#') << std::setw(10) << 42 << '\n'; // الخرج: // Default fill: 79 // setfill('#'): ########79
-
std::put_money(mon[, intl])
[C++11] - تُحوِّل القيمة النقديةmon
(من النوعlong double
أوstd::basic_string
) في التعبيرout << std::put_money(mon, intl)
إلى تمثيلها المحرفيّ كما هو محدد فيstd::money_put
في الإعدادات المحلّية الخاصّة بالعملة الموجودة فيout
. استخدم سلاسل العملات الدولية إذا كانتintl
تساويtrue
وإلا فاستخدم رموز العملات.
long double money = 123.45; // std::string money = "123.45"; :أو std::cout.imbue(std::locale("en_US.utf8")); std::cout << std::showbase << "en_US: " << std::put_money(money) << " or " << std::put_money(money, true) << '\n'; // en_US: $1.23 or USD 1.23 :الخرج std::cout.imbue(std::locale("ru_RU.utf8")); std::cout << "ru_RU: " << std::put_money(money) << " or " << std::put_money(money, true) << '\n'; // ru_RU: 1.23 руб or 1.23 RUB :الخرج std::cout.imbue(std::locale("ja_JP.utf8")); std::cout << "ja_JP: " << std::put_money(money) << " or " << std::put_money(money, true) << '\n'; // ja_JP: ¥123 or JPY 123 :الخرج
-
std::put_time(tmb, fmt)
[C++11] - تُنسّق وتُخرِج قيمة تقويم تاريخ/وقت إلىstd::tm
بحسب تنسيقfmt
. -
tmb
- مؤشّر إلى بنية التقويم (calendar time structure)const std::tm*
كما أعادتهlocaltime()
أوgmtime()
. -
fmt
- مؤشّر إلى سلسلة نصّية منتهية بقيمة فارغةconst CharT*
تمثّل تنسيق التحويل.
#include <ctime> ... std::time_t t = std::time(nullptr); std::tm tm = *std::localtime(&t); std::cout.imbue(std::locale("ru_RU.utf8")); std::cout << "\nru_RU: " << std::put_time(&tm, "%c %Z") << '\n'; // الخرج الممكن // ru_RU: Вт 04 июл 2017 15:08:35 UTC
معالِجات مجاري الدخل (Input stream manipulators)
-
تستهلك
std::ws
المسافات البادئة في مجرى الدخل، وهي مختلفة عنstd::skipws
.
#include <sstream> ... std::string str; std::istringstream(" \v\n\r\t Wow!There is no whitespaces!") >> std::ws >> str; std::cout << str; // الخرج // Wow!There is no whitespaces!
-
std::get_money(mon[, intl])
[C++11] - في تعبيرin >> std::get_money(mon, intl)
، تحلّل دخل المحارف كقيمة نقديّة كما هو محدّد بواسطةstd::money_get
في الإعدادات المحلية فيin
، وتخزّن القيمة فيmon
(من نوعlong double
أوstd::basic_string
). سيتوقّع المعالِج سلاسل العملات الدوليّة المطلوبة إذا كانتintl
تساويtrue
، وإلا فسَيتوقع رموز عملات اختيارية.
#include <sstream> #include <locale> ... std::istringstream in("$1,234.56 2.22 USD 3.33"); long double v1, v2; std::string v3; in.imbue(std::locale("en_US.UTF-8")); in >> std::get_money(v1) >> std::get_money(v2) >> std::get_money(v3, true); if (in) { std::cout << std::quoted(in.str()) << " parsed as: " << v1 << ", " << v2 << ", " << v3 << '\n'; } // الخرج // "$1,234.56 2.22 USD 3.33" parsed as: 123456, 222, 333
-
تحلّل
std::get_time(tmb, fmt)
[C++11] قيمة التاريخ/الوقت المُخزّنة فيtmb
بتنسيقfmt
المحدد. -
tmb
- مؤشّر صالح للكائنconst std::tm*
حيث ستُخزَّن النتيجة. -
fmt
- مؤشّر إلى سلسلة نصيّة منتهية بقيمة فارغةconst CharT*
تمثّل تنسيق التحويل.
#include <sstream> #include <locale> ... std::tm t = {}; std::istringstream ss("2011-Februar-18 23:12:34"); ss.imbue(std::locale("de_DE.utf-8")); ss >> std::get_time(&t, "%Y-%b-%d %H:%M:%S"); if (ss.fail()) { std::cout << "Parse failed\n"; } else { std::cout << std::put_time(&t, "%c") << '\n'; } // الخرج // Sun Feb 18 23:12:34 2011
هذا الدرس جزء من سلسلة مقالات عن C++.
ترجمة -بتصرّف- للفصل Chapter 13: C++ Streams والفصل Chapter 14: Stream manipulators من كتاب C++ Notes for Professionals
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.