DEV Community

Tejas Shinkar
Tejas Shinkar

Posted on

Exception Handling (`else`/`finally`, `raise`, Debugging Tools) + Regular Expressions (`re` module)

šŸ“Œ Key Concepts Overview

Concept One-Line Definition
try-except-else-finally The complete exception-handling block structure
else (in try block) Runs ONLY if no exception occurred in try
finally Always runs — exception or not — used for cleanup
sys.exc_info() Returns details about the exception currently being handled
traceback module Prints the full error traceback (where exactly it failed)
raise Manually triggers an exception
Regex (re module) Pattern matching/searching/extracting from text
Metacharacter Special symbol with reserved meaning in regex (., ^, $, [])
Quantifier Controls how many times a pattern repeats (*, +, ?, {n,m})

🧯 Part 1 — Exception Handling: Complete Structure

Nested try-except (Two Risky Operations)

try:                                    # outer suspicious code
    x = int(input('Enter a number: '))
    y = int(input('Enter a number: '))
    try:                                  # inner suspicious code
        c = x/y
        print(c)
    except:
        print('Division by zero not possible')
except:
    print('Incorrect input. Expecting an integer number only')
Enter fullscreen mode Exit fullscreen mode

This works, but nesting try blocks gets messy. Python gives a cleaner way: else.

else — Runs ONLY If try Succeeds (No Exception)

try:
    x = int(input('Enter a number: '))
    y = int(input('Enter a number: '))
except:
    print('Incorrect input. Expecting an integer number only')
else:                                     # only runs if try block had NO error
    try:
        c = x/y
        print(c)
    except:
        print('Division by zero not possible')
Enter fullscreen mode Exit fullscreen mode

Why else is better than just stuffing more code in try: It clearly separates "code that might fail" (in try) from "code that should only run if everything succeeded" (in else). Cleaner intent, easier to read.

lst = [73, 0, 6, 17, 0, 38, 10, 0, 47, 27]

try:
    print(10/lst[1])           # lst[1] = 0 → ZeroDivisionError
except:
    print('Exception caught')
else:
    print('If there is no exception caught, then this block gets executed')
print('Python')
# Output: 'Exception caught' then 'Python' — else block SKIPPED because an error occurred

try:
    print(10/lst[0])            # lst[0] = 73 → no error
except:
    print('Exception caught')
else:
    print('If there is no exception caught, then this block gets executed')
print('Python')
# Output: 3.65..., then 'If there is no exception...', then 'Python' — else block RUNS
Enter fullscreen mode Exit fullscreen mode

finally — Always Runs, No Matter What

lst = [73, 0, 6, 17, 0, 38, 10, 0, 47, 27]

try:
    print(10/lst[1])           # ZeroDivisionError
except:
    print('Exception caught')
else:
    print('If there is no exception caught, then this block gets executed')
finally:
    print('This block of code will always get executed')
# Output: Exception caught → This block of code will always get executed
# (else is SKIPPED because an error occurred, but finally ALWAYS runs)
Enter fullscreen mode Exit fullscreen mode

The Full Picture:

Block When it runs
try Always attempted first
except Only if try raises an error
else Only if try did NOT raise an error
finally ALWAYS — regardless of error or not

DevOps relevance for finally: Closing a network connection, releasing a file lock, or cleaning up a temp resource — things that MUST happen whether the operation succeeded or failed.


šŸ” Part 2 — Debugging Tools for Exceptions

sys.exc_info() — Get Details About the Current Exception

import sys

lst = [73, 0, 6, 17, 0, 38, 10, 0, 47, 27]
try:
    print(10/lst[1])
except:
    print(sys.exc_info())          # returns (exception_type, exception_value, traceback_object)
else:
    print('If there is no exception caught, then this block gets executed')
finally:
    print('This block of code will always get executed')

# Access individual parts:
print(sys.exc_info()[0])    # the exception TYPE, e.g. <class 'ZeroDivisionError'>
print(sys.exc_info()[1])    # the exception MESSAGE, e.g. division by zero
Enter fullscreen mode Exit fullscreen mode

traceback Module — Print Where Exactly It Failed

import traceback

lst = [73, 0, 6, 17, 0, 38, 10, 0, 47, 27]
try:
    print(10/0)
    print(lst[42])             # never reached — error happens above first
except:
    print(traceback.print_exc())     # prints the FULL traceback — file, line number, error type
else:
    print('If there is no exception caught, then this block gets executed')
finally:
    print('This block of code will always get executed')
Enter fullscreen mode Exit fullscreen mode

sys.exc_info() vs traceback.print_exc():

Tool Use case
except Exception as e: print(e) Quick, readable error message
sys.exc_info() Programmatic access to type/value/traceback object
traceback.print_exc() Full human-readable traceback — best for debugging logs
# The cleanest, most common production pattern:
try:
    x = int(input('Enter a number: '))
    y = int(input('Enter a number: '))
    print(x/y)
except Exception as e:
    print(e)             # simple, clear, catches everything with a readable message
Enter fullscreen mode Exit fullscreen mode

🚨 Part 3 — raise — Manually Triggering Exceptions

# raise keyword is used to raise a user-defined error
try:
    a = int(input('Enter your age: '))
    if a < 18:
        raise Exception                  # manually trigger an exception
    else:
        print('Driving license application accepted')
except:
    print('Age is less than 18. Not eligible for the DL')
Enter fullscreen mode Exit fullscreen mode

Why use raise instead of just an if-else with print()?

  • raise lets you enforce business rules as actual ERRORS — which propagate up, can be caught at a higher level, logged consistently, or stop execution entirely
  • Useful in larger systems where a function needs to signal "something is wrong" to whoever called it, not just print a message and continue
# Compare:
# Without raise — just a print, program flow continues normally
if a < 18:
    print('Age is less than 18')      # this is just informational

# With raise — flow JUMPS to except, treated as a real error
if a < 18:
    raise Exception                    # forces the except block to run
Enter fullscreen mode Exit fullscreen mode

DevOps relevance: Validating config values, environment variables, or API responses — raise lets you fail fast and loud instead of silently continuing with bad data.

# Practical DevOps example
def validate_port(port):
    if port < 1 or port > 65535:
        raise ValueError(f'Invalid port: {port}')
    return port

try:
    validate_port(99999)
except ValueError as e:
    print(e)
Enter fullscreen mode Exit fullscreen mode

ā˜ļø DevOps / Cloud Use Cases (Exception Handling)

# 1. Cleanup pattern with finally — close connections regardless of outcome
try:
    # connection = connect_to_db()
    print('Connected to DB')
    # risky_query()
except Exception as e:
    print(f'Query failed: {e}')
finally:
    print('Closing DB connection')      # ALWAYS runs — connection never left hanging

# 2. else for "only proceed if input was valid"
try:
    instance_count = int(input('How many instances to launch? '))
except ValueError:
    print('Must be a number')
else:
    if instance_count > 10:
        print('āš ļø Warning: launching more than 10 instances')
    print(f'Launching {instance_count} instances...')

# 3. raise for config validation — fail fast
def check_region(region):
    valid_regions = ['ap-south-1', 'us-east-1', 'eu-west-1']
    if region not in valid_regions:
        raise ValueError(f'{region} is not a supported region')
    return True

try:
    check_region('mars-central-1')
except ValueError as e:
    print(f'Config error: {e}')

# 4. traceback for production logging
import traceback
try:
    # deploy_to_server()
    1/0   # simulated failure
except Exception:
    error_log = traceback.format_exc()
    # write error_log to a log file for later debugging
    print('Deployment failed — error logged')
Enter fullscreen mode Exit fullscreen mode

āŒ Common Mistakes (Exception Handling)

Mistake Issue Fix
Putting everything in try, nothing in else Mixes "risky" code with "safe, dependent" code Use else for code that should only run on success
Forgetting finally for cleanup Resources (files, connections) may leak on error Use finally for guaranteed cleanup
Using print() instead of raise for real errors Program continues with bad data silently Use raise to stop and signal failure properly
Bare except: hides the real problem Hard to debug — don't know WHAT failed Use except Exception as e: print(e) minimum
Confusing sys.exc_info()[0] and [1] [0] = type, [1] = value/message Remember the order: (type, value, traceback)

šŸŽÆ Interview Points (Exception Handling)

  1. "What's the purpose of the else block in try-except?"
    → It runs only when the try block completes WITHOUT any exception — useful for code that depends on the try block succeeding, keeping it separate from the risky code itself.

  2. "What's the difference between else and finally?"
    → else runs only if NO exception occurred. finally runs ALWAYS — exception or not. finally is for guaranteed cleanup.

  3. "What does raise do?"
    → Manually triggers an exception, which can be caught by an except block — used to enforce validation rules or signal errors explicitly rather than silently continuing.

  4. "What does sys.exc_info() return?"
    → A tuple of (exception_type, exception_value, traceback_object) for the exception currently being handled.

  5. "Why use traceback.print_exc() over a simple print(e)?"
    → It shows the FULL traceback — exact file and line number where the error occurred — much more useful for debugging in logs than just the error message.


šŸ“š Knowledge Base — Quick Revision (Exception Handling)

# ── FULL TRY STRUCTURE ──────────────────────────────────────
try:
    risky_code()
except SpecificError:
    handle_specific()
except Exception as e:
    print(e)                  # catch-all with message
else:
    only_if_success()          # runs ONLY if no exception
finally:
    always_runs()                # runs NO MATTER WHAT

# ── DEBUGGING TOOLS ─────────────────────────────────────────
import sys
sys.exc_info()           # (type, value, traceback)
sys.exc_info()[0]         # exception type
sys.exc_info()[1]          # exception message/value

import traceback
traceback.print_exc()      # full traceback, prints directly
traceback.format_exc()      # full traceback, returns as string (for logging)

# ── RAISE ────────────────────────────────────────────────────
if condition:
    raise Exception           # generic
    raise ValueError('msg')    # specific, with message
Enter fullscreen mode Exit fullscreen mode

šŸ”Ž Part 4 — Regular Expressions (re module)

What Is Regex?

A pattern-matching language used to find, validate, extract, or replace specific patterns in text. In Python, accessed via import re.

DevOps relevance: Parsing log files, validating IP addresses/emails/ports, extracting fields from unstructured text (logs, config files, API responses), sed/grep-style operations but in Python.

The 4 Components of Regex

1. Functions          — match(), search(), findall(), finditer()
2. Metacharacters      — . ^ $ [] | ()
3. Special Sequences   — \w \W \s \S \d \D \b \B
4. Quantifiers         — ? * + {n} {n,m}
Enter fullscreen mode Exit fullscreen mode

šŸ”§ Regex Functions

re.match() — Match ONLY at the Beginning of the String

import re

text = 'India is my country. I love India very much'
pattern = r'India'
res = re.match(pattern, text)
print(res)              # <re.Match object; span=(0, 5), match='India'>

pattern = r'In'
res = re.match(pattern, text)
print(res)               # matches — 'In' is still at the start

pattern = r'love'              # NOT at the beginning
res = re.match(pattern, text)
print(res)                      # None — match() ONLY checks position 0
Enter fullscreen mode Exit fullscreen mode

Get the actual matched text:

res = re.match(r'India ', text)
print(res.group())         # 'India ' — the matched string itself
Enter fullscreen mode Exit fullscreen mode

re.search() — Find the FIRST Occurrence ANYWHERE

text = 'India is my country. I love India very much'
pattern = r'India'
res = re.search(pattern, text)
print(res)                  # finds it — anywhere in the string, not just the start

text2 = 'india is my country. I love India very much'   # lowercase first 'india'
pattern = r'India'
res = re.search(pattern, text2)
print(res)                   # finds the SECOND 'India' (capital I) — case-sensitive!
Enter fullscreen mode Exit fullscreen mode

Match Object Attributes

text = 'india is my country. I love India very much'
pattern = r'India'
res = re.search(pattern, text)

print(res.group())     # the matched text itself: 'India'
print(res.span())       # (start, end) tuple — e.g. (29, 34)
print(res.start())       # just the start index: 29
print(res.end())          # just the end index: 34 (exclusive)
Enter fullscreen mode Exit fullscreen mode

re.findall() — ALL Occurrences as a LIST of Strings

text = 'India is my country. I love India very much'
pattern = r'India'
res = re.findall(pattern, text)
print(res, type(res))      # ['India', 'India'] <class 'list'>

pattern = r'india'          # lowercase — won't match capital 'India'
res = re.findall(pattern, text)
print(res)                   # [] — empty list, case-sensitive, no match
Enter fullscreen mode Exit fullscreen mode

re.finditer() — ALL Occurrences as MATCH OBJECTS (Iterator)

text = 'We are learning Python. This is Python class. Python is very interesting.'
pattern = r'Python'
res = re.finditer(pattern, text)
for i in res:
    print(i)              # full match object
    print(i.group())       # just the matched text
    print(i.span())         # (start, end) for EACH occurrence
Enter fullscreen mode Exit fullscreen mode

findall() vs finditer() — Key Difference:

Function Returns Gives you span()/start()/end()?
findall() List of plain strings āŒ No — just the text
finditer() Iterator of match objects āœ… Yes — full details per match

šŸ”£ Metacharacters

[] — Character Set

text = 'chcwasj393e*&#^(@babeidbisadjeiesna'

re.finditer(r'a', text)        # matches literal 'a' wherever it appears
re.finditer(r'[a]', text)       # same as above, set with ONE character

re.finditer(r'[acw]', text)      # matches a OR c OR w — each one individually
re.finditer(r'[1234]', text)      # matches any digit 1, 2, 3, or 4

re.finditer(r'[a-z]', text)        # matches any lowercase letter a through z
re.finditer(r'[A-J]', text)         # matches any uppercase letter A through J
re.finditer(r'[0-9]', text)          # matches any digit
re.finditer(r'[A-Za-z0-9]', text)     # matches any alphanumeric character

re.finditer(r'[^K]', text)             # ^ INSIDE [] means NOT — matches everything EXCEPT 'K'
re.finditer(r'[^A-Z]', text)            # matches everything EXCEPT uppercase letters
Enter fullscreen mode Exit fullscreen mode

āš ļø ^ means two DIFFERENT things depending on context:

Position Meaning
r'^India' (outside []) Match at the BEGINNING of the string
r'[^A]' (inside []) Match anything EXCEPT 'A' (negation)

^ — Anchor to Start of String

text = 'India is my country. I love India'
pattern = r'^India'
res = re.finditer(pattern, text)
for i in res:
    print(i.group(), i.span())
# Only matches the FIRST 'India' — because it's at position 0
Enter fullscreen mode Exit fullscreen mode

$ — Anchor to End of String

text = 'This is Python class. Today is Saturday'
pattern = r'Saturday$'
res = re.finditer(pattern, text)
for i in res:
    print(i.group(), i.span())
# Matches only if 'Saturday' is the VERY LAST thing in the string

text2 = 'This is Python class. We have class on Saturday and Sunday. Today is Saturday'
pattern = r'Saturday$'
# Only matches the LAST 'Saturday' (the one at the true end) — not the earlier one
Enter fullscreen mode Exit fullscreen mode

. (Dot) — Matches ANY Character Except Newline

text = 'This is Python\n class.'
pattern = r'.'
res = re.finditer(pattern, text)
# Matches every character EXCEPT the \n (newline is skipped)

pattern = r's.'                     # 's' followed by ANY character
text = 'This is\n Python\n class.'
res = re.finditer(pattern, text)
# Matches 's' + next char, e.g., 'si', 'ss' — but won't match 's' followed by \n
Enter fullscreen mode Exit fullscreen mode

To match a LITERAL dot (not "any character"), escape it with \:

text = 'This. is P.ytho.n\n cla.ss.'
pattern = r'[.]'             # inside [] — . is treated literally
res = re.finditer(pattern, text)
# matches every actual '.' character

pattern = r'\.'                # backslash escape — also treats . literally
res = re.finditer(pattern, text)
# same result as [.] above
Enter fullscreen mode Exit fullscreen mode

Escaping Other Special Characters

text = '$**^*&GGIUGB jd^ibsji&&)71625 nce^i7 bhi 1.03 83.383 hdj'

re.finditer(r'\^', text)     # matches literal '^' character
re.finditer(r'\$', text)      # matches literal '$' character
re.finditer(r'\.', text)       # matches literal '.' character
Enter fullscreen mode Exit fullscreen mode

Rule: Any metacharacter (., ^, $, [, ], etc.) needs a \ before it to be treated as a literal character instead of a special instruction.


šŸ”¤ Special Sequences

# \w — matches alphanumeric characters (A-Z, a-z, 0-9, _)
# \W — matches everything EXCEPT alphanumeric (opposite of \w)

# \s — matches whitespace characters ( , \t, \v, \n, \r)
# \S — matches everything EXCEPT whitespace (opposite of \s)

# \d — matches digits (0-9)
# \D — matches everything EXCEPT digits (opposite of \d)

# \b — matches a WORD BOUNDARY (edge of a word)
# \B — matches everything EXCEPT a word boundary
Enter fullscreen mode Exit fullscreen mode
text = 'ndhAe82JE 7yt2vj*&(*^*&$*tvhDNDdviuy7t7BDH er8732ubj _ hdude7_ hj83798Y^&^bjno'

re.finditer(r'\w', text)     # every letter, digit, underscore
re.finditer(r'\W', text)      # every symbol/space — opposite of \w

re.finditer(r'\s', text)       # spaces, tabs, newlines, etc.
re.finditer(r'\S', text)        # everything that ISN'T whitespace

re.finditer(r'\d', text)         # every digit 0-9
re.finditer(r'\D', text)          # everything that ISN'T a digit
Enter fullscreen mode Exit fullscreen mode

Carriage Return \r and Vertical Tab \v

print('python\rHello')      # \r moves cursor to START of line — 'Hello' overwrites 'python'
                              # Output appears as: Hello (overwrites visually in terminal)
print('python\vHello')        # \v vertical tab — moves down a line, keeps horizontal position
Enter fullscreen mode Exit fullscreen mode

\b — Word Boundary

text = 'catherine bought a cat and named him Tomcat. The cat loves catherine'

pattern = r'\bcat'        # matches 'cat' ONLY at the start of a word
res = re.finditer(pattern, text)
# Matches: 'cat' (standalone), 'cat' (in 'cat'), but NOT the 'cat' inside 'Tomcat' (mid-word)
# catherine ALSO matches because 'cat' is at the start of that word too!

pattern = r'\Bcat'         # matches 'cat' ONLY when NOT at a word boundary (mid-word)
res = re.finditer(pattern, text)
# Matches the 'cat' INSIDE 'Tomcat' only

pattern = r'\bcat\b'        # 'cat' as a COMPLETE, standalone word only
res = re.finditer(pattern, text)
# Matches ONLY the standalone word 'cat' — not 'catherine', not 'Tomcat'
Enter fullscreen mode Exit fullscreen mode

This is the key pattern for "find the exact word, not a substring of a longer word."


šŸ”— | — OR Operator

text = 'xyz.com abc.net xyz@gmail.com xyz.in abc.com abc.gov'
pattern = 'com|gov|in'           # matches 'com' OR 'gov' OR 'in' — wherever found
res = re.finditer(pattern, text)
for i in res:
    print(i)
Enter fullscreen mode Exit fullscreen mode

() — Groups (Combine Multiple Patterns)

# Match abc.com, abc.gov, abc.in, abc.net, xyz.com, xyz.gov, xyz.in, xyz.net
text = 'xyz.com abc.net xyz@gmail.com xyz.in abc.com abc.gov'
pattern = '(abc|xyz)(.com|.gov|.in|.net)'
res = re.finditer(pattern, text)
for i in res:
    print(i)

# Match hat, cat, rat, bat, mat — two equivalent approaches:
text = 'hat matrbsi jbatsiucatvs ratvdibat mat hat'

# Approach 1 — character set
pattern = r'[A-Za-z]at'
# matches ANY single letter + 'at'

# Approach 2 — explicit group of options
pattern = r'(h|r|m|b)at'
# matches EXACTLY h, r, m, or b + 'at' — more precise/restrictive
Enter fullscreen mode Exit fullscreen mode

šŸ”¢ Quantifiers

# {3}     — exactly 3 repetitions
# {3,5}   — minimum 3, maximum 5 repetitions
# ?       — 0 or 1 repetition (optional)
# *       — 0 or MORE repetitions
# +       — 1 or MORE repetitions
Enter fullscreen mode Exit fullscreen mode
text = 'hat hdb726 87tVmatrb1si jbae3tsiu4catvs&^%80ratvdiba3tbjsbihmat bhjbdb hat'

re.finditer(r'[0-9]', text)         # every SINGLE digit, one at a time

re.finditer(r'[0-9]{2}', text)       # groups of EXACTLY 2 consecutive digits
re.finditer(r'[0-9]{3}', text)        # groups of EXACTLY 3 consecutive digits

text2 = 'hat hdb726 7363 373773 8378733 8376t3 6333b77 93 873 8373777 3638273636763'
re.finditer(r'[0-9]{3,5}', text2)      # groups of 3 to 5 consecutive digits

# ? — 0 or 1
text3 = 'bavcsabcxsa'
re.finditer(r'a?', text3)              # matches 'a' if present, or empty string otherwise

# * — 0 or more
text4 = 'bavcsaaabcxsa'
re.finditer(r'a*', text4)                # matches runs of 'a's of ANY length (including zero)

# + — 1 or more
re.finditer(r'a+', text4)                 # matches runs of 'a's — but only where at least ONE exists
Enter fullscreen mode Exit fullscreen mode

? vs * vs + — Quick Comparison:

Quantifier Min Max Example match on 'aaa'
? 0 1 'a' (just one, or none)
* 0 āˆž 'aaa' (the whole run, or empty)
+ 1 āˆž 'aaa' (the whole run, requires ≄1)

ā˜ļø DevOps / Cloud Use Cases (Regex)

import re

# 1. Validate an IP address pattern (basic)
text = 'Server connected from 192.168.1.105 on port 8080'
pattern = r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
ip = re.search(pattern, text)
print(ip.group())          # '192.168.1.105'

# 2. Extract all ERROR lines from a log
log = 'INFO: started\nERROR: disk full\nINFO: retry\nERROR: connection lost'
errors = re.findall(r'ERROR:.*', log)
print(errors)               # ['ERROR: disk full', 'ERROR: connection lost']

# 3. Extract port numbers from config text
config_text = 'app_port=8080, db_port=5432, cache_port=6379'
ports = re.findall(r'\d+', config_text)
print(ports)                 # ['8080', '5432', '6379']

# 4. Validate email format (basic pattern)
email = 'devops.engineer@company.com'
pattern = r'^[\w.]+@[\w]+\.[a-z]+$'
match = re.match(pattern, email)
print('Valid email' if match else 'Invalid email')

# 5. Extract resource names matching naming convention (env-service-number)
text = 'Resources: prod-web-01, staging-db-02, prod-cache-03'
pattern = r'\w+-\w+-\d{2}'
resources = re.findall(pattern, text)
print(resources)              # ['prod-web-01', 'staging-db-02', 'prod-cache-03']

# 6. Find lines starting with a timestamp pattern in logs
log_line = '2026-06-21 14:32:01 ERROR Connection timeout'
pattern = r'^\d{4}-\d{2}-\d{2}'
ts = re.match(pattern, log_line)
print(ts.group() if ts else 'No timestamp found')   # '2026-06-21'
Enter fullscreen mode Exit fullscreen mode

āŒ Common Mistakes (Regex)

Mistake Issue Fix
Using match() expecting full-string search match() only checks from position 0 Use search() to find anywhere in the string
Forgetting case sensitivity 'India' ≠ 'india' in default regex Use re.IGNORECASE flag if needed
Treating . as a literal dot . matches ANY character, not just . Escape with \. or use [.]
Confusing ^ inside vs outside [] Outside = "start of string"; inside = "NOT" Context matters — memorize both meanings
Forgetting r'' raw string prefix Backslash sequences may be misinterpreted Always use r'pattern' for regex
Using findall() when you need position info findall() gives only strings, no span Use finditer() for match objects with span/start/end
\b vs \B mix-up \b = word boundary, \B = NOT a word boundary \bcat\b for exact word; \Bcat for mid-word matches

šŸŽÆ Interview Points (Regex)

  1. "Difference between re.match() and re.search()?"
    → match() only checks for a match at the very beginning of the string. search() scans the entire string and returns the first match found anywhere.

  2. "Difference between findall() and finditer()?"
    → findall() returns a list of matched strings. finditer() returns an iterator of match objects, which gives access to span(), start(), end() for each match.

  3. "What does . mean in regex, and how do you match a literal dot?"
    → . matches any character except a newline. To match a literal ., escape it as \. or place it inside a character set [.].

  4. "What's the difference between \b and \B?"
    → \b matches a word boundary (start/end of a word). \B matches everywhere that is NOT a word boundary — useful for finding patterns strictly inside a word.

  5. "Difference between *, +, and ? quantifiers?"
    → * = 0 or more, + = 1 or more (requires at least one), ? = 0 or 1 (optional, single occurrence).

  6. "Why use raw strings (r'...') for regex patterns?"
    → To prevent Python from interpreting backslash sequences (like \n, \b) as escape characters before the regex engine sees them — ensures the pattern is passed through literally.


šŸ“š Knowledge Base — Quick Revision (Regex)

import re

# ── FUNCTIONS ────────────────────────────────────────────────
re.match(pattern, text)        # only checks the START of string
re.search(pattern, text)        # first match ANYWHERE
re.findall(pattern, text)        # ALL matches → list of strings
re.finditer(pattern, text)        # ALL matches → iterator of match objects

# match object attributes
match.group()        # matched text
match.span()           # (start, end) tuple
match.start()            # start index
match.end()                # end index

# ── METACHARACTERS ──────────────────────────────────────────
.        # any character except \n
^        # start of string (outside []) / NOT (inside [])
$        # end of string
[]       # character set, e.g. [a-z], [0-9], [A-Za-z0-9]
[^...]   # NOT these characters
|        # OR
()       # grouping

# ── SPECIAL SEQUENCES ───────────────────────────────────────
\w  \W     # word char / NOT word char
\s  \S     # whitespace / NOT whitespace
\d  \D     # digit / NOT digit
\b  \B     # word boundary / NOT word boundary

# ── QUANTIFIERS ─────────────────────────────────────────────
{n}        # exactly n
{n,m}      # between n and m
?          # 0 or 1
*          # 0 or more
+          # 1 or more

# ── ALWAYS USE RAW STRINGS ──────────────────────────────────
pattern = r'\d+'     # āœ… raw string for regex patterns
Enter fullscreen mode Exit fullscreen mode

šŸ‹ļø Practice Questions

Easy

  1. Write a try-except-else-finally block that asks for two numbers, divides them, and demonstrates all 4 blocks running (success case) — print a distinct message in each.
  2. Use re.findall() to extract all digits from the string: 'Server-01 has 8 CPUs and 32 GB RAM, port 8080'.
  3. Write a regex pattern using \b to find the standalone word 'log' in the text: 'log file blogger logger log' (should match only the exact word 'log', not 'blogger' or 'logger').

Medium

  1. Write a function safe_divide(a, b) that uses raise ValueError if b is zero, instead of letting Python's natural ZeroDivisionError happen. Catch it with a try-except and print a custom message.
  2. Given a log string with multiple lines, use re.findall() with the pattern r'ERROR:.*' to extract all error messages. Then use finditer() on the same pattern to also print the span() of each match.
  3. Write a regex pattern that extracts all valid AWS-style resource tags in this format: env-service-number (e.g., prod-web-01) from a string containing mixed text.

DevOps-Focused

  1. Robust Deployment Function: Write a function deploy(version) that:
    • Uses try to attempt the "deployment" (simulate with 1/int(version))
    • Uses except to catch and print errors
    • Uses else to print "Deployment successful" only if no error occurred
    • Uses finally to always print "Deployment process finished"

Test it with deploy(2) and deploy(0).

  1. Log Parser with Regex: Given this log data:
   log_data = '''2026-06-20 10:15:32 INFO Service started
   2026-06-20 10:16:45 ERROR Connection refused on port 5432
   2026-06-20 10:17:02 WARN High memory usage 85%
   2026-06-20 10:18:10 ERROR Disk space critical'''
Enter fullscreen mode Exit fullscreen mode

Use regex to: (a) extract all timestamps using pattern r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}', (b) extract all ERROR messages using r'ERROR.*', (c) count total ERROR occurrences using len() on the findall() result.


Top comments (0)