Python-এ regular expression: ফাঁদসহ ব্যবহারিক গাইড
Regular expression লেখা খুঁজে নতুন রূপ দেয়। group, greedy বনাম lazy, বাংলাদেশি মোবাইল নম্বর যাচাই ও যে backtracking ফাঁদ server জমিয়ে দিতে পারে তা শিখুন।

Regular expression (regex) লেখার একটি pattern বর্ণনা করে, যাতে আপনি তা খুঁজতে, যাচাই করতে বা নতুন রূপ দিতে পারেন। log, সহজ validation ও পরিষ্কারের কাজে চমৎকার, আর যা এটি ভালো পারে না তাতে ভুল ব্যবহার সহজ। নিচের code ও output প্রকাশের আগে Python 3-এ চালানো।
মূল উপাদান
\dঅঙ্ক,\wঅক্ষর, অঙ্ক বা underscore,\sফাঁকা,.নতুন লাইন ছাড়া যেকোনো অক্ষর।+এক বা একাধিক,*শূন্য বা বেশি,?ঐচ্ছিক,{4}ঠিক চারটি।[A-Z]একটি সেটের অক্ষর,^শুরু,$শেষ।( ... )group,(?P<name> ... )named group।- pattern raw string-এ (
r"...") লিখুন, যাতে backslash regex engine-এ পৌঁছায়।
পরীক্ষিত ভ্রমণ
import re
log = "2026-10-29 ERROR payment failed order=1042 user=amina@example.com"
m = re.search(r"(?P<date>\d{4}-\d{2}-\d{2}) (?P<level>[A-Z]+) (?P<msg>.*?) order=(?P<order>\d+)", log)
print(m.groupdict())
print(re.findall(r"[\w.+-]+@[\w-]+\.[\w.]+", "mail amina@example.com or ravi@mail.test today"))
html = "<b>one</b> and <b>two</b>"
print("greedy:", re.findall(r"<b>.*</b>", html), "| lazy:", re.findall(r"<b>.*?</b>", html))
print(re.sub(r"(\d{4})-(\d{2})-(\d{2})", r"\3/\2/\1", "due 2026-11-03"))
phone = re.compile(r"^(?:\+?88)?01[3-9]\d{8}$")
print([bool(phone.match(x)) for x in ["01712345678", "+8801712345678", "8801712345678", "0171234567", "02112345678"]])
{'date': '2026-10-29', 'level': 'ERROR', 'msg': 'payment failed', 'order': '1042'}
['amina@example.com', 'ravi@mail.test']
greedy: ['<b>one</b> and <b>two</b>'] | lazy: ['<b>one</b>', '<b>two</b>']
due 03/11/2026
[True, True, True, False, False]
লক্ষ্য করুন:
- Named group log লাইনকে নামে পড়া যায় এমন dictionary বানায়।
- Greedy বনাম lazy।
.*যতটা পারে নেয় এবং দুটি bold ট্যাগই গিলেছে, আর.*?প্রথম</b>-এ থামে। re.subgroup আবার ব্যবহার করে (\3/\2/\1) তারিখের ক্রম বদলায়।- ফোন যাচাই
017...,+88017...ও88017...নেয় এবং অঙ্ক কম হলে বাদ দেয়। এটি বাংলাদেশের প্রচলিত মোবাইল ফরম্যাটের উদাহরণ, প্রতিটি বৈধ নম্বরের পূর্ণ নিয়ম নয়।
ফাঁদ: catastrophic backtracking
কিছু pattern প্রায়-মেলা input-এ সূচকীয় হারে বেশি সময় নেয়। এভাবে একটি request-ই server জমিয়ে দিতে পারে (ReDoS)।
import re, time
def run(pattern, n):
s = "a" * n + "b"
t = time.perf_counter(); re.match(pattern, s); return time.perf_counter() - t
for n in (20, 22, 24):
print(f"(a+)+$ on {n} a's then b: {run(r'(a+)+$', n):.3f} s | a+$: {run(r'a+$', n):.6f} s")
(a+)+$ on 20 a's then b: 0.031 s | a+$: 0.000057 s
(a+)+$ on 22 a's then b: 0.121 s | a+$: 0.000006 s
(a+)+$ on 24 a's then b: 0.473 s | a+$: 0.000008 s
nested quantifier (a+)+-এ দুটি অক্ষর বাড়ালে প্রায় চার গুণ সময় লেগেছে, অথচ নিরাপদ a+$ তাৎক্ষণিক। দীর্ঘ string-এ এটি মিনিটে গিয়ে ঠেকে।
নিরাপদ থাকবেন যেভাবে
(a+)+,(.*)*ও(a|aa)+-এর মতো nested quantifier এড়ান।- ব্যবহারকারীর লেখায় মেলানোর আগে input-এর দৈর্ঘ্যের সীমা দিন।
- যথেষ্ট হলে সহজ টুল পছন্দ করুন:
str.startswith,split,in, বা HTML ও JSON-এর জন্য আসল parser। - email-এ হালকা যাচাই করুন ও নিশ্চিতকরণ বার্তা পাঠান। regex প্রমাণ করতে পারে না একটি ঠিকানা কাজ করে।
- একটি pattern বহুবার ব্যবহার হলে
re.compileএকবার করুন।
সাধারণ ভুল
- HTML parse করতে regex ব্যবহার। parser ব্যবহার করুন।
- raw string prefix ভুলে ভুল করে backslash দ্বিগুণ করা।
re.searchচাওয়ার জায়গায়re.match(matchশুধু শুরু দেখে)।- anchor ভুলে যাওয়া, ফলে
\d{4}দীর্ঘ সংখ্যার ভেতরেও মেলে। - কাজ ভাগ করার বদলে একটি বিশাল pattern লেখা।
মূল কথা: named group ব্যবহার করুন, সবচেয়ে ছোট মিল চাইলে lazy quantifier নিন, pattern-এ anchor দিন, আর অবিশ্বস্ত input-এ nested quantifier-সহ pattern কখনও চালাবেন না।
Programming roadmaps সিরিজ, পর্ব ৩ (ভালো Python লেখা): 2 নম্বর (মোট 5)। আগের লেখা: Python virtual environment ও packaging: পরিষ্কার সেটআপ.


