মনে হয় গতকালের regex conditionals সম্পর্কে আর্টিকেলের পর আজ কিছু অন্যান্য মজার ট্রিক রুবি রেগুলার এক্সপ্রেশনে দেখাব।
রেগুলার এক্সপ্রেশন দিয়ে স্ট্রিং স্প্লিট
আপনি সম্ভবত টেক্সট ডিলিমিটার দিয়ে স্ট্রিং স্প্লিট করার সাথে খুব পরিচিত:
"one,two".split(",") # => ["one", "two"]
কিন্তু কি আপনি জানেন যে split রেগুলার এক্সপ্রেশনও এক্সেপ্ট করে?
# `,` এবং `-` ডিলিমিটার হিসেবে ব্যবহার
"one,two-three".split(/,|-/) # => ["one", "two", "three"]
# US কারেন্সির জন্য কমা থাউজেন্ড সেপারেটর হিসেবে ব্যবহার,
# কিন্তু ইউরোর জন্য স্পেস
"1,000USD".split /(?=.*(USD))(?(1),| )/
ডিলিমিটার ক্যাপচারিং
এখানে একটি মজার পার্টি ট্রিক। সাধারণত, আপনি যখন একটি স্ট্রিং স্প্লিট করেন, ডিলিমিটারগুলো হারিয়ে যায়:
# কমাগুলো হারিয়ে গেল!
"one,two".split(",") # => ["one", "two"]
কিন্তু আপনি যদি রেগুলার এক্সপ্রেশন ব্যবহার করেন এবং ডিলিমিটারকে একটি গ্রুপের ভেতরে রাখেন, split ডিলিমিটারটিও ক্যাপচার করবে।
"one,two-three".split(/(,|-)/) # => ["one", ",", "two", "-", "three"]
এটি ঘটার কারণ হচ্ছে split আসলে প্রতিটি ক্যাপচার গ্রুপের বাউন্ডারি-এ স্ট্রিং স্প্লিট করে।
Split দুর্নীত
আপনি split কে অপব্যবহার করে অলমস্ট match-এর মতো আচরণ করতে বাধ্য করতে পারেন। নিচের কোডে, আমি রেগুলার এক্সপ্রেশনে চারটি গ্রুপ ব্যবহার করছি স্ট্রিংকে ৪ টুকরোতে স্প্লিট করতে।
"1-800-555-1212".split(/(1)-(\d{3})-(\d{3})-(\d{4})/)
# => ["", "1", "800", "555", "1212"]
ফলাফল অ্যারের প্রথম আইটেম খালি স্ট্রিং কারণ রেগুলার এক্সপ্রেশন পুরো সোর্স স্ট্রিং ম্যাচ করেছে।
গ্লোবাল ম্যাচিং
ডিফল্টভাবে, রেগুলার এক্সপ্রেশন একটি প্যাটার্ন একবারই ম্যাচ করে। নিচের কোডে, পাঁচটি সম্ভাব্য ম্যাচ থাকা সত্ত্বেও আমরা শুধু একটি ম্যাচ পাই।
"12345".match /\d/ # => #<MatchData "1">
পার্লের মতো অন্যান্য ল্যাঙ্গুয়েজে সমাধান হচ্ছে রেগুলার এক্সপ্রেশনকে "গ্লোবাল" ফ্ল্যাগ করা। রুবিতে সেটি নেই, কিন্তু String#scan মেথড আছে।
scan মেথড সব ম্যাচ ধারণকারী একটি অ্যারে রিটার্ন করে:
"12345".scan /\d/ # => ["1", "2", "3", "4", "5"]
এটিতে একটি হ্যান্ডি ব্লক সিনট্যাক্সও আছে:
"12345".scan /\d/ do |i|
puts i
end
দুর্ভাগ্যবশত, স্ট্রিংকে লেজিলি স্ক্যান করার কোনো উপায় নেই মনে হয়। তাই এই টেকনিক probable ৫০০MB ফাইল প্রসেস করার জন্য উপযুক্ত নয়।
গ্রুপ সহ স্ক্যানিং
এই পয়েন্টে আশা করি আপনি চিন্তা করছেন গ্রুপ ব্যবহার করে scan-এ কী কুল ট্রিক করা যায়।
দুর্ভাগ্যবশত, এখানে আচরণ সম্পূর্ণ প্রেডিক্টেবল এবং BORING। গ্রুপ ব্যবহার করলে মাল্টি-ডাইমেনশনাল অ্যারে রিটার্ন হয়:
"hiho hiho".scan /(hi)(ho)/ # => [["hi", "ho"], ["hi", "ho"]]
একটি অদ্ভুত এজ কেস আছে। আপনি যদি গ্রুপ ব্যবহার করেন, যেকোনো জিনিস গ্রুপে না থাকলে সেটি রিটার্ন হবena।
"hiho hiho".scan /(hi)ho/ # => [["hi"], ["hi"]]
শর্টহ্যান্ড
আমি ধরে নিচ্ছি আপনি =~ সম্পর্কে জানেন রেগুলার এক্সপ্রেশন ম্যাচ চেক করার একটি উপায় হিসেবে। এটি সেই ক্যারেক্টারের ইনডেক্স রিটার্ন করে যেখানে ম্যাচ শুরু হয়।
"hiho" =~ /hi/ # 0
"hiho" =~ /ho/ # 2
ম্যাচ চেক করার আরেকটি কুইক উপায় আছে। আমি কথা বলছি === অপারেটরের।
/hi/ === "hiho" # true
রুবিতে আপনি যখন a === b লিখেন, আপনি প্রশ্ন করছেন "kya b a-র সংজ্ঞায়িত সেটে বেলং করে"। বা এই কেসে, "kya 'hiho' রেগুলার এক্সপ্রেশন /hi/-এর ম্যাচ করা স্ট্রিংস সেটে বেলং করে"।
=== অপারেটর রুবির case স্টেটমেন্টে ইন্টারন্যালি ব্যবহার হয়। এর মানে আপনি case স্টেটমেন্টে রেগুলার এক্সপ্রেশনও ব্যবহার করতে পারেন।
case "hiho"
when /hi/
puts "match"
end
ট্রিপল-ইকুয়ালস অপারেটর আপনার নিজের মেথডগুলোকেও রেগুলার এক্সপ্রেশন বা স্ট্রিং এক্সেপ্ট করার জন্য ইউজফুল হতে পারে।
কল্পনা করুন আপনি একটি এরর হলে কিছু কোড এক্সিকিউট করতে চান, যদি না সেটি একটি প্রি-কনফিগারড লিস্টের ক্লাসে থাকে যা ইগনোর করতে হবে। নিচের উদাহরণে, আমরা === অপারেটর ব্যবহার করি যাতে ইউজার স্ট্রিং বা রেগুলার এক্সপ্রেশন যেকোনো একটা স্পেসিফাই করতে পারে।
def ignored?(error)
@ignored_patterns.any? { |x| x === error.class.name }
end
শেষ!
নিশ্চিত রুবি এবং রেইলসে এতেক подоб আরো দশক সাথে ট্রিক ছড়িয়ে পড়া আছে। আপনার কাছে যদি কোনো একটা পছন্দের ট্রিক থাকে, আমাকে জানান!