একটি রেগুলার এক্সপ্রেশন (বা রেজেক্স) হলো অক্ষরের একটি ক্রম, যা দিয়ে আমরা স্ট্রিংয়ের নির্দিষ্ট কিছু এলিমেন্টকে টার্গেট করে ম্যানিপুলেট করতে পারি। তাই আমরা পারি:
এই কনসেপ্টে মূলত JavaScript-এ রেগুলার এক্সপ্রেশন ব্যবহারের দিকে নজর দেওয়া হয়েছে। রেগুলার এক্সপ্রেশন কীভাবে লিখবেন তা শিখতে চাইলে Eloquent JavaScript একটি ভালো রিসোর্স হতে পারে।
💡 JavaScript-এর রেজেক্স ফ্লেভার ভাষাটির ECMA-262 স্ট্যান্ডার্ডের অংশ। এর মানে হলো, ব্রাউজারভেদে কম্প্যাটিবিলিটি নিয়ে আপনাকে ভাবতে হবে না।
JavaScript-এ রেগুলার এক্সপ্রেশন বেশিরভাগ ক্ষেত্রেই /pattern/modifiers ফরম্যাটে লেখা হয়, যেখানে 'pattern' হলো মূল রেজেক্স, আর 'modifiers' হলো এমন কিছু অক্ষরের সিরিজ, যা দিয়ে আমরা বিশেষ অপশন (যেন সুপারপাওয়ার) বোঝাতে যোগ করতে পারি।
তবুও, রেগুলার এক্সপ্রেশন তৈরির দুটি উপায় আছে:
const regex = /[a-z]/;
const regex = new RegExp('[a-z]');
দুটি ক্ষেত্রেই JavaScript রেজেক্স থেকে একটি অবজেক্ট তৈরি করে। ডিফল্ট হিসেবে লিটারালসহ ইমিউটেবল প্যাটার্ন ব্যবহার করার পরামর্শ দেওয়া হয়।
RegExp কনস্ট্রাক্টর এমন ক্ষেত্রে ব্যবহার করা যায়, যেখানে রেজেক্স বদলাবে বা আমরা এখনো সেটি জানি না (যেমন কোনো ইনপুট)।
রেগুলার এক্সপ্রেশনের flags নামে অপশনাল সুপারপাওয়ার থাকে, যা দিয়ে আরও কিছু ফিচার পাওয়া যায়। এই ফ্ল্যাগগুলো আলাদাভাবে বা একসাথে যেকোনো ক্রমে ব্যবহার করা যায়, এবং এগুলো রেগুলার এক্সপ্রেশনের অংশ হিসেবেই থাকে।
বেশ জনপ্রিয় কিছু ফ্ল্যাগ হলো:
/g - গ্লোবাল সার্চ/i - কেস ইনসেনসিটিভ/m - মাল্টিলাইন সার্চএখানে একটি সহজ উদাহরণ:
const re = /home/gi;
const str = 'Home, sweet home.';
str.match(re);
// => ["Home", "home"]
g ক্যারেক্টারটি দিয়ে আমরা একটি স্ট্রিংয়ের ভেতরে সম্ভাব্য সব ম্যাচ পার্স করতে পারি। এই ফিচারটি না থাকলে JavaScript কেবল প্রথম Home ম্যাচটি এক্সট্র্যাক্ট করত।
কেস ইনসেনসিটিভ ফ্ল্যাগ /i প্যাটার্ন খোঁজার সময় আমাদের নমনীয় হতে দেয়। ফলে আমরা যা খুঁজছি তা UPPERCASE না lowercase, সেটি কোনো ব্যাপারই না।
RegExp কনস্ট্রাক্টর ব্যবহার করার সময় ফ্ল্যাগ যোগ করার সিনট্যাক্স আলাদা। সেক্ষেত্রে ফ্ল্যাগগুলোকে শুধু দ্বিতীয় আর্গুমেন্ট হিসেবে পাস করতে হয়।
রেগুলার এক্সপ্রেশনের সাথে JavaScript-এর বিল্ট-ইন ফাংশনগুলো মিলিয়ে ব্যবহার করলে স্ট্রিং থেকে ডেটা বের করা ও তা নিয়ে কাজ করার বেশ শক্তিশালী উপায় হাতে আসে।
কোনো নির্দিষ্ট স্ট্রিংয়ের ভেতরে কাঙ্ক্ষিত মান আছে কি না, তা সার্চ করে জানার দারুণ একটি উপায় হলো test() মেথড। এভাবে এটি একটি বুলিয়ান মান, true বা false, রিটার্ন করে।
match() মেথড কোনো নির্দিষ্ট স্ট্রিং থেকে রেগুলার এক্সপ্রেশনের ম্যাচ এক্সট্র্যাক্ট করে। এটি তথ্য ও ম্যাচসহ একটি অ্যারে রিটার্ন করে।
কখন কোনটি ব্যবহার করবেন? স্ট্রিংয়ের ভেতরে কোনো মান দ্রুত চেক করতে চাইলে test() ব্যবহার করুন, আর ওই মানটি ব্যবহার করতে চাইলে বা ম্যাচ সম্পর্কে আরও তথ্য চাইলে match() ব্যবহার করুন।
test() মেথড একটি রেগুলার এক্সপ্রেশন আর নির্দিষ্ট একটি স্ট্রিংয়ের মধ্যে ম্যাচ খুঁজে সার্চ চালায়। এটি ট্রু বা ফলস রিটার্ন করে।
const str = 'It is difficult to test if you have a virus';
const result = /virus$/.test(str);
console.log(result);
// => true
ঠিক আছে, কিন্তু রেগুলার এক্সপ্রেশন সার্চের আসল মানগুলো যদি আমরা পেতে চাই?
কেবল একটি বুলিয়ান রিটার্ন করার বদলে match() মেথড দিয়ে আমরা একটি কাজের অ্যারে পাই, যার কনটেন্ট নির্ভর করে ম্যাচগুলো পাওয়া গেছে কি না তার উপর।
এভাবে আমরা যেকোনো স্ট্রিং থেকে তথ্য সার্চ ও এক্সট্র্যাক্ট, দুটোই করতে পারি। উদাহরণ:
const funnyQuote =
'If you see someone crying, ask if it is because of their haircut.';
const regex1 = /someone/;
const regex2 = /happy/;
funnyQuote.match(regex1);
// => ["someone", index: 3, input: "If you see someone crying, ask if it is because of their haircut.", groups: undefined]
funnyQuote.match(regex2);
// => null
গ্লোবাল সার্চ ফ্ল্যাগ /g থাকলে, index বা input-এর মতো কাজের তথ্যসহ কেবল একটি ম্যাচ পাওয়ার বদলে মেথডটি অ্যারেতে থাকা সবগুলো ম্যাচ রিটার্ন করে:
const funnyQuote =
'If you see someone crying, ask if it is because of their haircut.';
const regex3 = /if/gi;
funnyQuote.match(regex3);
// => ["If", "if"];
JavaScript-এর replace() মেথড দিয়ে আমরা একটি নির্দিষ্ট স্ট্রিংয়ের ভেতরে কোনো মান খুঁজে সেটি নতুন মান দিয়ে রিপ্লেস করতে পারি।
string.replace(searchValue, newValue);
সাবস্টিটিউশনের জন্য খোঁজার প্যাটার্নটি একটি একক স্ট্রিং বা একটি রেগুলার এক্সপ্রেশন হতে পারে।
let string = 'I like dogs!';
let result = string.replace('dogs', 'cats');
let string = 'I would love to travel to Japan';
let result = string.replace(/Japan/g, 'Hawaii');
আরও, প্রতিটি মানে বাড়তি পরিবর্তন আনার জন্য আমরা রিপ্লেসমেন্টের জায়গায় একটি ফাংশন প্রয়োগ করতে পারি।
let text = 'Say hello to the chatbot.';
let result = text.replace(/chatbot|hello/gi, function (word) {
return word.toUpperCase();
});
// => "Say HELLO to the CHATBOT"
💡 শেষ বিচারে, রেগুলার এক্সপ্রেশন আর
replace()মেথডের সমন্বয় হলো এলিমেন্ট রিপ্লেস করার আরও ডাইনামিক উপায়। একটি একক স্ট্রিং ব্যবহার করলে সীমাবদ্ধতা থেকে যেতে পারে।
JavaScript-এর split() মেথড রেগুলার এক্সপ্রেশন দিয়ে স্ট্রিং ব্যবহার ও ম্যানিপুলেট করার ভিন্ন একটি উপায়।
এভাবে, কোনো প্যাটার্ন চিনে একটি স্ট্রিং ভাগ করার জন্য আমরা রেজেক্স ব্যবহার করব, যেমন str.split(/[,.\s]/)। এই প্যাটার্নটিই separator হিসেবে ব্যবহৃত হবে।
const str = 'hello,user.how are.you';
const result = str.split(/[,.\s]/);
console.log(result);
// => ['hello', 'user', 'how', 'are', 'you']
পারফরম্যান্সের কথা ভাবলে, দুটিই একটি RegExp অবজেক্ট তৈরি করে। মূল পার্থক্য হলো রেজেক্সটি কতবার কম্পাইল হয়:
Regular Expression Literal দিয়ে: কোড প্রথমবার পার্স ও কম্পাইল করার সময় একবারRegExp() সিনট্যাক্স দিয়ে: প্রতিবার নতুন অবজেক্ট তৈরি হওয়ার সময়।শুধু পারফরম্যান্সের কারণেই নয়, সরলতা ও পড়ার সুবিধার জন্যও লিটারাল সিনট্যাক্স ব্যবহার করা ভালো একটি অপশন হতে পারে। আরও বিস্তারিত জানতে এই Stackoverflow আলোচনা দেখুন।
RegExp() কনস্ট্রাক্টর ব্যবহার করলে কোটেশন এস্কেপ করতে হয় এবং ব্যাকস্ল্যাশ দুবার এস্কেপ করতে হয়। এতে রেগুলার এক্সপ্রেশন, যা স্বভাবতই পড়া ও বোঝা কঠিন, আরও কঠিন হয়ে যায়।