রেগুলার এক্সপ্রেশন (রেজেক্স) হলো এমন কিছু অক্ষরের ক্রম, যা টেক্সটে খোঁজার একটি প্যাটার্ন নির্দিষ্ট করে।
রেগুলার এক্সপ্রেশনের সিনট্যাক্স শেখা এই টপিকের আলোচনার বাইরে। আমরা এখানে jq রেজেক্স ব্যবহারের জন্য যে এক্সপ্রেশনগুলো সরবরাহ করে, সেগুলোতেই মন দেব।
ভিন্ন ভিন্ন টুল রেগুলার এক্সপ্রেশনের ভিন্ন ভিন্ন সংস্করণ তৈরি করে। jq ব্যবহার করে Oniguruma রেজেক্স লাইব্রেরি, যা Perl v5.8-এর রেজেক্সের সাথে বেশিরভাগ ক্ষেত্রেই সামঞ্জস্যপূর্ণ।
jq যে নির্দিষ্ট সিনট্যাক্স ব্যবহার করে, তা Oniguruma-র GitHub রিপোতে পাওয়া যাবে।
jq-এ রেগুলার এক্সপ্রেশনের জন্য কোনো আলাদা সিনট্যাক্স নেই। এগুলোকে কেবল স্ট্রিং হিসেবে লেখা হয়। তার মানে হলো, রেগুলার এক্সপ্রেশনে থাকা যেকোনো ব্যাকস্ল্যাশকে স্ট্রিংয়ের ভেতরে এস্কেপ করতে হবে।
উদাহরণস্বরূপ, ডিজিট ক্যারেক্টার ক্লাস (\d) লিখতে হবে "\\d" হিসেবে।
jq-এ রেগুলার এক্সপ্রেশন ব্যবহার সীমাবদ্ধ কিছু ফিল্টারের মধ্যে।
একটি স্ট্রিং কোনো প্যাটার্নের সাথে মিলছে কি না জানতে চাইলে test ফিল্টার ব্যবহার করুন।
STRING | test(REGEX)
STRING | test(REGEX; FLAGS)
STRING | test([REGEX, FLAGS])
এই ফিল্টারটি একটি বুলিয়ান ফলাফল আউটপুট দেয়।
"Hello World!" | test("W") # => true
"Goodbye Mars" | test("W") # => false
প্যাটার্নের সাথে আসলে যে সাবস্ট্রিংটি মিলেছে তা বের করতে চাইলে match ফিল্টার ব্যবহার করুন।
STRING | match(REGEX)
STRING | match(REGEX; FLAGS)
STRING | match([REGEX, FLAGS])
এই ফিল্টারটি আউটপুট দেয়:
এই উদাহরণটি ব্যাকরেফ সিনট্যাক্স \1 ব্যবহার করে পরপর দুটি একই স্বরবর্ণ খুঁজে বের করে।
"Hello World!" | match("([aeiou])\\1")
# => empty
"Goodbye Mars" | match("([aeiou])\\1")
# => {
# "offset": 1,
# "length": 2,
# "string": "oo",
# "captures": [
# {
# "offset": 1,
# "length": 1,
# "string": "o",
# "name": null
# }
# ]
# }
match ফিল্টার প্রতিটি ম্যাচের জন্য একটি অবজেক্ট রিটার্ন করে। এই উদাহরণে সব স্বরবর্ণ খুঁজে বের করতে "g" ফ্ল্যাগটি কাজে লাগানো হয়েছে।
"Goodbye Mars" | match("[aeiou]"; "g")
# => { "offset": 1, "length": 1, "string": "o", "captures": [] }
# { "offset": 2, "length": 1, "string": "o", "captures": [] }
# { "offset": 6, "length": 1, "string": "e", "captures": [] }
# { "offset": 9, "length": 1, "string": "a", "captures": [] }
match ফিল্টারের মতোই, ম্যাচ থাকলে capture ফিল্টার একটি অবজেক্ট রিটার্ন করে।
STRING | capture(REGEX)
STRING | capture(REGEX; FLAGS)
STRING | capture([REGEX, FLAGS])
রিটার্ন করা অবজেক্টটি হলো নেমড ক্যাপচারগুলোর একটি ম্যাপিং।
"JIRAISSUE-1234" | capture("(?<project>\\w+)-(?<issue_num>\\d+)")
# => {
# "project": "JIRAISSUE",
# "issue_num": "1234"
# }
scan ফিল্টারটি "g" ফ্ল্যাগসহ match-এর মতোই।
STRING | scan(REGEX)
STRING | scan(REGEX; FLAGS)
# note, there is no scan([REGEX, FLAGS]) version, unlike other filters
scan সাবস্ট্রিংগুলোর একটি স্ট্রিম আউটপুট দেবে।
"Goodbye Mars" | scan("[aeiou]")
# => "o"
# "o"
# "e"
# "a"
সাবস্ট্রিংগুলো ক্যাপচার করতে [...] অ্যারে কনস্ট্রাক্টর ব্যবহার করুন।
"Goodbye Mars" | [ scan("[aeiou]") ]
# => ["o", "o", "e", "a"]
স্ট্রিংয়ের যে অংশগুলো আপনি রাখতে চান সেগুলো জানা থাকলে match বা scan ব্যবহার করুন। আর যে অংশগুলো বাদ দিতে চান সেগুলো জানা থাকলে split ব্যবহার করুন।
STRING | split(REGEX; FLAGS)
এক-আর্গুমেন্টের split ফিল্টার তার আর্গুমেন্টকে একটি ফিক্সড স্ট্রিং হিসেবে ধরে নেয়।
split-এর সাথে রেজেক্স ব্যবহার করতে হলে আপনাকে অবশ্যই দ্বিতীয় আর্গুমেন্টটি দিতে হবে; সেখানে খালি স্ট্রিং দিলেও সমস্যা নেই।
নিচের উদাহরণটি যেকোনো রকম হোয়াইটস্পেসে একটি স্ট্রিং ভাগ করে।
"first second third fourth" | split("\\s+"; "")
# => ["first", "second", "third", "fourth"]
ফ্ল্যাগ আর্গুমেন্টটি ভুলে গেলে যা হয়, তা এই:
"first second third fourth" | split("\\s+")
# => ["first second third fourth"]
ফলাফল মাত্র একটি: ইনপুটে ফিক্সড স্ট্রিং \s+ খুঁজে পাওয়া যায়নি।
এক-আর্গুমেন্টের split যেকোনো রকম হোয়াইটস্পেস সামলাতে পারে না। স্পেস দিয়ে ভাগ করলে ফল হয় এই রকম।
"first second third fourth" | split(" ")
# => ["first", "", "", "second", "", "", "", "",
# "", "", "", "", "", "", "third", "fourth" ]
sub ও gsub ফিল্টার ইনপুট স্ট্রিংটিকে রূপান্তর করতে পারে, ইনপুটের মিলে যাওয়া অংশগুলোর জায়গায় একটি রিপ্লেসমেন্ট স্ট্রিং বসিয়ে দিয়ে।
কেবল প্রথম ম্যাচটি বদলাতে চাইলে sub ব্যবহার করুন। সব ম্যাচ বদলাতে চাইলে gsub ব্যবহার করুন।
STRING | sub(REGEX; REPLACEMENT)
STRING | sub(REGEX; REPLACEMENT; FLAGS)
STRING | gsub(REGEX; REPLACEMENT)
STRING | gsub(REGEX; REPLACEMENT; FLAGS)
"Goodnight kittens. Goodnight mittens." | sub("night"; " morning")
# => "Good morning kittens. Goodnight mittens."
"Goodnight kittens. Goodnight mittens." | gsub("night"; " morning")
# => "Good morning kittens. Good morning mittens."
রিপ্লেসমেন্ট টেক্সটে মিলে যাওয়া সাবস্ট্রিংগুলো উল্লেখ করা যায়; এর জন্য নেমড ক্যাপচার ও স্ট্রিং ইন্টারপোলেশন ব্যবহার করুন।
"Some 3-letter acronyms: gnu, csv, png"
| gsub( "\\b(?<tla>[[:alpha:]]{3})\\b"; # find words 3 letters long
"\(.tla | ascii_upcase)" ) # upper-case the match
# => "Some 3-letter acronyms: GNU, CSV, PNG"
উপরের সব ফিল্টারেই FLAGS হলো একটি স্ট্রিং, যাতে সমর্থিত ফ্ল্যাগগুলোর শূন্য বা তার বেশি সংখ্যক থাকতে পারে।
g - গ্লোবাল সার্চ (কেবল প্রথমটি নয়, সব ম্যাচ খুঁজে বের করে)i - কেস-ইনসেনসিটিভ সার্চm - মাল্টি লাইন মোড ('.' নিউলাইনও ম্যাচ করবে)n - খালি ম্যাচ উপেক্ষা করেp - s ও m দুটি মোডই চালু থাকেs - সিঙ্গল লাইন মোড ('^' -> '\A', '$' -> '\Z')l - সম্ভাব্য সবচেয়ে লম্বা ম্যাচ খুঁজে বের করেx - এক্সটেন্ডেড রেজেক্স ফরম্যাট (হোয়াইটস্পেস ও কমেন্ট উপেক্ষা করে)উদাহরণস্বরূপ
"JIRAISSUE-1234" | capture("(?<project>\\w+)-(?<issue_num>\\d+)")
# or with Extended formatting
"JIRAISSUE-1234" | capture("
(?<project> \\w+ ) # the Jira project
- # followed by a hyphen
(?<issue_num> \\d+ ) # followed by digits
"; "x")