1.3.11 · Coding › Python Intermediate
Intuition Is note ka 80/20
Ek regular expression (regex) ek choti si pattern language hai jo text ki shape describe karti hai — exact text nahi. Tum ek baar pattern likhte ho, aur regex engine kisi bhi string ko scan karke har woh jagah dhundhta hai jo us shape se match kare. Ye 5 verbs master karo aur tumhare paas ~80% real-world text work cover ho jaayega: search, match, findall, groups, sub.
Maan lo tumhe ek messy log file se har phone number, email, ya date nikalni hai. Haath se if/for/.split() chains likhna brittle hai: bahut saari variations hoti hain ("12-05-2024", "12/05/24", "Dec 5"). Ek regex tumhe ek compact string mein shapes ki family describe karne deta hai. Engine tumhare liye looping aur backtracking karta hai.
Mental model:
Tum ek pattern dete ho (ek shape ki description).
Engine ek cursor left→right move karta hai aur poochta hai "kya text yahan se shuru hokar meri shape se match karta hai?"
Woh matches report karta hai, optionally groups (captured sub-pieces) bhi nikalta hai.
Definition Core pattern atoms
==.== koi bhi single character match karta hai (newline chhod ke).
==\d== ek digit [0-9]; \w ek word char [A-Za-z0-9_]; \s whitespace.
==[abc]== ek character class — set mein se ek char; [^abc] = not woh wale.
Anchors : ==^ string ka start, $== string ka end.
Quantifiers : ==* 0+, + 1+, ?== 0 ya 1, {m,n} m aur n ke beech.
==( ... )== ek capturing group — yaad rakhta hai usne kya match kiya.
(?: ... ) ek non-capturing group (structure ke liye group, yaad nahi rakhta).
| alternation ("or"); \b ek word boundary.
* "any text" kyun lagta hai lekin hai nahi
Beginners * ko "kuch bhi yahan" padhte hain (jaise shell globbing mein *.txt). Fix: regex mein * ek quantifier hai — matlab hai "pichle atom ko 0+ baar repeat karo". Toh a* = zero-or-more as. "Kisi bhi character ka run" describe karne ke liye tumhe .* chahiye (any char, repeated).
==re.search(pat, s)== pehla match kahin bhi dhundhta hai, ek Match object return karta hai (ya None).
==re.match(pat, s)== sirf s ke start mein match karta hai.
==re.findall(pat, s)== saare matches ki ek list return karta hai strings mein (ya tuples agar groups hain).
==re.sub(pat, repl, s)== har match ko repl se replace karta hai, ek naya string return karta hai.
re.finditer(pat, s) findall jaisa lekin Match objects yield karta hai (positions bhi deta hai).
match vs search
re.match("dog", "the dog") None return karta hai! Kyun weird lagta hai: "the dog mein clearly dog hai." Fix: match sirf position 0 par anchored hai. Kahin bhi dhundhne ke liye ==search== use karo.
Python strings \ ko escape maante hain (\n = newline). Regex bhi \ use karta hai (\d, \b). Do layers lad rahi hain! Patterns ko raw strings r"\d+" ke roop mein likho taaki Python backslash ko unchanged regex engine tak pahuncha de.
"\d" vs r"\d"
Theek lagta hai kyunki "\d" aksar kaam karta hai (Python unknown escapes ko abhi chhod deta hai — yeh deprecated hai). Fix: patterns ke liye hamesha r"..." use karo taaki \b, \d, \w reliably behave karein.
Worked example 1 — Saare integers extract karo
import re
re.findall( r " \d + " , "order 12 of 345 items" ) # -> ['12', '345']
\d+ kyun? \d = ek digit, + = "ek ya zyada baar lagataar", toh consecutive digits '12' aur '345' mein clump ho jaate hain, '1','2',... mein nahi. + ke bina tumhe har single digit alag milti.
Worked example 2 — Groups ek date ko split karte hain
m = re.search( r " (\d {2} ) / (\d {2} ) / (\d {4} ) " , "born 05/12/2024 ok" )
m.group( 0 ) # '05/12/2024' (poora match)
m.group( 1 ) # '05' (pehla group)
m.groups() # ('05', '12', '2024')
Parentheses kyun? Har ( ) ek sub-piece ko capture karta hai taaki tum day/month/year alag se nikal sako. group(0) hamesha poora match hota hai; group(n) n-th captured group.
findall groups hone par tuples return karta hai
re.findall( r " (\w + ) @ (\w + ) " , "a@x b@y" ) # -> [('a','x'), ('b','y')]
Tuples kyun? Jab pattern mein 2+ groups hain, findall har match ko uske groups ke tuple ke roop mein return karta hai (poora match nahi). 0 groups ke saath woh poore matches return karta hai; 1 group ke saath sirf us group ka text.
sub backreference ke saath
re.sub( r " (\w + ) @ (\w + ) " , r " \2 . \1 " , "a@x" ) # -> 'x.a'
\1/\2 kyun? Replacement mein, \1 matlab "group 1 dwara captured text". Toh hum dono halves swap kar rahe hain. Aise tum matched text ko reformat karte ho.
Worked example 5 — Greedy vs lazy
re.findall( r " < . * > " , "<a><b>" ) # -> ['<a><b>'] greedy: jitna ho sake utna lega
re.findall( r " < . *? > " , "<a><b>" ) # -> ['<a>', '<b>'] lazy: jitna kam ho sake utna
Kyun? * greedy hai — yeh jitna right mein ho sake match karta hai, phir backtrack karta hai. Quantifier ke baad ? lagate hain toh woh lazy ho jaata hai (minimal match). Tags/quotes parse karne ke liye bahut zaroori hai.
Agar tum ek pattern kaafi baar use karte ho, ==re.compile== se ek baar pattern object mein compile karo: p = re.compile(r"\d+"), phir p.findall(s). Behaviour same hai, lekin pattern sirf ek baar parse hota hai — loops mein faster aur cleaner dikhta hai.
Recall Feynman: ek 12-saal ke bacche ko samjhao
Socho tumhare paas ek badi kitaab hai aur tum har phone number highlight karna chahte ho. Har line khud padhne ke bajaye, tum ek robot ko ek rule card dete ho: "woh chunk dhundho jo kuch digits, ek dash, aur kuch aur digits jaisa dikhta ho." Robot zoom karke har woh chunk highlight kar deta hai jo card se match kare. Regex woh rule card hai. ( ) matlab tum card par chhoti boxes bana rahe ho aur bol rahe ho "aur is box ke andar jo hai woh alag yaad rakhna." findall = "mujhe har highlight dikhao." sub = "har highlight ko is naye text se replace karo."
"SMFS-G" = S earch (kahin bhi), M atch (sirf start), F indall (list), S ub (replace), G roups (woh boxes).
Quantifiers ke liye: "Plus = Present (1+), Star = Sometimes (0+), Question = Quitable (0/1)."
Kuch match na hone par re.search kya return karta hai? None (toh .group call karne se pehle check karna zaroori hai).
re.match aur re.search mein kya fark hai?match sirf string ke start par check karta hai; search kahin bhi scan karta hai.
\d+ ka matlab kya hai?Lagataar ek ya zyada digits.
Patterns ke liye raw strings r"..." kyun use karte hain? Taaki Python backslash na khaaye; regex engine ko \d, \b etc. intact mile.
Jab pattern mein 2 capturing groups hों toh findall kya return karta hai? Tuples ki ek list, har match ke liye group strings ka ek tuple.
group(0) kya hai?Poora matched substring.
Quantifier ko lazy kaise banate hain? Uske baad ? lagao (jaise .*?), taaki woh jitne kam chars ho sake match kare.
re.sub mein replacement string mein \1 ka kya matlab hai?Group 1 dwara captured text (ek backreference).
Non-capturing group kya hai aur kyun use karte hain? (?:...) structure/alternation ke liye group karta hai bina use numbered group ke roop mein store kiye.
^ aur $ kya anchor karte hain?^ = string ka start, $ = string ka end.
re.match("dog","the dog") None kyun hai?match position 0 par anchored hai; "dog" start mein nahi hai.
re.compile se kya fayda hota hai?Pattern ko ek baar parse karke reusable object banata hai — loops mein faster.
String methods — split, join, format
Python Intermediate — File I/O and parsing logs
Finite State Machines (regex engines under the hood NFAs/DFAs hote hain)
Greedy vs Backtracking algorithms
Escape characters and raw strings
findall returns tuples via