Skip to content

Commit 65724f3

Browse files
committed
* add practice exercise: grep
1 parent 3d44246 commit 65724f3

File tree

14 files changed

+1245
-0
lines changed

14 files changed

+1245
-0
lines changed

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,14 @@
462462
"practices": [],
463463
"prerequisites": [],
464464
"difficulty": 3
465+
},
466+
{
467+
"slug": "grep",
468+
"name": "Grep",
469+
"uuid": "4d4adf29-ae22-4192-b303-ebb8620b3b43",
470+
"practices": [],
471+
"prerequisites": [],
472+
"difficulty": 3
465473
}
466474
]
467475
},
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Instructions
2+
3+
Search files for lines matching a search string and return all matching lines.
4+
5+
The Unix [`grep`][grep] command searches files for lines that match a regular expression.
6+
Your task is to implement a simplified `grep` command, which supports searching for fixed strings.
7+
8+
The `grep` command takes three arguments:
9+
10+
1. The string to search for.
11+
2. Zero or more flags for customizing the command's behavior.
12+
3. One or more files to search in.
13+
14+
It then reads the contents of the specified files (in the order specified), finds the lines that contain the search string, and finally returns those lines in the order in which they were found.
15+
When searching in multiple files, each matching line is prepended by the file name and a colon (':').
16+
17+
## Flags
18+
19+
The `grep` command supports the following flags:
20+
21+
- `-n` Prepend the line number and a colon (':') to each line in the output, placing the number after the filename (if present).
22+
- `-l` Output only the names of the files that contain at least one matching line.
23+
- `-i` Match using a case-insensitive comparison.
24+
- `-v` Invert the program -- collect all lines that fail to match.
25+
- `-x` Search only for lines where the search string matches the entire line.
26+
27+
[grep]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/grep.html
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"authors": [
3+
"jimmytty"
4+
],
5+
"files": {
6+
"solution": [
7+
"Grep.pas"
8+
],
9+
"test": [
10+
"TestCases.pas"
11+
],
12+
"example": [
13+
".meta/example.pas"
14+
]
15+
},
16+
"blurb": "Search a file for lines matching a regular expression pattern. Return the line number and contents of each matching line.",
17+
"source": "Conversation with Nate Foster.",
18+
"source_url": "https://www.cs.cornell.edu/Courses/cs3110/2014sp/hw/0/ps0.pdf"
19+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
unit Grep;
2+
3+
{$mode ObjFPC}{$H+}
4+
5+
interface
6+
7+
type
8+
TStrArray = Array Of String;
9+
10+
function grep(
11+
const pattern : string;
12+
const flags : TStrArray;
13+
const files : TStrArray
14+
) : TStrArray;
15+
16+
implementation
17+
18+
uses SysUtils, StrUtils, Classes;
19+
20+
function grep(
21+
const pattern : string;
22+
const flags : TStrArray;
23+
const files : TStrArray
24+
) : TStrArray;
25+
var
26+
i : integer;
27+
LineContent : string;
28+
LineNumber : integer;
29+
LText, LPattern : string;
30+
PatternCount : integer = 0;
31+
PatternContent : string;
32+
TFIn : TextFile;
33+
FlagN : boolean = false;
34+
FlagL : boolean = false;
35+
FlagI : boolean = false;
36+
FlagV : boolean = false;
37+
FlagX : boolean = false;
38+
begin
39+
for i := low(flags) to high(flags) do
40+
begin
41+
case flags[i] of
42+
'-n' : FlagN := true;
43+
'-l' : FlagL := true;
44+
'-i' : FlagI := true;
45+
'-v' : FlagV := true;
46+
'-x' : FlagX := true;
47+
end;
48+
end;
49+
result := [];
50+
LPattern := IfThen(FlagI, LowerCase(pattern), pattern);
51+
for i := low(files) to high(files) do
52+
begin
53+
LineNumber := 0;
54+
AssignFile(TFIn, files[i]);
55+
reset(TFIn);
56+
while not eof(TFIn) do
57+
begin
58+
PatternContent := '';
59+
inc(LineNumber);
60+
ReadLn(TFIn, LineContent);
61+
LText := IfThen(FlagI, LowerCase(LineContent), LineContent);
62+
if FlagX then
63+
begin
64+
if FlagV then
65+
begin
66+
if LPattern <> LText then PatternContent := LineContent;
67+
end
68+
else
69+
begin
70+
if LPattern = LText then PatternContent := LineContent;
71+
end
72+
end
73+
else if FlagV then
74+
begin
75+
if pos(LPattern, LText) = 0 then PatternContent := LineContent;
76+
end
77+
else if pos(LPattern, LText) > 0 then PatternContent := LineContent;
78+
if PatternContent <> '' then
79+
begin
80+
if FlagL then
81+
begin
82+
insert(files[i], result, length(result));
83+
break;
84+
end;
85+
inc(PatternCount);
86+
if FlagN then
87+
PatternContent := format('%d:%s', [LineNumber, PatternContent]);
88+
if length(files) > 1 then
89+
PatternContent := format('%s:%s', [files[i], PatternContent]);
90+
insert(PatternContent, result, PatternCount - 1);
91+
end;
92+
end;
93+
CloseFile(TFIn);
94+
end;
95+
end;
96+
97+
end.
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[9049fdfd-53a7-4480-a390-375203837d09]
13+
description = "Test grepping a single file -> One file, one match, no flags"
14+
15+
[76519cce-98e3-46cd-b287-aac31b1d77d6]
16+
description = "Test grepping a single file -> One file, one match, print line numbers flag"
17+
18+
[af0b6d3c-e0e8-475e-a112-c0fc10a1eb30]
19+
description = "Test grepping a single file -> One file, one match, case-insensitive flag"
20+
21+
[ff7af839-d1b8-4856-a53e-99283579b672]
22+
description = "Test grepping a single file -> One file, one match, print file names flag"
23+
24+
[8625238a-720c-4a16-81f2-924ec8e222cb]
25+
description = "Test grepping a single file -> One file, one match, match entire lines flag"
26+
27+
[2a6266b3-a60f-475c-a5f5-f5008a717d3e]
28+
description = "Test grepping a single file -> One file, one match, multiple flags"
29+
30+
[842222da-32e8-4646-89df-0d38220f77a1]
31+
description = "Test grepping a single file -> One file, several matches, no flags"
32+
33+
[4d84f45f-a1d8-4c2e-a00e-0b292233828c]
34+
description = "Test grepping a single file -> One file, several matches, print line numbers flag"
35+
36+
[0a483b66-315b-45f5-bc85-3ce353a22539]
37+
description = "Test grepping a single file -> One file, several matches, match entire lines flag"
38+
39+
[3d2ca86a-edd7-494c-8938-8eeed1c61cfa]
40+
description = "Test grepping a single file -> One file, several matches, case-insensitive flag"
41+
42+
[1f52001f-f224-4521-9456-11120cad4432]
43+
description = "Test grepping a single file -> One file, several matches, inverted flag"
44+
45+
[7a6ede7f-7dd5-4364-8bf8-0697c53a09fe]
46+
description = "Test grepping a single file -> One file, no matches, various flags"
47+
48+
[3d3dfc23-8f2a-4e34-abd6-7b7d140291dc]
49+
description = "Test grepping a single file -> One file, one match, file flag takes precedence over line flag"
50+
51+
[87b21b24-b788-4d6e-a68b-7afe9ca141fe]
52+
description = "Test grepping a single file -> One file, several matches, inverted and match entire lines flags"
53+
54+
[ba496a23-6149-41c6-a027-28064ed533e5]
55+
description = "Test grepping multiples files at once -> Multiple files, one match, no flags"
56+
57+
[4539bd36-6daa-4bc3-8e45-051f69f5aa95]
58+
description = "Test grepping multiples files at once -> Multiple files, several matches, no flags"
59+
60+
[9fb4cc67-78e2-4761-8e6b-a4b57aba1938]
61+
description = "Test grepping multiples files at once -> Multiple files, several matches, print line numbers flag"
62+
63+
[aeee1ef3-93c7-4cd5-af10-876f8c9ccc73]
64+
description = "Test grepping multiples files at once -> Multiple files, one match, print file names flag"
65+
66+
[d69f3606-7d15-4ddf-89ae-01df198e6b6c]
67+
description = "Test grepping multiples files at once -> Multiple files, several matches, case-insensitive flag"
68+
69+
[82ef739d-6701-4086-b911-007d1a3deb21]
70+
description = "Test grepping multiples files at once -> Multiple files, several matches, inverted flag"
71+
72+
[77b2eb07-2921-4ea0-8971-7636b44f5d29]
73+
description = "Test grepping multiples files at once -> Multiple files, one match, match entire lines flag"
74+
75+
[e53a2842-55bb-4078-9bb5-04ac38929989]
76+
description = "Test grepping multiples files at once -> Multiple files, one match, multiple flags"
77+
78+
[9c4f7f9a-a555-4e32-bb06-4b8f8869b2cb]
79+
description = "Test grepping multiples files at once -> Multiple files, no matches, various flags"
80+
81+
[ba5a540d-bffd-481b-bd0c-d9a30f225e01]
82+
description = "Test grepping multiples files at once -> Multiple files, several matches, file flag takes precedence over line number flag"
83+
84+
[ff406330-2f0b-4b17-9ee4-4b71c31dd6d2]
85+
description = "Test grepping multiples files at once -> Multiple files, several matches, inverted and match entire lines flags"

exercises/practice/grep/Grep.pas

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
unit Grep;
2+
3+
{$mode ObjFPC}{$H+}
4+
5+
interface
6+
7+
type
8+
TStrArray = Array Of String;
9+
10+
function grep(
11+
const pattern : string;
12+
const flags : TStrArray;
13+
const files : TStrArray
14+
) : TStrArray;
15+
16+
implementation
17+
18+
uses SysUtils;
19+
20+
function grep(
21+
const pattern : string;
22+
const flags : TStrArray;
23+
const files : TStrArray
24+
) : TStrArray;
25+
begin
26+
27+
raise ENotImplemented.Create('Please implement your solution.'); result := [pattern, IntToStr(length(flags)), IntToStr(length(files))];
28+
29+
end;
30+
31+
end.

exercises/practice/grep/Makefile

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
SHELL = /bin/bash
2+
MAKEFLAGS += --no-print-directory
3+
DESTDIR = build
4+
EXECUTABLE = $(DESTDIR)/test
5+
COMMAND = fpc -l- -v0 -g -gl -Sa -Cr -Sehnw -Fu./lib test.pas -FE"./$(DESTDIR)"
6+
7+
.ONESHELL:
8+
9+
test:
10+
@mkdir -p "./$(DESTDIR)"
11+
@cp -r ./lib "./$(DESTDIR)"
12+
@$(COMMAND) && ./$(EXECUTABLE) $(test)
13+
14+
clean:
15+
@rm -fr "./$(DESTDIR)"

0 commit comments

Comments
 (0)