ট্র্যাক
/
jq
jq
/
অনুশীলনী
/
রেগুলার চ্যাটবট
রেগুলার চ্যাটবট

রেগুলার চ্যাটবট

লার্নিং অনুশীলনী

ভূমিকা

রেগুলার এক্সপ্রেশন

রেগুলার এক্সপ্রেশন (রেজেক্স) হলো অক্ষরের এমন একটি ক্রম, যা টেক্সটে খোঁজার একটি প্যাটার্ন ঠিক করে দেয়।

রেগুলার এক্সপ্রেশনের সিনট্যাক্স শেখানো এই টপিকের পরিধির বাইরে। আমরা রেজেক্স কাজে লাগাতে jq যে এক্সপ্রেশনগুলো দেয়, সেগুলোতেই মনোযোগ দেব।

রেজেক্সের ধরন

ভিন্ন ভিন্ন টুল রেগুলার এক্সপ্রেশনের ভিন্ন ভিন্ন ভার্সন বাস্তবায়ন করে। jq Oniguruma রেজেক্স লাইব্রেরিটি ব্যবহার করে, যা Perl v5.8-এর রেজেক্সের সাথে বেশিরভাগ ক্ষেত্রেই সামঞ্জস্যপূর্ণ।

jq যে নির্দিষ্ট সিনট্যাক্স ব্যবহার করে, তা Oniguruma GitHub রিপোতে পাওয়া যাবে।

Caution

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)

scan সাবস্ট্রিংয়ের একটি স্ট্রিম আউটপুট দেবে।

"Goodbye Mars" | scan("[aeiou]")
# => "o"
#    "o"
#    "e"
#    "a"

সাবস্ট্রিংগুলো ক্যাপচার করতে [...] অ্যারে কনস্ট্রাক্টরটি ব্যবহার করুন।

"Goodbye Mars" | [ scan("[aeiou]") ]
# => ["o", "o", "e", "a"]
স্ট্রিং ভাগ করা

স্ট্রিংয়ের যে অংশগুলো আপনি রাখতে চান সেগুলো যদি জানা থাকে, তবে match বা scan ব্যবহার করুন। আর যে অংশগুলো আপনি বাদ দিতে চান সেগুলো যদি জানা থাকে, তবে split ব্যবহার করুন।

STRING | split(REGEX; FLAGS)
Caution

একটি মাত্র আর্গুমেন্ট নেওয়া split ফিল্টারটি তার আর্গুমেন্টকে একটি ফিক্সড স্ট্রিং হিসেবে ধরে।

split-এর সাথে রেজেক্স ব্যবহার করতে হলে আপনাকে অবশ্যই দ্বিতীয় আর্গুমেন্টটি দিতে হবে; খালি স্ট্রিং দিলেও চলবে।

যেকোনো হোয়াইটস্পেসে একটি স্ট্রিং ভাগ করার একটি উদাহরণ।

"first   second           third fourth" | split("\\s+"; "")
# => ["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")

নির্দেশনা

আপনি একটি কোম্পানিতে রেগুলার এক্সপ্রেশন স্পেশালিস্ট হিসেবে নিয়োগ পেয়েছেন, যে কোম্পানি একটি চ্যাটবট তৈরি করছে।

এটি এখন উন্নয়নের একেবারে প্রাথমিক পর্যায়ে আছে। আপনার মিশন হলো রেগুলার এক্সপ্রেশন ব্যবহার করে প্রাকৃতিক ভাষা বোঝা ও তৈরি করার চ্যাটবটের ক্ষমতা বাড়ানো।

1. বৈধ কমান্ড যাচাই করুন

বুদ্ধিমান হওয়ার পাশাপাশি চ্যাটবট একজন বিশ্বস্ত সহকারীও। চ্যাটবটকে কিছু জিজ্ঞাসা করতে হলে ব্যবহারকারীকে কমান্ডের একেবারে প্রথমে "Chatbot" শব্দটি বলতে হবে। কিওয়ার্ডটি বড় হাতের অক্ষরে লেখা হোক বা ছোট হাতের অক্ষরে, তাতে কিছু যায় আসে না। গুরুত্বপূর্ণ হলো শব্দটির অবস্থান।

is_valid_command ফাংশনটি ইমপ্লিমেন্ট করুন, যা ব্যবহারকারী কখন কমান্ড দিচ্ছে তা চিনতে চ্যাটবটকে সাহায্য করে।

"Chatbot, play a song from the 80's." | is_valid_command
# => true
"Hey Chatbot, where is the closest pharmacy?" | is_valid_command
# => false
"CHATBOT, do you have a solution for this challenge?" | is_valid_command
# => true

2. এনক্রিপ্টেড ইমোজি সরান

মানুষ কীভাবে মনের ভাব প্রকাশ করতে ইমোজি ব্যবহার করে, তা বুঝতে চ্যাটবটের বেশ কষ্ট হয়। চ্যাটবট ব্যবহারকারীর মেসেজ পেলে প্রতিটি ইমোজি লেখা হয় "emoji" স্ট্রিং এবং তার পরে একটি id নম্বর হিসেবে।

remove_emoji মেথডটি ইমপ্লিমেন্ট করুন, যা একটি স্ট্রিং নিয়ে মেসেজের সব ইমোজি সরিয়ে দেয়।

যে লাইনগুলোতে ইমোজি নেই, সেগুলো অপরিবর্তিত অবস্থায় রিটার্ন করা উচিত। শুধু emoji স্ট্রিংটি সরিয়ে দিন। হোয়াইটস্পেস বদলাবেন না।

"I love playing videogames emoji3465 it's one of my hobbies" | remove_emoji
# => "I love playing videogames  it's one of my hobbies"

3. বৈধ ফোন নম্বর যাচাই করুন

চ্যাটবটের সাথে কথোপকথনের কোনো এক পর্যায়ে ব্যবহারকারী একটি ফোন নম্বর দেবে। চ্যাটবট কেবল একটি নির্দিষ্ট ফরম্যাটের নম্বরেই কল করতে পারে।

check_phone_number ফাংশনটি ইমপ্লিমেন্ট করুন।

নম্বরটি বৈধ হলে চ্যাটবট ব্যবহারকারীকে ধন্যবাদ জানিয়ে এবং নম্বরটি নিশ্চিত করে একটি বার্তা দেয়। নম্বরটি অবৈধ হলে চ্যাটবট ব্যবহারকারীকে জানায় যে ফোন নম্বরটি বৈধ নয়।

প্রত্যাশিত ফরম্যাট হলো (+NN) NNN-NNN-NNN, যেখানে N একটি ডিজিট।

"chatbot my phone number is (+34) 659-771-594" | check_phone_number
# => "Thanks! Your phone number is OK."
"chatbot, call me at 659-771-594" | check_phone_number
# => "Oops, it seems like I can't reach out to 659-771-594."

4. ওয়েবসাইট লিংক পান

চ্যাটবট সত্যিই একটি কৌতূহলী সফটওয়্যার। কোনো নির্দিষ্ট বিষয়ে এটি ইন্টারনেটে খুঁজতে পারলেও, প্রাসঙ্গিক তথ্য খুঁজে পেতে ব্যবহারকারীদের কাছে ঘুরে দেখার মতো দারুণ সব ওয়েবসাইট সম্পর্কে জানতে ভালোবাসে।

উদাহরণ কথোপকথন:

Chatbot: হে ব্যবহারকারী, আমি JavaScript-এ কোড করা শিখতে চাই। আপনি কি এমন কোনো দারুণ ওয়েবসাইট চেনেন যেখানে আমি শিখতে পারব?

User: আমি exercism.org থেকে অনেক কিছু শিখেছি, ওখানে দারুণ সব জিনিস আছে।

get_domains ফাংশনটি ইমপ্লিমেন্ট করুন, যা ওয়েবসাইট ডোমেইনগুলোর একটি অ্যারে রিটার্ন করে।

"I learned a lot from exercism.org and google.com" | get_domains
# => ["exercism.org", "google.com"]

5. ব্যবহারকারীকে স্বাগত জানান

ভদ্র একটি চ্যাটবট ব্যবহারকারীদের নাম ধরে সম্বোধন করে। ব্যবহারকারী নিজের পরিচয় দিলে আমাদের চ্যাটবট তার নাম শনাক্ত করে বন্ধুত্বপূর্ণ অভিবাদন জানায়।

nice_to_meet_you ফাংশনটি লিখুন।

ইনপুট স্ট্রিংয়ে "My name is Someone." থাকলে নামটি ক্যাপচার করুন এবং "Nice to meet you, Someone." স্ট্রিংটি রিটার্ন করুন।

"My name is Jean-Luc" | nice_to_meet_you
# => "Nice to meet you, Jean-Luc"

6. অতি সরল CSV পার্সিং

"একটার পর একটা ফিচার যোগ করার নেশা"-র কাছে হার মেনে আমরা চ্যাটবটে একটি CSV পার্সিং ফাংশন যোগ করব।

parse_csv ফাংশনটি ইমপ্লিমেন্ট করুন, যা একটি স্ট্রিং নিয়ে ফলস্বরূপ ফিল্ডগুলোর একটি অ্যারে রিটার্ন করে। ফিল্ড আলাদা করার নিয়ম হবে "কমা এবং তার পরে ঐচ্ছিক হোয়াইটস্পেস"।

CSV ফরম্যাটের কোনো এজ কেস নিয়ে আমরা মাথা ঘামাব না (যেমন কমা থাকা ফিল্ড)।

"first, second,third,   fourth" | parse_csv
# => ["first", "second", "third", "fourth"]
GitHub-এর মাধ্যমে সম্পাদনা করুন লিংকটি একটি নতুন উইন্ডো বা ট্যাবে খোলে
jq Exercism

রেগুলার চ্যাটবট শুরু করতে প্রস্তুত?

Exercism-এ সাইন আপ করুন, jq ট্র্যাকের 12টি কনসেপ্ট75টি অনুশীলনী আর সত্যিকারের মানুষের মেন্টরিং দিয়ে শিখুন ও দক্ষ হয়ে উঠুন, সম্পূর্ণ বিনামূল্যে।