রুবি রেগুলার এক্সপ্রেশন (রুবি regex সংক্ষেপে) আপনাকে স্ট্রিংয়ের ভেতর নির্দিষ্ট প্যাটার্ন খুঁজে বের করতে সাহায্য করে, ডেটা এক্সট্রাক্ট করার উদ্দেশ্যে আরও প্রসেসিং-এর জন্য।
রেগুলার এক্সপ্রেশনের দুটি সাধারণ ইউজ কেস হলো ভ্যালিডেশন এবং পার্সিং।
উদাহরণস্বরূপ:
একটি ইমেইল অ্যাড্রেস সম্পর্কে চিন্তা করুন, একটি রুবি regex দিয়ে আপনি ডিফাইন করতে পারেন একটি বৈধ ইমেইল অ্যাড্রেস কেমন দেখাবে। অন্য কথায়, আপনার প্রোগ্রাম একটি বৈধ এবং অবৈধ ইমেইল অ্যাড্রেসের পার্থক্য বুঝতে পারবে।

রুবি রেগুলার এক্সপ্রেশন দুটি ফরোয়ার্ড স্ল্যাশের মাঝপথে ডিফাইন করা হয় অন্যান্য ল্যাঙ্গুয়েজ সিনট্যাক্স থেকে আলাদা করার জন্য। সবচেয়ে সিম্পল এক্সপ্রেশনগুলো একটি ওয়ার্ড বা এমনকি একটি সিঙ্গল লেটার ম্যাচ করে।
উদাহরণস্বরূপ:
# 'like' শব্দটি খুঁজুন "Do you like cats?" =~ /like/
এটি ওয়ার্ডটি প্রথমবার পাওয়া গেলে এর ইনডেক্স রিটার্ন করবে (সফল ম্যাচ) অথবা nil অন্যথায়। আমাদের যদি ইনডেক্স নিয়ে কনসার্ন না থাকে তবে আমরা String#include? মেথড ব্যবহার করতে পারি।
একটি স্ট্রিং রেগেক্স ম্যাচ করছে কিনা চেক করার আরেকটি পদ্ধতি হলো match মেথড ব্যবহার করা:
if "Do you like cats?".match(/like/) puts "Match found!" end
এখন:
আপনি শিখবেন কীভাবে আরও অ্যাডভান্সড প্যাটার্ন বানাতে হয় যাতে আপনি ডেট, ফোন নম্বর, ইমেইল, URL, ইত্যাদি ম্যাচ, ক্যাপচার এবং রিপ্লেস করতে পারেন।
ক্যারেক্টার ক্লাস
একটি ক্যারেক্টার ক্লাস আপনাকে একটি রেঞ্জ বা ক্যারেক্টার লিস্ট ডিফাইন করতে দেয় ম্যাচ করার জন্য। উদাহরণস্বরূপ, [aeiou] যেকোনো ভোয়েল ম্যাচ করে।
উদাহরণ: স্ট্রিংটি কি একটি ভোয়েল ধারণ করে?
def contains_vowel(str) str =~ /[aeiou]/ end contains_vowel("test") # returns 1 contains_vowel("sky") # returns nil
এটি ক্যারেক্টারların পরিমাণ বিবেচনা করবে না, আমরা শীঘ্রই দেখব কীভাবে সেটা করব।
রেঞ্জ
আমরা রেঞ্জ ব্যবহার করতে পারি একাধিক লেটার বা নাম্বার ম্যাচ করতে তাদের সব টাইপ না করেও। অন্য কথায়, [2-5] এর মতো একটি রেঞ্জ সেম [2345]।
কয়েকটি উপকারী রেঞ্জ:
- [0-9] ০ থেকে ৯ পর্যন্ত যেকোনো নাম্বার ম্যাচ করে
- [a-z] a থেকে z পর্যন্ত যেকোনো লেটার ম্যাচ করে (ক্যাপস নয়)
- [^a-z] নিগেটেড রেঞ্জ
উদাহরণ: এই স্ট্রিংটি কি কোনো নাম্বার ধারণ করে?
def contains_number(str) str =~ /[0-9]/ end contains_number("The year is 2015") # returns 12 contains_number("The cat is black") # returns nil
মনে রাখবেন: `=~` ব্যবহার করার সময় রিটার্ন ভ্যালু হয় স্ট্রিং ইনডেক্স অথবা `nil`
ক্যারেক্টার রেঞ্জ স্পেসিফাই করার একটি সুন্দর শর্টহ্যান্ড সিনট্যাক্স রয়েছে:
- \w সমতুল্য [0-9a-zA-Z_]
- \d সেম [0-9]
- \s হোয়াইট স্পেস ম্যাচ করে (ট্যাব, রেগুলার স্পেস, নিউলাইন)
এইগুলোর নেগেটিভ ফর্মও রয়েছে:
- \W যেকোনো জিনিস যা [0-9a-zA-Z_]-এ নেই
- \D যেকোনো জিনিস যা নাম্বার নয়
- \S যেকোনো জিনিস যা স্পেস নয়
ডট ক্যারেক্টার . নিউলাইন বাদে সব কিছুর সাথে ম্যাচ করে। আপনি যদি একটি লিটারেল . ব্যবহার করতে চান তবে আপনাকে এটি এস্কেপ করতে হবে।
উদাহরণ: স্পেশাল ক্যারেক্টার এস্কেপ করা
# আমরা যদি এস্কেপ না করি, লেটারটি ম্যাচ করবে "5a5".match(/\d.\d/) # এই কেসে শুধু লিটারেল ডট ম্যাচ করবে "5a5".match(/\d\.\d/) # nil "5.5".match(/\d\.\d/) # match
মডিফায়ার
এখন পর্যন্ত আমরা শুধু একটি সিঙ্গল ক্যারেক্টার ম্যাচ করতে পেরেছি। একাধিক ক্যারেক্টার ম্যাচ করতে আমরা প্যাটার্ন মডিফায়ার ব্যবহার করতে পারি।
| মডিফায়ার | বিবরণ |
|---|---|
| + | ১ বা অধিক |
| * | ০ বা অধিক |
| ? | ০ বা ১ |
| {3,5} | ৩ এবং ৫ এর মাঝপথে |
আমরা এখন পর্যন্ত শিখেছি সব কিছুর কম্বিনেশন দিয়ে আরও কমপ্লেক্স রেগুলার এক্সপ্রেশন তৈরি করতে পারি।
উদাহরণ: এটি কি একটি IP অ্যাড্রেসের মতো দেখাচ্ছে?
# নোট করুন এটি কিছু অবৈধ IP অ্যাড্রেসও ম্যাচ করবে # যেন 999.999.999.999, কিন্তু এই কেসে আমরা শুধু ফরম্যাটকে কেয়ার করি। def ip_address?(str) # আমরা !! ব্যবহার করি রিটার্ন ভ্যালুকে বুলিয়ানে কনভার্ট করার জন্য !!(str =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) end ip_address?("192.168.1.1") # returns true ip_address?("0000.0000") # returns false
এক্সাক্ট স্ট্রিং ম্যাচিং
আপনি যদি এক্সাক্ট ম্যাচ চান তবে আপনাকে অন্য টাইপের মডিফায়ার লাগবে। একটি উদাহরণ দেখি যাতে আপনি বুঝতে পারেন আমি কী বলছি:
# আমরা চাই এই স্ট্রিংটি এক্সাক্টলি চার লেটার লম্বা কিনা, এটি ম্যাচ করবে কারণ এরা বেশি লম্বা, কিন্তু এটি আমরা চাই নাই। "Regex are cool".match /\w{4}/ # বদলে আমরা 'beginning of line' এবং 'end of line' মডিফায়ার ব্যবহার করব "Regex are cool".match /^\w{4}$/ # এই বার এটি ম্যাচ করবে না। এটি একটি নিরূপণ উদাহরণ, কারণ আমরা শুধু .size ব্যবহার করতে পারতাম লেন্থ পেতে, কিন্তু আমি মনে করি আইডিয়া বুঝানো হয়েছে।
এক স্ট্রিংয়ের শুরুতে স্ট্রিক্টলি ম্যাচ করতে এবং শুধু প্রতিটি লাইনে না (একটি \n-এর পরে) আপনাকে \A এবং \Z ব্যবহার করতে হবে ^ এবং $-র বদলে।
ক্যাপচার গ্রুপ
ক্যাপচার গ্রুপের সাথে, আমরা একটি ম্যাচের অংশ ক্যাপচার করতে পারি এবং পরে পুনরায় ব্যবহার করতে পারি। আমরা যে অংশটি ক্যাপচার করতে চাই সেটিকে প্যারেনথেসিসে এনক্লোজ করি।
উদাহরণ: একটি লগ ফাইল পার্স করা
Line = Struct.new(:time, :type, :msg) LOG_FORMAT = /(\d{2}:\d{2}) (\w+) (.*)/ def parse_line(line) line.match(LOG_FORMAT) { |m| Line.new(*m.captures) } end parse_line("12:41 INFO User has logged in.") # এটি এইরকম অবজেক্ট প্রডিউস করে: #
এই উদাহরণে, আমরা .match ব্যবহার করছি =~-এর বদলে।
এই মেথডটি একটি MatchData অবজেক্ট রিটার্ন করে যদি ম্যাচ থাকে, অন্যথায় nil। MatchData ক্লাসের অনেক উপকারী মেথড রয়েছে, ডকুমেন্টেশন দেখুন আরও জানতে!
আপনি যদি শুধু একটি বুলিয়ান ভ্যালু (true / false) চান তবে আপনি match? মেথড ব্যবহার করতে পারেন, যা রুবি ২.৪ থেকে উপলব্ধ। এটি match-এর চেয়ে ফাস্টার কারণ রুবিকে MatchData অবজেক্ট তৈরি করতে হয় না।
আপনি ক্যাপচার করা ডেটা এক্সেস করতে পারেন .captures মেথড বা MatchData অবজেক্টকে অ্যারে মনে করে, জিরো ইনডেক্সে ফুল ম্যাচ থাকবে এবং পরের ইনডেক্সগুলো ম্যাচ করা গ্রুপগুলো ধারণ করবে।
আপনি যদি প্রথম ক্যাপচার গ্রুপ চান তবে এভাবে করতে পারেন:
m = "John 31".match /\w+ (\d+)/ m[1] # 31
আপনার নন-ক্যাপচারিং গ্রুপও থাকতে পারে। এগুলো আপনাকে এক্সপ্রেশনগুলো গ্রুপ করতে দেবে কোনো পারফরম্যান্স পেনাল্টি ছাড়া। আপনি নেমড গ্রুপও উপকারী পেতে পারেন কমপ্লেক্স এক্সপ্রেশন পড়া সহজ করতে।
| সিনট্যাক্স | বিবরণ |
|---|---|
(?:...) |
Non-capturing group |
(?<foo>...) |
Named group |
উদাহরণ: Named Groups
m = "David 30".match /(?\w+) (?\d+)/ m[:age] # => "30" m[:name] # => "David"
একটি নেমড গ্রুপ একটি MatchData অবজেক্ট রিটার্ন করে যেটি আপনি রেজাল্ট পড়তে এক্সেস করতে পারেন।
Look Ahead এবং Look Behind
এটি একটি আরও অ্যাডভান্সড টেকনিক যা সব রেগেক্স ইমপ্লিমেন্টেশনে উপলব্ধ নাও হতে পারে। রুবির রেগুলার এক্সপ্রেশন ইঞ্জিন এটি করতে পারে, তাই চলুন দেখি কীভাবে এর সুবিধা নেওয়া যায়।
Look ahead আমাদের দরকার দিয়ে পিক করতে দেয় এবং দেখতে দেয় একটি স্পেসিফিক ম্যাচ আগে বা পরে আছে কিনা।
| নাম | বিবরণ |
|---|---|
| (?=pat) | Positive lookahead |
| (?<=pat) | Positive lookbehind |
| (?!pat) | Negative lookahead |
| (?<!pat) | Negative lookbehind |
উদাহরণ: কমপক্ষে একটি লেটারের পর একটি নাম্বার আছে কিনা?
def number_after_word?(str) !!(str =~ /(?<=\w) (\d+)/) end number_after_word?("Grade 99")
রুবির Regex ক্লাস
রুবি রেগুলার এক্সপ্রেশন Regexp ক্লাসের ইনস্ট্যান্স। অধিকাংশ সময় আপনি এই ক্লাসটি সরাসরি ব্যবহার করবেন না, তবে জানা ভালো 🙂
puts /a/.class # Regexp
একটি সম্ভাব্য ব্যবহার হলো একটি স্ট্রিং থেকে regex তৈরি করা:
regexp = Regexp.new("a")
Regexp তৈরি করার আরেকটি পদ্ধতি:
regexp = %r{\w+}
Regex অপশনস
আপনি আপনার রেগুলার এক্সপ্রেশনে কিছু অপশন সেট করতে পারেন যাতে এটি আলাদা ভাবে বیهেভ করে।
| অপশন | বিবরণ |
|---|---|
| i | ruby regex case insensitive |
| m | dot matches newline |
| x | ignore whitespace |
এই অপশনগুলো ব্যবহার করতে আপনি রেজেক্সের শেষে, ক্লোজিং /-এর পর লেটারটি যোগ করুন।
যেন:
"abc".match?(/[A-Z]/i)
লম্বা রেগুলার এক্সপ্রেশন ফরম্যাট করা
কমপ্লেক্স রুবি রেগুলার এক্সপ্রেশন খুব হার্ড হয় পড়তে, তাই এটি হেল্পফুল হবে যদি আমরা এটিকে একাধিক লাইনে ভাঙি। আমরা এটা করতে পারি ‘x’ মডিফায়ার ব্যবহার করে। এই ফরম্যাট আপনাকে আপনার regex-এ কমেন্ট ব্যবহার করতে দেয়।
উদাহরণ:
LOG_FORMAT = %r{ (\d{2}:\d{2}) # Time \s(\w+) # Event type \s(.*) # Message }x
রুবি regex: সব কিছু একসাথে
রেগুলার এক্সপ্রেশন অনেক রুবি মেথডের সাথে ব্যবহার করা যায়।
- .split
- .scan
- .gsub
- এবং আরও অনেক…
উদাহরণ: .scan ব্যবহার করে একটি স্ট্রিং থেকে সকল ওয়ার্ড ম্যাচ করুন
"this is some string".scan(/\w+/) # => ["this", "is", "some", "string"]
উদাহরণ: একটি স্ট্রিং থেকে সকল নাম্বার এক্সট্রাক্ট করুন
"The year was 1492.".scan(/\d+/) # => ["1492"]
উদাহরণ: একটি স্ট্রিংয়ের সকল ওয়ার্ড ক্যাপিটালাইজ করুন
str = "lord of the rings" str.gsub(/\w+/) { |w| w.capitalize } # => "Lord Of The Rings"
উদাহরণ: একটি ইমেইল অ্যাড্রেস ভ্যালিডেট করুন
email = "test@example.com" !!email.match(/\A[\w.+-]+@\w+\.\w+\z/) # true
এই শেষ উদাহরণটি !! ব্যবহার করে রেজাল্টকে বুলিয়ান ভ্যালুতে (true / false) কনভার্ট করে, অথবা আপনি রুবি ২.৪+ এ match? মেথড ব্যবহার করতে পারেন যা ইতিমধ্যে এটি করে দেয় এবং এটি ফাস্টারও।
উপসংহার
রেগুলার এক্সপ্রেশন চমৎকার কিন্তু কখনো কখনো একটু ট্রিকি হতে পারে। Rubular.com-এর মতো একটি টুল ব্যবহার করে আপনি আপনার রুবি regex-কে আরও ইন্টারঅ্যাক্টিভভাবে বানাতে পারেন। Rubular-এ একটি রুবি রেগুলার এক্সপ্রেশন চিট শিটও রয়েছে যা আপনি খুব উপকারী পাবেন। এখন আপনার পালা, এডিটর খুলুন এবং কোডিং শুরু করুন!
ওহ, এবং আপনার বন্ধুদের সাথে এটি শেয়ার করা ভুলবেন না আপনি যদি এটিকে এনজয় করেন, যাতে আরও মানুষ শিখতে পারে 🙂