Search a file for lines matching a regular expression pattern. Return the line number and contents of each matching line.
The Unix grep command can be used to search for lines in one or more files
that match a user-provided search query (known as the pattern).
The grep command takes three arguments:
- The pattern used to match lines in a file.
- Zero or more flags to customize the matching behavior.
- One or more files in which to search for matching lines.
Your task is to implement the grep function, which should read the contents
of the specified files, find the lines that match the specified pattern
and then output those lines as a single string. Note that the lines should
be output in the order in which they were found, with the first matching line
in the first file being output first.
As an example, suppose there is a file named "input.txt" with the following contents:
hello
world
hello again
If we were to call grep "hello" input.txt, the returned string should be:
hello
hello again
As said earlier, the grep command should also support the following flags:
-nPrint the line numbers of each matching line.-lPrint only the names of files that contain at least one matching line.-iMatch line using a case-insensitive comparison.-vInvert the program -- collect all lines that fail to match the pattern.-xOnly match entire lines, instead of lines that contain a match.
If we run grep -n "hello" input.txt, the -n flag will require the matching
lines to be prefixed with its line number:
1:hello
3:hello again
And if we run grep -i "HELLO" input.txt, we'll do a case-insensitive match,
and the output will be:
hello
hello again
The grep command should support multiple flags at once.
For example, running grep -l -v "hello" file1.txt file2.txt should
print the names of files that do not contain the string "hello".
This exercise introduces the anyhow crate, which makes it easy to handle arbitrary error types.
Its intent is to ensure that when you're writing an application, you don't have to worry about what
particular errors your called function is returning, but to just do the right thing when propagating them.
N.B.: it is actually somewhat bad form to use anyhow when writing a library, as we are here; it's more
explicit and more useful to write your own Error enum when writing a library (potentially with the aid of helper
macros such as are provided by the thiserror crate). However, we are
intentionally and explicitly doing so here to demonstrate the use of this crate.
To learn more about this crate refer to its documentation.
While this exercise asks you to implement only the most basic functions of grep,
there is actually a project to fully re-implement grep in Rust - ripgrep.
If you liked the concept of rewriting the basic util programs in Rust be sure to check the following projects:
- fd - a clone of
find - exa - a clone of
ls - bat - a clone of
cat - coreutils - a rewrite of the GNU coreutils
Refer to the exercism help page for Rust installation and learning resources.
Execute the tests with:
$ cargo testAll but the first test have been ignored. After you get the first test to
pass, open the tests source file which is located in the tests directory
and remove the #[ignore] flag from the next test and get the tests to pass
again. Each separate test is a function with #[test] flag above it.
Continue, until you pass every test.
If you wish to run all ignored tests without editing the tests source file, use:
$ cargo test -- --ignoredTo run a specific test, for example some_test, you can use:
$ cargo test some_testIf the specific test is ignored use:
$ cargo test some_test -- --ignoredTo learn more about Rust tests refer to the online test documentation
Make sure to read the Modules chapter if you haven't already, it will help you with organizing your files.
After you have solved the exercise, please consider using the additional utilities, described in the installation guide, to further refine your final solution.
To format your solution, inside the solution directory use
cargo fmtTo see, if your solution contains some common ineffective use cases, inside the solution directory use
cargo clippy --all-targetsGenerally you should submit all files in which you implemented your solution (src/lib.rs in most cases). If you are using any external crates, please consider submitting the Cargo.toml file. This will make the review process faster and clearer.
The exercism/rust repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help!
If you want to know more about Exercism, take a look at the contribution guide.
Conversation with Nate Foster. http://www.cs.cornell.edu/Courses/cs3110/2014sp/hw/0/ps0.pdf
It's possible to submit an incomplete solution so you can see how others have completed the exercise.