স্ট্রিং
পূর্বের অধ্যায়ে অ্যারে নিয়ে আলোচনা করেছিলাম। আমরা int এবং double টাইপের অ্যারে দেখেছিলাম কিন্তু long long এবং char টাইপের অ্যারে দেখিনি। এই অধ্যায়ে long long টাইপ নিয়ে আলোচনা করব না কারণ int আর long long টাইপের অ্যারে একই শুধু ধারণক্ষমতার ভিন্নতা। কিন্তু, char টাইপের অ্যারে নিয়ে আলোচনা করব যাকে আসলে string বলা হয়। এটা নিয়ে অ্যারে অধ্যায়ে আলোচনা না করে আরেকটি অধ্যায়ে আলোচনা করার কারণ হচ্ছে, বাকি টাইপ গুলো থেকে এর কিছু ভিন্নতা আছে। আমরা int টাইপের অ্যারেতে একাধিক নাম্বার রাখতে পারতাম। লক্ষ করলে দেখবেন একটি নাম্বারই আসলে তৈরি হয় এক বা একাধিক সংখ্যা/ক্যারেক্টার দিয়ে। কিন্তু, char টাইপের অ্যারেতে আমরা ঐভাবে রাখতে পারব না। কারণ, char টাইপের অ্যারের একটি ঘরেতে একটিমাত্র ক্যারেকটারই ব্যবহার করতে পারব। আর আমরা জানি ফাঁকা/স্পেস ও একটি ক্যারেক্টার। কমা, ফুল স্টপ এইগুলো সবই char। সুতরাং char টাইপ অ্যারে বা স্ট্রিং ব্যবহারের ক্ষেত্রে একটু ভিন্নতা বা সতর্কতার প্রয়োজন। সি++ এর স্ট্রিংয়ে একটু সুবিধা আছে। কারণ, আপানাকে আগে থেকেই বলে দিতে হবে না আপনি কতটি ক্যারেক্টার নিবেন। ডিক্লেয়ার করার পর আপনি যতখুশি তত ক্যারেক্টার রাখতে পারেন, সি++ এর কম্পাইলার আপনাআপনিই জায়গা বরাদ্দ করে নেয়। যেমন, string str; মানে এখানে আপনি str নামে একটি খালি স্ট্রিং তৈরি করে ফেলেছেন। আর কথা না বাড়িয়ে তাহলে প্রোগ্রাম শুরু করে দিতে পারি।
আমাদের নিশ্চয়ই মনে আছে প্রথম প্রোগ্রামের কথা। সেখানে, আমরা "Hello World!" প্রিন্ট করার প্রোগ্রাম দেখেছিলাম। এখন আমরা সেই প্রোগ্রামটিই করব। তবে "Hello World!" লেখাটি স্ট্রিংয়ে নিয়ে।
#include <iostream>
using namespace std;
int main() { string str;
str = "Hello World!";
cout << str << endl;
return 0; } Code: 7.0 |
প্রথমেই আমরা একটি স্ট্রিং ডিক্লেয়ার করেছি। এরপর তাতে লেখাটি রেখে দিয়েছি। তারপর প্রিন্ট। এখানে কিছু উল্লেখ্য বিষয়, আমরা একটি ক্যারেক্টার রাখার সময় সিঙ্গেল কোটেশন ' ' ব্যবহার করেছিলাম কিন্তু স্ট্রিংয়ের জন্য ডাবল কোটেশন " " ব্যবহার করতে হবে, আপনাকে পুরো স্ট্রিং প্রিন্ট করার জন্যে লুপ লাগছে না, এসাইন করার সময় যদি প্রতিটি ক্যারেক্টারের মাঝে int অ্যারেতে রাখার মত ফাঁকা বা কমা দিতে যান তাহলে সেগুলোকেও ক্যারেক্টার হিসেবে নিয়ে নিবে, Hello এবং World এই দুইটি শব্দের মাঝে আমি ফাঁকা রেখেছিলাম সেটিও ক্যারেক্টার হিসেবে নিয়ে প্রিন্ট করে দিয়েছে।
এখন আমরা ইউজারের থেকে স্ট্রিং ইনপুট নিয়ে একটি প্রোগ্রাম দেখব। এই প্রোগ্রামে আপনি আপনার ডাক নাম ইনপুট দিবেন এবং সেটিই প্রোগ্রামটি ইনপুট নিয়ে প্রিন্ট করবে।
#include <iostream>
using namespace std;
int main() { string str;
cout << "Enter your Nickname: "; cin >> str;
cout << "Your Nickname is: "; cout << str << endl;
return 0; } Code: 7.1 |
এবার একটি প্রশ্ন, আপনার পুরো নাম ইনপুট দিলে পুরো নামটিই আউটপুট হিসেবে দেখাচ্ছে? এই প্রোগ্রামে যেভাবে ইনপুট নেওয়া দেখিয়েছি, সেভাবে আসলে ইনপুট দিলে শুধু একটি word ই ইনপুট দিতে পারবেন। ফাঁকা ক্যারেক্টার পাওয়ার পরই আর কিছু ইনপুট নিবে না। তাহলে, পুরো নামটি ইনপুট দেওয়ার জন্যে আমাদের অন্য নিয়মে ইনপুট নিতে হবে। এর জন্যে ব্যবহার করতে হবে getline();। এর কাজ হচ্ছে একটি লাইনে যাই থাকুক সম্পূর্ণ লাইনটি ইনপুট হিসেবে নিয়ে নেওয়া।
#include <iostream>
using namespace std;
int main() { string str;
cout << "Enter your full name: "; getline(cin, str);
cout << "Your full name is: "; cout << str << endl;
return 0; } Code: 7.2 |
এখন নিশ্চয়ই আপনার পুরো নামটিই দেখাচ্ছে? যদি কোথাও ভুল না করে থাকেন।
একটি স্ট্রিং এর সাইজ কত তা বের করব কীভাবে? একটা স্ট্রিং শেষ হয়েছে এটা বুঝার জন্য স্ট্রিংটির শেষে থাকে '\0' এই ক্যারেক্টার। একে নাল/NULL ক্যারেক্টার বলা হয়। তাহলে, আইডিয়াটি হচ্ছে আমরা 0 থেকে লুপ চালাব এবং যতক্ষণ না নাল ক্যারেক্টার পাব ততক্ষণ চলতেই থাকবে। যে ভেরিয়েবল দিয়ে লুপ চালাব সেটি যতবার ঘুরেছে তাই হচ্ছে স্ট্রিংটির দৈর্ঘ্য/সাইজ।
#include <iostream>
using namespace std;
int SIZE(string s){ int tot = 0; while (s[tot] != '\0'){ tot++; } return tot; }
int main() { string str;
cout << "Enter your full name: "; getline(cin, str);
int len = SIZE(str);
cout << len << endl;
return 0; } Code: 7.3 |
স্ট্রিংয়ের সাইজ বের করার জন্যে কিন্তু সি++ এ বিল্ডইন ফাংশন আছে। আমরা খুব সহজে সেটি কল করেই সাইজ বের করে ফেলতে পারতাম (int len = str.size())। কিন্তু বিল্ডইন ফাংশন কীভাবে কাজ করে এটা না জেনে শুধু ব্যবহার করাটা ভালো প্র্যাক্টিস না। তাই, সাইজ কীভাবে বের করতে হয় তা আগে দেখে নিলাম।
এখন স্ট্রিংয়ের কিছু বেসিক কাজ দেখব। যেমন, স্ট্রিং কপি করা, স্ট্রিং জোরা লাগানো এবং স্ট্রিং খালি করে দেওয়া। স্ট্রিং কপি করা যায় খুব সহজেই। একটি ভেরিয়েবলের ভ্যালু আরেকটি ভেরিয়েবলে যেভাবে এসাইন করতাম সেভাবেই আমরা স্ট্রিং ও আরেকটি স্ট্রিংয়ে এসাইন করতে পারব। তবে, আমি প্রথমে একটি একটি করে ক্যারেক্টার নিয়ে আরেকটি ফাঁকা স্ট্রিংয়ে যোগ করে দেখিয়েছি। কারণ, ঐ একই। সবরকম নিয়ম জেনে রাখা ভালো। কোন নিয়ম কখন কাজে লেগে যাবে তার ঠিক নেই।
#include <iostream>
using namespace std;
int main() { string s1, s2, s3;
cout << "Enter a string: "; cin >> s1;
int len = s1.size();
// type 1: copy string for (int i = 0; i < len; i++){ s2 += s1[i]; }
cout << s2 << endl;
// type 2: copy string s3 = s1; cout << s3 << endl;
// concatenation two string for (int i = 0;i < len;i++){ s2 += s3[i]; }
cout << s2 << endl; cout << endl;
cout << len << endl;
s1.clear(); s2.clear(); s3.clear();
len = s1.size(); cout << len << endl;
return 0; } Code: 7.4 |
লক্ষ করলে দেখবেন, লুপের ভিতরে আমি i একইসাথে ডিক্লেয়ার ও এসাইন করেছি। এভাবেও করা যায়। তবে, পার্থক্য হচ্ছে এই ভেরিয়েবল আর লুপের বাইরে ব্যবহার করতে পারবেন না। এখন প্রোগ্রামের প্রথম কাজ দেখবেন আমি লুপ চালিয়ে একটি স্ট্রিং আরেকটিতে কপি করতেছি কিন্তু পরেই আবার দেখতে পারবেন কাজটি আসলে অনেক সহজেই করা যায় s3 = s1;। এরপর s2 এর সাথে s3 জোরা লাগিয়েছি। এখানেও আসলে s2 তে s3 এর ক্যারেক্টারগুলো একটি একটি করে যোগ হচ্ছে s2 এর শেষ মাথা থেকে। আপনি s3 কে s2এর শুরুতে যোগ করতে পারবেন? দুটি স্ট্রিং যোগ করার কাজও কিন্তু খুব সহজে করা যায়। যেমন, s2 += s3; বা, s1 = s2 + s3; ইত্যাদি উপায়ে। এরপরের কাজ হচ্ছে তিনটি স্ট্রিংকেই আমরা খালি করে দিয়েছি clear(); ফাংশনের মাধ্যমে। এটি দেখানোর জন্যে শেষে সাইজ প্রিন্ট করেছি যেন সহজে বুঝতে পারেন স্ট্রিংটি আসলেই খালি হয়েছে কিনা।
আপনাকে একটি স্ট্রিং ইনপুট দেওয়া হবে, বলতে হবে স্ট্রিংটিতে মোট কতটি vowel আছে। স্ট্রিংয়ে ইনপুট হিসেবে শুধু Small Letter দেওয়া হবে। এর আগে আমরা একটি ক্যারেক্টার চেক করেছি সেটি vowel কিনা। এখন স্ট্রিংয়ে থাকা প্রতিটি ক্যারেক্টার vowel কিনা তাই দেখব।
#include <iostream>
using namespace std;
int main() { string str;
cout << "Enter a string: "; cin >> str;
int total = 0; int len = str.size();
for (int i = 0; i < len; i++){ if (str[i]=='a' || str[i]=='e' || str[i]=='i' || str[i]=='o' || str[i]=='u'){ total++; } }
cout << "Total Alphabet: " << total << endl;
return 0; } Code: 7.5 |
আপনি কি প্যালিন্ড্রম সম্পর্কে জানেন? প্যালিন্ড্রম হচ্ছে, একটি শব্দকে ডান ও বাম যেদিক থেকে পড়বেন শব্দটির কোন পার্থক্য হবে না। যেমন, abc কে ডান দিক থেকে পড়লে cba কিন্তু aba কে ডান দিক থেকে পড়লে aba ই পাওয়া যাবে তাই এটি প্যালিন্ড্রম। madam ও একইভাবে প্যালিন্ড্রম। এটা করতে হলে আমরা আগে একটি স্ট্রিং ইনপুট নিয়ে নিব এবং আরেকটি স্ট্রিংয়ে সেটি কপি করে রাখব। এবার দ্বিতীয় স্ট্রিংটি রিভার্স করে দিব। তারপর দেখব প্রতিটি পজিশনে প্রথম ও দ্বিতীয় স্ট্রিংয়ের ক্যারেক্টারে অমিল আছে কিনা। যদি একটি অমিল ও থাকে তাহলে এটি প্যালিন্ড্রম নয় অন্যথায় এটি প্যালিন্ড্রম।
#include <iostream>
using namespace std;
void REVERSE(string &s, int n){ for (int i = 0, j = n-1;i < n/2;i++, j--){ char ch = s[i]; s[i] = s[j]; s[j] = ch; } }
int main() { string a, b;
cout << "Enter a string: "; cin >> a;
int len = a.size();
b = a;
// Reveres string b REVERSE(b, len);
bool dif = false; for (int i = 0; i < len; i++){ if (a[i] != b[i]){ dif = true; break; } }
if (dif == true){ cout << a << " is not palindrome" << endl; } else { cout << a << " is palindrome" << endl; }
return 0; } Code: 7.6 |
ফাংশনে স্ট্রিং রিসিভ করার সময় & কেন দেওয়া হয়েছে স্ট্রিংয়ের সামনে? এটি এখানে Address Operator হিসেবে ব্যবহার হয়েছে। এটি ব্যবহারের কারণ হচ্ছে, আমরা ত মেইন ফাংশন থেকে b তে থাকা ক্যারেক্টার গুলো পাঠিয়ে দিচ্ছি b কিন্তু না। তাই, ফাংশনের ভিতরে স্ট্রিং s রিভার্স হলেও b রিভার্স হবে না। কিন্তু, আমাদের b কে রিভার্স করতে হবে। এর জন্যেই আমরা শুধু b তে থাকা ক্যারেক্টারগুলো না পাঠিয়ে b এর এড্রেস পাঠিয়ে দিয়েছি। এখন ফাংশনে s পরিবর্তন হওয়া মানে b পরিবর্তন হবে। কারণ নাম আলাদা হলেও এড্রেস আসলে একই। এগুলো নিয়ে বিস্তারিত জানতে পারবেন যখন পয়েন্টার পড়বেন। এটি একটু এডভান্সড জিনিস তাই বেসিক পড়ার সময় এটি নিয়ে আলোচনা করছি না। এখন প্রোগ্রামের কাজে আসি। ফাংশনের ভিতরে আমি রিভার্স করেছি। এটি যদি না বুঝে থাকেন তাহলে অ্যারে অধ্যায়ে রিভার্স নিয়ে আলোচনা করেছি, আপনি সেটি ফাকি দিয়েছেন :| । এরপর dif নামের একটা ভেরিয়েবলকে আগে false করে রেখেছি। কারণ, আমরা প্রথমে ধরে নিচ্ছি স্ট্রিংটি প্যালিন্ড্রম। তবে, যদি শেষ পর্যন্ত dif তে false থাকে। এরপর চেক করে যাব প্রতিটি পজিশনের a ও b ক্যারেক্টারে মিল আছে কিনা। যদি মিল না থাকে তাহলে স্ট্রিংটি প্যালিন্ড্রম নয় এবং আমরা dif কে true করে দিব। এখন আর বাকি ক্যারেক্টারগুলো পরীক্ষা করে লাভ নেই। তাই, লুপ ব্রেক করে লুপ থেকে বের হয়ে যাচ্ছি।
আপনাকে একটি লাইন ইনপুট নিতে হবে এবং লাইনের প্রতিটি word এর প্রথম ক্যারেক্টার যদি Small Letter হয় সেটি Capital Letter করতে হবে। কাজটি কি নিজে নিজেই করতে পারবেন? আইডিয়া হচ্ছে লাইনে word গুলো ত ফাঁকা ক্যারেক্টার দিয়ে আলাদা থাকে। এখন ইনপুটে কিন্তু একাধিক ফাঁকা ক্যারেক্টার দিয়েও word গুলো আলাদা থাকতে পারে। তাই, আমরা প্রথমে ফাঁকা ক্যারেক্টারগুলো ইগনোর করব। এরপর যদি স্ট্রিংয়ের শেষ না হয় তাহলে অবশ্যই যেকোন একটি word এর সামনে আছি আমরা। এবার সেই word এর প্রথম ক্যারেক্টার পরীক্ষা করব এটি Small Letter কিনা। Small Letter হলে Capital করে দিব। এরপর আবার যতক্ষণ না ফাঁকা ক্যারেক্টার আসবে ততক্ষণ বাকি ক্যারেক্টারগুলো ইগনোর করব। এভাবে শেষ না হওয়া পর্যন্ত চলতে থাকবে।
#include <iostream>
using namespace std;
int main() { string str;
cout << "Enter a string: "; getline(cin, str);
int len = str.size();
int i = 0; while (i < len){ // ignoring space character while (i < len && str[i] == ' '){ i++; } // checking first character of a word is small and replace with capital if (i < len && str[i] >= 'a' && str[i] <= 'z'){ str[i] = str[i] - 32; } // ignore the word while (i < len && str[i] != ' '){ i++; } }
cout << str << endl;
return 0; } Code: 7.7 |
আগে যে আমরা লুপের ভিতরে লুপের কাজ করেছি সেখানে কিন্তু nXn টি কাজ করতে হত। মানে, n = 5 হলে মোট 5X5 = 25 বার লুপ ঘুরত। এখানে কিন্তু তা হচ্ছে না যদিও লুপের ভিতরে লুপ দেখে মনে হতে পারে। এখানে স্ট্রিংয়ের সাইজের সমান কাজ ই হবে। আর প্রোগ্রামে আমরা প্রথমে দেখতেছি সাইজের বাইরে চলে যাচ্ছি কিনা while (i < len)। এরপরের পার্টে দেখছি সামনে কোন স্পেস ক্যারেক্টার আছে কিনা। যদি থাকে, যতগুলো থাকবে তার সবই ইগনোর হয়ে যাবে। স্পেস শেষ হয়েছে মানে এখন পরের word টি শুরু। আর আমাদের কাজ হচ্ছে word এর প্রথম ক্যারেক্টারটি Capital করে দেওয়া, যদি Small থাকে। এরপরের কাজ আমরা তাই করেছি। তারপরের কাজ পুরো word টিকে ইগনোর করে দেওয়া। এভাবেই চলতে থাকবে যতক্ষণ না স্ট্রিং শেষ হবে।
এবার আমরা দেখব, স্ট্রিংয়ের ভিতরে স্ট্রিং মানে, 2D স্ট্রিং নিয়ে। এটি ডিক্লেয়ার করতে হয় এভাবে, string str[100]; মানে এর ভিতরে আপনি এখন একশটি স্ট্রিং নিতে পারবেন। তবে ভিতরের স্ট্রিং গুলো কিন্তু যতখুশি তত সাইজের নিতে পারবেন। আমরা একটি প্রোগ্রাম দেখি, যে প্রোগ্রামের কাজ n টি লাইন বা স্ট্রিং ইনপুট নিবে এবং তা প্রিন্ট করবে।
#include <iostream>
using namespace std;
int main() { string str[100]; int n;
cin >> n;
for (int i = 0; i < n; i++){ cin >> str[i]; }
for (int i = 0; i < n; i++){ cout << str[i] << endl; }
cout << str << endl;
return 0; } Code: 7.8 |
এখানে কিন্তু এক লাইন সম্পূর্ণ ইনপুট নিতে পারবে না। আপনি যদি ইনপুট দেন এভাবে,
3
abc bb
abbb
cca
তাহলে আউটপুট দেখাবে এভাবে,
abc
bb
abbb
আউটপুট ও ইনপুটের মত দেখাতে চাইলে কি করতে হবে তা অবশ্যই আপনারা এই অধ্যায়ের শুরুতে জেনে গেছেন। এরপরেও আমরা প্রোগ্রামটি দেখে নেই।
#include <iostream>
using namespace std;
int main() { string str[100]; int n;
cin >> n;
for (int i = 0; i < n; i++){ getline(cin, str[i]); }
for (int i = 0; i < n; i++){ cout << str[i] << endl; }
cout << str << endl;
return 0; } Code: 7.9 |
কিন্তু এখানেও সমস্যা। নিশ্চয়ই ইনপুট পুরোপুরি নিচ্ছে না বা ইনপুট n লাইন দেওয়ার আগে কোন সমস্যা হচ্ছেই। এর কারণ, হচ্ছে getline(); আসলে একটি লাইনে যা আছে সবই পড়ে। আর আমরা জানি newline ও একটি ক্যারেক্টার '\n'(endl এর মাঝে আসলে এই ক্যারেক্টার থাকে)। ত যখন আপনি প্রোগ্রামের শুরুতে n ইনপুট দিয়ে Enter দিয়েছেন তখন যে নিউলাইনটি ইনপুটে এসেছে তা অন্য ইনপুট নেওয়ার মাধ্যম আপনাআপনিই ইগনোর করে কিন্তু getline(); তা করে না কারণ, এর উদ্দ্যেশ্যই লাইনে যা থাকবে তাই ইনপুট নেওয়া। তাই getline(); শুরু করার আগেই যে অতিরিক্ত ক্যারেক্টারটি আসবে তা ইগনোর করার ব্যবস্থা করতে হবে। এর জন্যে আপনি এই প্রোগ্রামে cin >> n; লাইনটির পরে cin.ignore(); লিখে দিন তাহলেই হয়ে যাবে।
এই অধ্যায় এই পর্যন্তই সাথে সি++ বেসিক সিরিজ ও শেষ। আশাকরি প্রতিটা অধ্যায় ভালো করে প্র্যাক্টিস করেছেন। এখন কাজ হচ্ছে সম্ভব হলে আবারো একবার প্রথম থেকে প্র্যাক্টিস করা। এরপর আপনি কিছুদিন প্রবলেম সলভিং করতে পারেন। যদি ভালো লাগে তাহলে এটাই আরো ভালো করে করুন আর যদি ভালো না লাগে তাহলে অন্য যাই করুন শিখাটা কিন্তু বন্ধ করা যাবে না।
No comments