কম্পিউটার টিউটোরিয়াল

পাইথনে রেগুলার এক্সপ্রেশন (Regex) দিয়ে প্যাটার্ন ম্যাচিং


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

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

প্রতিটি পাইথন ইনস্টলেশনের সাথে আসা "re" মডিউল রেগুলার এক্সপ্রেশন সাপোর্ট প্রদান করে।

পাইথনে রেগুলার এক্সপ্রেশন সার্চ সাধারণত এভাবে লেখা হয়:

match = re.search(pattern, string)

re.search() মেথড দুটি আর্গুমেন্ট নেয়: একটি রেগুলার এক্সপ্রেশন প্যাটার্ন এবং একটি স্ট্রিং, এবং স্ট্রিংয়ের ভেতর সেই প্যাটার্নটি খুঁজে বের করে। যদি প্যাটার্নটি স্ট্রিংয়ের মধ্যে পাওয়া যায়, তবে search() একটি ম্যাচ অবজেক্ট ফেরত দেয়, অন্যথায় None। সুতরাং, একটি রেগুলার এক্সপ্রেশনে, একটি স্ট্রিং দেওয়া থাকলে, নির্ধারণ করা হয় সেটি দেওয়া প্যাটার্নের সাথে মেলে কিনা, এবং ঐচ্ছিকভাবে প্রাসঙ্গিক তথ্য ধারণকারী সাবস্ট্রিংগুলো সংগ্রহ করা হয়। রেগুলার এক্সপ্রেশন দিয়ে নিচের প্রশ্নগুলোর উত্তর পাওয়া যায়:

  • এই স্ট্রিংটি কি একটি বৈধ URL?

  • /etc/passwd-এ কোন ইউজাররা কোন গ্রুপে আছে?

  • লগ ফাইলে সকল ওয়ার্নিং মেসেজের তারিখ ও সময় কী?

  • ভিজিটর যেভাবে URL টাইপ করেছে, তার 의해 কী ইউজারনেম এবং ডকুমেন্ট রিকোয়েস্ট করা হয়েছে?

প্যাটার্ন ম্যাচিং

রেগুলার এক্সপ্রেশনগুলো জটিল মিনি-ল্যাঙ্গুয়েজ। এগুলো অজানা স্ট্রিং ম্যাচ করার জন্য স্পেশাল ক্যারেক্টারগুলোর উপর নির্ভর করে, কিন্তু আসুন লিটারেল ক্যারেক্টার দিয়ে শুরু করি, যেমন অক্ষর, সংখ্যা এবং স্পেস ক্যারেক্টার, যারা সবসময় নিজেদের সাথে ম্যাচ করে। একটি বেসিক উদাহরণ দেখি:

# রেগুলার এক্সপ্রেশনের জন্য 're' মডিউল দরকার
import re

search_string = "TutorialsPoint"
pattern = "Tutorials"
match = re.match(pattern, search_string)

# search() সফল হয় কিনা তা টেস্ট করার জন্য if-স্টেটমেন্ট
if match:
    print("regex matches: ", match.group())
else:
    print('pattern not found')

ফলাফল

regex matches: Tutorials

একটি স্ট্রিং ম্যাচ করা

পাইথনের "re" মডিউলের অনেক মেথড আছে, এবং কোন নির্দিষ্ট রেগুলার এক্সপ্রেশন নির্দিষ্ট স্ট্রিংয়ের সাথে মেলে কিনা টেস্ট করতে re.search() ব্যবহার করতে পারেন। re.MatchObject অডিশনাল ইনফোর্মেশন প্রদান করে, যেমন স্ট্রিংয়ের কোন অংশে ম্যাচটি পাওয়া গেল।

সিনট্যাক্স

matchObject = re.search(pattern, input_string, flags=0)

উদাহরণ

import re

# একটি ডেট স্ট্রিং ম্যাচ করার জন্য রেগুলার এক্সপ্রেশন ব্যবহার
regex = r"([a-zA-Z]+) (\d+)"
if re.search(regex, "Jan 2"):
    match = re.search(regex, "Jan 2")
    # এটি [0, 5) প্রিন্ট করবে, কারণ এটি শুরু এবং শেষে ম্যাচ করেছে
    print("Match at index %s, %s" % (match.start(), match.end()))
    # গ্রুপগুলো ম্যাচ করা মানগুলো ধারণ করে। বিশেষভাবে:
    # match.group(0) সবসময় পুরো ম্যাচ করা স্ট্রিং ফেরত দেয়
    # match.group(1), match.group(2), ... ইনপুট স্ট্রিংয়ের বাম থেকে ডানে ক্রম অনুযায়ী ক্যাপচার গ্রুপগুলো ফেরত দেয়
    # match.group() match.group(0)-এর সমতুল্য
    print("Full match: %s" % (match.group(0)))
    print("Month: %s" % (match.group(1)))
    print("Day: %s" % (match.group(2)))
else:
    print("Pattern not Found!")

ফলাফল

Match at index 0, 5
Full match: Jan 2
Month: Jan
Day: 2

উপরের মেথড প্রথম ম্যাচ পাওয়ার পর থামে, তাই এটি রেগুলার এক্সপ্রেশন টেস্ট করার জন্য বেশি উপযুক্ত, ডেটা এক্সট্র্যাক্ট করার জন্য কম।

ক্যাপচারিং গ্রুপস

যদি প্যাটার্নে দুটি বা তার বেশি প্যারেনথেসিস থাকে, তবে ফলাফলটি একটি লিস্টের বদলে টাপল হবে, প্যারেনথেসিস () গ্রুপ মেকানিজম এবং findall() সাহায্যে। প্রতিটি ম্যাচ করা প্যাটার্ন একটি টাপল দ্বারা রিপ্রেজেন্ট করা হয় এবং প্রতিটি টাপলে group(1), group(2)... ডেটা থাকে।

import re
regex = r'([\w\.-]+)@([\w\.-]+)'
str = ('hello john@hotmail.com, hello@Tutorialspoint.com, hello python@gmail.com')
matches = re.findall(regex, str)
print(matches)
for tuple in matches:
    print("Username: ", tuple[0])  # username
    print("Host: ", tuple[1])      # host

ফলাফল

[('john', 'hotmail.com'), ('hello', 'Tutorialspoint.com'), ('python', 'gmail.com')]
Username: john
Host: hotmail.com
Username: hello
Host: Tutorialspoint.com
Username: python
Host: gmail.com

স্ট্রিং খুঁজে বের করা এবং রিপ্লেস করা

দেওয়া স্ট্রিংয়ে প্যাটার্নের সকল ইনস্ট্যান্স খুঁজে বের করে সেগুলো রিপ্লেস করা একটি সাধারণ কাজ, re.sub(pattern, replacement, string) এটি সঠিকভাবে করে। উদাহরণস্বরূপ, পুরনো ইমেইল ডোমেনের সকল ইনস্ট্যান্স রিপ্লেস করতে:

কোড

import re

# দেওয়া স্ট্রিং
str = ('hello john@hotmail.com, hello@Tutorialspoint.com, hello python@gmail.com, Hello World!')

# ম্যাচ করার প্যাটার্ন
pattern = r'([\w\.-]+)@([\w\.-]+)'

# ম্যাচ করা প্যাটার্নকে স্ট্রিংয় থেকে রিপ্লেস করুন
replace = r'\1@XYZ.com'
# re.sub(pat, replacement, str) -- সব রিপ্লেসমেন্টসহ নতুন স্ট্রিং ফেরত দেয়
# \1 হলো group(1), \2 হলো group(2) রিপ্লেসমেন্টে
print(re.sub(pattern, replace, str))

ফলাফল

hello john@XYZ.com, hello@XYZ.com, hello python@XYZ.com, Hello World!

Re অপশন ফ্ল্যাগস

পাইথন রেগুলার এক্সপ্রেশনে উপরের মত ভিন্ন অপশন ব্যবহার করে প্যাটার্ন ম্যাচের আচরণ পরিবর্তন করা যায়। এই এক্সট্রা আর্গুমেন্টস, অপশনাল ফ্ল্যাগ, search() বা findall() ইত্যাদি ফাংশনে যোগ করা হয়, যেমন re.search(pattern, string, re.IGNORECASE)।

  • IGNORECASE - প্যাটার্নকে কেস-ইনসেনসিটিভ করে (upper/lowercase), তাই 'a' এবং 'A' উভয় ম্যাচ করে।

  • DOTALL - re.DOTALL ডট (.) মেটাক্যারেক্টারকে নিউলাইন (\n) সহ সব ক্যারেক্টার ম্যাচ করতে দেয়।

  • MULTILINE - re.MULTILINE স্ট্রিংয়ের প্রতিটি লাইনের শুরু (^) এবং শেষ ($) ম্যাচ করতে দেয়। সাধারণত ^ এবং $ পুরো স্ট্রিংয়ের শুরু এবং শেষ ম্যাচ করে।


  1. পাইথনে প্যাটার্ন প্রিন্ট করার পদ্ধতি

  2. পাইথনে ফাইলোট্যাক্সিস (Phyllotaxis) প্যাটার্ন তৈরি করুন

  3. পাইথন রেগেক্সে রিপিটিশনের পর নির্দিষ্ট ক্যারেক্টার ম্যাচ না করার পদ্ধতি (নেগেটিভ লুকআহেড)

  4. পাইথনে মাল্টিলাইন স্ট্রিং-এ প্যাটার্ন ম্যাচ করার পদ্ধতি (re.DOTALL)