Implement a simplified grep with extensible flags
Company: Bloomberg
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
## Problem
Implement a simplified version of `grep` that searches a text file and returns the lines that match a given query string.
You should focus on **clean, readable, extensible design** (e.g., parsing flags/options in a way that makes it easy to add new flags later), not on advanced algorithms.
## Requirements
- Input:
- `pattern`: a non-empty string to search for.
- `lines`: an array/list of strings representing the file content, one element per line.
- `flags/options`: a set of optional flags (you may choose the interface, e.g., CLI args, a struct/object, or a map).
- Output:
- The matching lines, in original order.
## Supported flags (minimum)
Define at least a few flags and implement them, such as:
- Case-insensitive match (e.g., `-i`)
- Print line numbers along with matched lines (e.g., `-n`)
- Invert match (return non-matching lines) (e.g., `-v`)
## Notes
- Assume a simple **substring match** (not full regex).
- Be explicit about edge cases (empty file, empty lines, pattern casing, etc.).
- The interviewer will evaluate:
- Code organization (separation of concerns: parsing, matching, formatting)
- Extensibility (how easy it is to add a new flag)
- Correctness and testability
## Example
Given:
- `pattern = "error"`
- `lines = ["ok", "Error: disk full", "no issue", "error again"]`
- flags: case-insensitive
Output:
- `"Error: disk full"`
- `"error again"`
Overview: This question evaluates competency in designing maintainable, extensible text-processing code, covering flag parsing, separation of concerns, and correct substring matching behavior.
Read the full Bloomberg Software Engineer interview experience this question came from
Community answers
Answer by huhi
from dataclasses import dataclass
@dataclass
class GrepOptions:
ignore_case: bool = False # -i
show_line_number: bool = False # -n
invert_match: bool = False # -v
def parse_flags(flags: list[str]) -> GrepOptions:
options = GrepOptions()
for flag in flags:
# 如果是大小写不敏感匹配
if flag == "-i":
options.ignore_case = True
# 如果要输出行号
elif flag == "-n":
options.show_line_number = True
# 如果要返回不匹配的行
elif flag == "-v":
options.invert_match = True
else:
raise ValueError(f"unsupported flag: {flag}")
return options
def matches(line: str, pattern: str, options: GrepOptions) -> bool:
# 如果忽略大小写,就统一转小写后做子串匹配
if options.ignore_case:
line = line.lower()
pattern = pattern.lower()
found = pattern in line
# 如果开启了反选,就把匹配结果取反
if options.invert_match:
return not found
return found
def format_line(line: str, line_number: int, options: GrepOptions) -> str:
# 如果要求显示行号,就按 "行号:内容" 输出
if options.show_line_number:
return f"{line_number}:{line}"
return line
def grep(pattern: str, lines: list[str], flags: list[str]) -> list[str]:
# 题目说 pattern 是非空,这里顺手做个保护
if not pattern:
return []
options = parse_flags(flags)
result = []
for idx, line in enumerate(lines, start=1):
# 如果当前行满足匹配条件,就格式化后加入结果
if matches(line, pattern, options):
result.append(format_line(line, idx, options))
return result