From e0c0ee8e42352af95d5285b2da9a914559effa93 Mon Sep 17 00:00:00 2001 From: Xevion Date: Tue, 23 Jul 2019 23:04:12 -0500 Subject: [PATCH] grep exercise --- .vscode/launch.json | 70 +++++++++++++++++++++++++++++++++++++++++++++ python/COMMENTS.md | 8 +++++- python/grep/grep.py | 51 ++++++++++++++++++++++++++++++++- 3 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..92a2fa2 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,70 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Current File (Integrated Terminal)", + "type": "python", + "request": "launch", + "program": "${file}", + "console": "integratedTerminal" + }, + { + "name": "Python: Remote Attach", + "type": "python", + "request": "attach", + "port": 5678, + "host": "localhost", + "pathMappings": [ + { + "localRoot": "${workspaceFolder}", + "remoteRoot": "." + } + ] + }, + { + "name": "Python: Module", + "type": "python", + "request": "launch", + "module": "enter-your-module-name-here", + "console": "integratedTerminal" + }, + { + "name": "Python: Django", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}/manage.py", + "console": "integratedTerminal", + "args": [ + "runserver", + "--noreload", + "--nothreading" + ], + "django": true + }, + { + "name": "Python: Flask", + "type": "python", + "request": "launch", + "module": "flask", + "env": { + "FLASK_APP": "app.py" + }, + "args": [ + "run", + "--no-debugger", + "--no-reload" + ], + "jinja": true + }, + { + "name": "Python: Current File (External Terminal)", + "type": "python", + "request": "launch", + "program": "${file}", + "console": "externalTerminal" + } + ] +} \ No newline at end of file diff --git a/python/COMMENTS.md b/python/COMMENTS.md index 80ebdbd..6850c4f 100644 --- a/python/COMMENTS.md +++ b/python/COMMENTS.md @@ -2,7 +2,7 @@ This page represents all my comments from my solutions currently hosted on [Exercism.io](https://exercism.io/). You can view my profile [here](https://exercism.io/profiles/Xevion). The reason for this is simply to have a place where I can collect my comments, as well as just have some fun with Python and webscraping. Exercise file and exercise submission links will be provided for each and every exercise. -This file is for the **Python** track, contains **47** submissions, **17** of which have comments. This file was built on **23-07-2019** at **23:47:58 UTC**. +This file is for the **Python** track, contains **48** submissions, **18** of which have comments. This file was built on **24-07-2019** at **04:03:49 UTC**. ## Word Count @@ -233,6 +233,12 @@ I forgot that a couple things could be omitted, and decided to trim the nouns so +## Grep + +[Link to File](./grep/grep.py) | [Link to Submission](https://exercism.io/tracks/python/exercises/grep/solutions/c5d464b7392248d6adaab310e49803f5) + +I liked this exercise honestly. I learned about some new modules and methods, for example, while trying to create the invert flag, I was looking into how to negate the matching function, and the `functools` module allows one to create a wrapper that can negate any function you pass through it. + ## Tournament [Link to File](./tournament/tournament.py) | [Link to Submission](https://exercism.io/tracks/python/exercises/tournament/solutions/6617ee41fac443be992d3090e650a16e) diff --git a/python/grep/grep.py b/python/grep/grep.py index ca44ce1..e7d38c3 100644 --- a/python/grep/grep.py +++ b/python/grep/grep.py @@ -1,2 +1,51 @@ +from functools import partial + +all_flags = ['n', 'l', 'i', 'v', 'x', 'm'] # m for multiple files + +# Main grep function that works on multiple files def grep(pattern, flags, files): - pass \ No newline at end of file + # Parse the flags into a dictionary + flags = [flag.strip('-').strip() for flag in flags.split()] + flags = {k : k in flags for k in all_flags} + flags['m'] = len(files) > 1 + # Parse all the files given and then concatenate into a string + res = [grep_individual(pattern, flags, filename) for filename in files] + res = '\n'.join(list(filter(None, res))) # Filters out empty strings + return res + '\n' if len(res) > 0 else '' + +# Matching function with options for case, full match and inversion +def match(subtext, text, case=True, full=False, invert=False): + if not case: + subtext, text = subtext.lower(), text.lower() + res = (subtext == text) if full else (subtext in text) + return not res if invert else res + +# Function for processing against a individual file +def grep_individual(pattern, flags, filename): + # Create a local matching function using partial with the flags set + localmatch = partial(match, case=not flags['i'], full=flags['x'], invert=flags['v']) + text = open(filename, 'r').read() + result = [] + if not flags['l']: + for i, line in enumerate(text.split('\n')): + if localmatch(pattern, line): + pieces = [line] + # Add number to beginning + if flags['n']: + pieces.insert(0, str(i + 1)) + # If multiple files, add the file name to the front furthermore + if flags['m']: + pieces.insert(0, filename) + # Kind of a funky way to be doing it, but it's alright. + res = ':'.join(pieces) + result.append(res) + return '\n'.join(result) + # File name only flags + elif flags['l']: + for line in text.split('\n'): + # Returns as soon as a match is found + if localmatch(pattern, line): + return filename + return '' + +print(grep("may", "-n -m", ['grep_test.py'])) \ No newline at end of file