Concepts / Loops and Conditionals in Python

Loops and Conditionals in Python

A grep simulator reads a file line by line, tests each line against a user-supplied regular expression, and counts how many lines match the pattern.

  • Programming

From grep to a Python loop

The Unix grep command can be understood as a small sequence of programming actions: receive a pattern, open a file, inspect each line, decide whether the line matches, count successful matches, and report the final count. A Python grep simulator is useful because it makes the loop and conditional decision visible. The loop visits every line, while the conditional determines whether the counter changes.

The counter belongs before the loop because it represents the total collected across all iterations.

The execution flow

The simulator follows one repeating path. It obtains a line from the file, tests that line against the user-supplied regular expression, and then takes one of two branches. If the pattern matches, the counter increases by one. If it does not match, the counter remains unchanged. After the loop has processed the final line, the program reports the counter.

readtest patternmatchno match: continuenext iterationloop endsFilenext lineCurrent linetextRegex testmatch?Match countincrease on matchFinal reportafter loop
How does each line move from the file through the regular-expression test and then update the match count?

A five-line trace

Counting lines that start with X

Trace a search for the pattern ^X through five file lines.

Before iteration: The counter starts at 0.

Author: John: The line does not match ^X, so the counter stays 0.

X-Priority: 1: The line matches ^X, so the counter becomes 1.

Subject: Meeting: The line does not match ^X, so the counter stays 1.

X-Mailer: Outlook: The line matches ^X, so the counter becomes 2.

Date: Monday: The line does not match ^X, so the counter stays 2.

After iteration: The loop ends after all five lines have been tested.

Two lines match ^X.

iteration 1iteration 2iteration 3iteration 4iteration 5Startcount 0Author: Johnno match; count 0X-Priority: 1match; count 1Subject: Meetingno match; count 1X-Mailer: Outlookmatch; count 2Date: Mondayno match; count 2
What are the current line, match result, and count after each iteration through the file?

Building the simulator

The implementation mirrors the trace. The pattern and filename are supplied by the user. The file is opened, the counter is initialized before iteration begins, and each line is tested inside the loop. The counter is reported only after the loop has finished.

import re pattern = input("Pattern: ") filename = input("Filename: ") count = 0 with open(filename) as file: for line in file: line = line.strip() if re.search(pattern, line): count += 1 print(count)

testyesnocontinuecontinueCurrent lineafter stripRegex testmatch?count + 1matchCurrent countno matchNext linecontinue loop
What happens next when the regular expression matches the current line versus when it does not?

Tracing before debugging

When a count looks wrong, trace the execution state instead of looking only at the final number. For every iteration, record the current line, whether the regular expression matches, and the counter after the conditional. This exposes whether the loop is visiting the expected lines and whether the counter changes only on matches.

Trace questionWhat to inspect
Which input is being tested?The current line from the file
What decision was made?Whether the line matches the supplied pattern
What changed?The counter increases only after a match
When is the result reported?After the loop ends

A compact checklist for tracing one iteration at a time

Mistakes in line matching

  • Initializing the counter inside the loop

    Earlier matches are discarded on every iteration.

    Fix: Initialize the counter before the loop so it can accumulate matches across the entire file.

  • Forgetting to strip the newline character

    The text being tested is not exactly the visible line content.

    Fix: Strip each line before applying the regular expression.

  • Using re.match() instead of re.search()

    The source identifies this as a common mistake when implementing the simulator.

    Fix: Use re.search for the line test in this grep-style program.

  • Reporting the count inside the loop

    The reported value is not yet the total for the file.

    Fix: Report the count after the loop ends.

  • Testing only the first few lines

    Matches later in the file are never included.

    Fix: Allow the file iteration to test every line.

Correct structureMistaken structure
Counter before the loopCounter reset inside the loop
Test the current lineTest the wrong input
Count only after a matchChange the count on every iteration
Report after all linesReport before iteration is complete

Patterns beyond a prefix

The same loop can search for more complex line formats. Instead of looking only for lines beginning with X, the pattern can describe a structure such as a line containing New Revision: followed by a number. The loop, conditional, counter, and final report remain the same; only the supplied regular expression changes.

MEDIUM

Write or adapt the simulator so that it searches a file for lines matching a pattern describing New Revision: followed by a number. Then trace at least three iterations by recording the current line, match result, and counter.

Hints
  • Keep the counter initialization before the loop.
  • Apply the pattern to every line, not just the first few.
  • Check the counter after each conditional decision.
  • Report the final count only after the loop ends.

What do you think happens?

A five-line file contains two lines beginning with X. If the counter starts at 0 and increases only when the pattern ^X matches, what should the final count be?

  • 0
  • 1
  • 2
  • 5
Reveal answer

Answer: 2

The source trace shows two matching lines: X-Priority: 1 and X-Mailer: Outlook. The other three lines leave the counter unchanged.

The complete mental model

  1. A grep simulator reads a file line by line and tests every line against a user-supplied regular expression.
  2. Initialize the match counter before the loop.
  3. Use the conditional to increment the counter only when the current line matches.
  4. Strip each line before testing it and use re.search rather than re.match for the simulator described here.
  5. Trace the current line, match result, and counter to debug the program.

Key Takeaways

  • The program's loop processes every file line, and its conditional decides whether that line contributes to the count.
  • The counter must be initialized before iteration and reported after iteration.
  • Tracing each line and counter value makes regex-based matching errors easier to locate.
  • Common implementation problems include resetting the counter, retaining newline characters, using re.match instead of re.search, and stopping or reporting too early.