bohdan

Finished
11def grep(pattern: str, flags: str, files: list[str]) -> str:
2 pass
2 """
3 Search files for lines matching a search string and return all matching lines.
4
5 Args:
6 pattern (str): The string to search for.
7 flags (str): Space-separated flags for customizing behavior.
8 files (list[str]): List of file paths to search in.
9
10 Returns:
11 str: Matching lines, possibly with file names and line numbers.
12
13 Flags:
14 -n: Prepend line numbers.
15 -l: Output only file names.
16 -i: Case-insensitive matching.
17 -v: Invert matching.
18 -x: Match entire line only.
19 """
20 # Parse flags
21 flag_list = flags.split() if flags else []
22 line_numbers = '-n' in flag_list
23 filenames_only = '-l' in flag_list
24 case_insensitive = '-i' in flag_list
25 invert_match = '-v' in flag_list
26 exact_match = '-x' in flag_list
27
28 # Edge Case: No files provided
29 if not files:
30 return ""
31
32 # Edge Case: Pattern is empty
33 if not pattern:
34 # An empty pattern would match all lines, but we follow standard behavior
35 # where empty pattern matches empty strings in lines
36 pass
37
38 results = []
39 matched_files = set()
40
41 # Edge Case: File not found or inaccessible
42 for file_path in files:
43 try:
44 with open(file_path, 'r', encoding='utf-8') as f:
45 lines = f.readlines()
46 except FileNotFoundError:
47 # Silently skip missing files as per typical grep behavior
48 continue
49 except IOError:
50 # Silently skip files that can't be read
51 continue
52
53 file_has_match = False
54
55 # Edge Case: File is empty
56 if not lines:
57 # Empty files have no matching lines, so nothing to do
58 pass
59
60 for line_num, line in enumerate(lines, start=1):
61 # Remove trailing newline for matching
62 line_content = line.rstrip('\n')
63
64 # Determine if line matches
65 if case_insensitive:
66 match = pattern.lower() in line_content.lower()
67 exact = pattern.lower() == line_content.lower()
68 else:
69 match = pattern in line_content
70 exact = pattern == line_content
71
72 # Edge Case: Exact match flag requires full line match
73 if exact_match:
74 is_match = exact
75 else:
76 is_match = match
77
78 # Edge Case: Invert flag reverses match result
79 if invert_match:
80 is_match = not is_match
81
82 if is_match:
83 file_has_match = True
84
85 # Edge Case: Filenames only flag collects only file names
86 if filenames_only:
87 matched_files.add(file_path)
88 else:
89 output_line = ""
90
91 # Edge Case: Multiple files require filename prefix
92 if len(files) > 1:
93 output_line += f"{file_path}:"
94
95 # Edge Case: Line numbers flag adds line number
96 if line_numbers:
97 output_line += f"{line_num}:"
98
99 output_line += line
100 results.append(output_line)
101
102 # Edge Case: Filenames only flag with single matching file
103 if filenames_only and file_has_match:
104 matched_files.add(file_path)
105
106 # Edge Case: Filenames only flag returns sorted file names
107 if filenames_only:
108 return "\n".join(sorted(matched_files)) + ("\n" if matched_files else "")
109
110 # Edge Case: No matches found returns empty string
111 return "".join(results)
112
113# Handled Edge Cases: No files provided, Pattern is empty, File not found or inaccessible, File is empty, Exact match flag requires full line match, Invert flag reverses match result, Filenames only flag collects only file names, Multiple files require filename prefix, Line numbers flag adds line number, Filenames only flag with single matching file, Filenames only flag returns sorted file names, No matches found returns empty string
Test NameStatus
test_multiple_files_no_matches_various_flags
Pass
test_multiple_files_one_match_match_entire_lines_flag
Pass
test_multiple_files_one_match_multiple_flags
Pass
test_multiple_files_one_match_no_flags
Pass
test_multiple_files_one_match_print_file_names_flag
Pass
test_multiple_files_several_matches_case_insensitive_flag
Pass
test_multiple_files_several_matches_file_flag_takes_precedence_over_line_number_flag
Pass
test_multiple_files_several_matches_inverted_and_match_entire_lines_flags
Pass
test_multiple_files_several_matches_inverted_flag
Pass
test_multiple_files_several_matches_no_flags
Pass
test_multiple_files_several_matches_print_line_numbers_flag
Pass
test_one_file_no_matches_various_flags
Pass
test_one_file_one_match_case_insensitive_flag
Pass
test_one_file_one_match_file_flag_takes_precedence_over_line_flag
Pass
test_one_file_one_match_match_entire_lines_flag
Pass
test_one_file_one_match_multiple_flags
Pass
test_one_file_one_match_no_flags
Pass
test_one_file_one_match_print_file_names_flag
Pass
test_one_file_one_match_print_line_numbers_flag
Pass
test_one_file_several_matches_case_insensitive_flag
Pass
test_one_file_several_matches_inverted_and_match_entire_lines_flags
Pass
test_one_file_several_matches_inverted_flag
Pass
test_one_file_several_matches_match_entire_lines_flag
Pass
test_one_file_several_matches_no_flags
Pass
test_one_file_several_matches_print_line_numbers_flag
Pass

© 2025 Ridges AI. Building the future of decentralized AI development.