From 4409bdf6f56a7936d10b115396019a38084d87de Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Mon, 28 Aug 2017 15:28:37 +0530 Subject: [PATCH 01/54] question numbering and formatting --- Exercises.md | 75 ++++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/Exercises.md b/Exercises.md index 0f06e71..0b13551 100644 --- a/Exercises.md +++ b/Exercises.md @@ -1,18 +1,18 @@ # Exercises -* [Variables and Print](#variables-and-print) -* [Functions](#functions) -* [Control structures](#control-structures) -* [List](#list) -* [File](#file) -* [Text processing](#text-processing) -* [Misc](#misc) +1) [Variables and Print](#variables-and-print) +2) [Functions](#functions) +3) [Control structures](#control-structures) +4) [List](#list) +5) [File](#file) +6) [Text processing](#text-processing) +7) [Misc](#misc)
-## Variables and Print +## 1) Variables and Print -Ask user information, for ex: `name`, `department`, `college` etc and display them using print function +**Q1a)** Ask user information, for ex: `name`, `department`, `college` etc and display them using print function ``` # Sample of how program might ask user input and display output afterwards @@ -30,9 +30,9 @@ College : PSG Tech
-## Functions +## 2) Functions -* Returns length of integer numbers +**Q2a)** Returns length of integer numbers ```python >>> len_int(962306349871524124750813401378124) @@ -52,7 +52,7 @@ Traceback (most recent call last): TypeError: provide only integer input ``` -* Returns True/False - two strings are same irrespective of lowercase/uppercase +**Q2b)** Returns True/False - two strings are same irrespective of lowercase/uppercase ```python >>> str_cmp('nice', 'nice') @@ -65,7 +65,7 @@ True False ``` -* Returns True/False - two strings are anagrams (assume input consists of alphabets only) +**Q2c)** Returns True/False - two strings are anagrams (assume input consists of alphabets only) ```python >>> str_anagram('god', 'Dog') @@ -78,14 +78,15 @@ True
-## Control structures +## 3) Control structures -* Write a function that returns - * 'Good' for numbers divisable by 7 - * 'Food' for numbers divisable by 6 - * 'Universe' for numbers divisable by 42 - * 'Oops' for all other numbers - * Only one output, divisable by 42 takes precedence +**Q3a)** Write a function that returns + +* 'Good' for numbers divisable by 7 +* 'Food' for numbers divisable by 6 +* 'Universe' for numbers divisable by 42 +* 'Oops' for all other numbers +* Only one output, divisable by 42 takes precedence ```python >>> six_by_seven(66) @@ -121,7 +122,7 @@ True 100 Oops ``` -* Print all numbers from 1 to 1000 which reads the same in reversed form in both binary and decimal format +**Q3b)** Print all numbers from 1 to 1000 which reads the same in reversed form in both binary and decimal format ``` $ ./dec_bin.py @@ -158,9 +159,9 @@ $ ./dec_bin_oct_hex.py
-## List +## 4) List -* Write a function that returns product of all numbers of a list +**Q4a)** Write a function that returns product of all numbers of a list ```python >>> product([1, 4, 21]) @@ -185,8 +186,7 @@ $ ./dec_bin_oct_hex.py # can you identify what mathematical function the last one performs? ``` -* Write a function that returns nth lowest number of a list (or iterable in general) - * by default, return the lowest if second argument not specified +**Q4b)** Write a function that returns nth lowest number of a list (or iterable in general). Return the lowest if second argument not specified ```python >>> nums = [42, 23421341, 234.2e3, 21, 232, 12312, -2343] @@ -212,9 +212,9 @@ IndexError: list index out of range
-## File +## 5) File -* Print sum of all numbers from a file containing only single column and all numbers +**Q5a)** Print sum of all numbers from a file containing only single column and all numbers ``` $ cat f1.txt @@ -230,7 +230,7 @@ $ ./col_sum.py 10485.14 ``` -* Print sum of all numbers (assume only positive integer numbers) from a file containing arbitrary string +**Q5b)** Print sum of all numbers (assume only positive integer numbers) from a file containing arbitrary string ``` $ cat f2.txt @@ -245,10 +245,9 @@ $ ./extract_sum.py
-## Text processing +## 6) Text processing -* Check if two words are same or differ by only one character (irrespective of case) - * input strings should have same length +**Q6a)** Check if two words are same or differ by only one character (irrespective of case), input strings should have same length ```python >>> is_one_char_diff('bar', 'bar') @@ -272,8 +271,9 @@ False False ``` -* Check if a word is in ascending/descending alphabetic order or not (irrespective of case) - * can you think of a way to do it only using built-in functions and string methods? +**Q6b)** Check if a word is in ascending/descending alphabetic order or not (irrespective of case) + +Can you think of a way to do it only using built-in functions and string methods? ```python >>> is_alpha_order('bot') @@ -306,9 +306,8 @@ False
-## Misc +## 7) Misc + +**Q7a)** Play a song (**hint** use `subprocess` module) -* Play a song - * **hint** use `subprocess` module -* Open a browser along with any link, for ex: https://github.com/learnbyexample/Python_Basics - * **hint** use `webbrowser` module +**Q7b)** Open a browser along with any link, for ex: https://github.com/learnbyexample/Python_Basics (**hint** use `webbrowser` module) From 243c741858d1c53aa023c839a5f51148555dc217 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Mon, 28 Aug 2017 15:53:52 +0530 Subject: [PATCH 02/54] typo correction --- Exercises.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/Exercises.md b/Exercises.md index 0b13551..e4f2385 100644 --- a/Exercises.md +++ b/Exercises.md @@ -173,8 +173,6 @@ $ ./dec_bin_oct_hex.py *bonus*: works on any kind of iterable ```python ->>> product(b) -84 >>> product((-3, 11, 2)) -66 >>> product({8, 300}) From 868834eb4af9c669634a5cb2e596ce121a6f4586 Mon Sep 17 00:00:00 2001 From: learnbyexample Date: Mon, 28 Aug 2017 19:05:17 +0530 Subject: [PATCH 03/54] added exercise related files --- exercise_files/f1.txt | 7 +++++++ exercise_files/f2.txt | 4 ++++ exercise_files/q2a_int_length.py | 18 ++++++++++++++++++ exercise_files/q2b_str_comparison.py | 13 +++++++++++++ exercise_files/q2c_str_same_letters.py | 11 +++++++++++ exercise_files/q3a_6by7.py | 13 +++++++++++++ exercise_files/q4a_iter_product.py | 13 +++++++++++++ exercise_files/q4b_lowest_value.py | 16 ++++++++++++++++ exercise_files/q6a_one_char_diff.py | 23 +++++++++++++++++++++++ exercise_files/q6b_alpha_order.py | 22 ++++++++++++++++++++++ 10 files changed, 140 insertions(+) create mode 100644 exercise_files/f1.txt create mode 100644 exercise_files/f2.txt create mode 100755 exercise_files/q2a_int_length.py create mode 100755 exercise_files/q2b_str_comparison.py create mode 100755 exercise_files/q2c_str_same_letters.py create mode 100755 exercise_files/q3a_6by7.py create mode 100755 exercise_files/q4a_iter_product.py create mode 100755 exercise_files/q4b_lowest_value.py create mode 100755 exercise_files/q6a_one_char_diff.py create mode 100755 exercise_files/q6b_alpha_order.py diff --git a/exercise_files/f1.txt b/exercise_files/f1.txt new file mode 100644 index 0000000..d944f3c --- /dev/null +++ b/exercise_files/f1.txt @@ -0,0 +1,7 @@ +8 +53 +3.14 +84 +73e2 +100 +2937 diff --git a/exercise_files/f2.txt b/exercise_files/f2.txt new file mode 100644 index 0000000..cc8fa8c --- /dev/null +++ b/exercise_files/f2.txt @@ -0,0 +1,4 @@ +Hello123 World 35 +341 2 +Good 13day +How are 1784 you diff --git a/exercise_files/q2a_int_length.py b/exercise_files/q2a_int_length.py new file mode 100755 index 0000000..658db59 --- /dev/null +++ b/exercise_files/q2a_int_length.py @@ -0,0 +1,18 @@ +#!/usr/bin/python3 + +def len_int(n): + pass + +assert len_int(123) == 3 +assert len_int(2) == 1 +assert len_int(+42) == 2 +assert len_int(-42) == 2 +assert len_int(572342) == 6 +assert len_int(962306349871524124750813401378124) == 33 + +try: + assert len_int('a') +except TypeError as e: + assert str(e) == 'provide only integer input' + +print('all tests passed') diff --git a/exercise_files/q2b_str_comparison.py b/exercise_files/q2b_str_comparison.py new file mode 100755 index 0000000..f2cf54f --- /dev/null +++ b/exercise_files/q2b_str_comparison.py @@ -0,0 +1,13 @@ +#!/usr/bin/python3 + +def str_cmp(s1, s2): + pass + +assert str_cmp('abc', 'Abc') +assert str_cmp('Hi there', 'hi there') +assert not str_cmp('foo', 'food') +assert str_cmp('nice', 'nice') +assert str_cmp('GoOd DaY', 'gOOd dAy') +assert not str_cmp('how', 'who') + +print('all tests passed') diff --git a/exercise_files/q2c_str_same_letters.py b/exercise_files/q2c_str_same_letters.py new file mode 100755 index 0000000..bbce388 --- /dev/null +++ b/exercise_files/q2c_str_same_letters.py @@ -0,0 +1,11 @@ +#!/usr/bin/python3 + +def str_anagram(s1, s2): + pass + +assert str_anagram('god', 'Dog') +assert str_anagram('beat', 'abet') +assert not str_anagram('beat', 'table') +assert not str_anagram('seat', 'teal') + +print('all tests passed') diff --git a/exercise_files/q3a_6by7.py b/exercise_files/q3a_6by7.py new file mode 100755 index 0000000..85b0f40 --- /dev/null +++ b/exercise_files/q3a_6by7.py @@ -0,0 +1,13 @@ +#!/usr/bin/python3 + +def six_by_seven(num): + pass + +assert six_by_seven(66) == 'Food' +assert six_by_seven(13) == 'Oops' +assert six_by_seven(42) == 'Universe' +assert six_by_seven(14) == 'Good' +assert six_by_seven(84) == 'Universe' +assert six_by_seven(235432) == 'Oops' + +print('all tests passed') diff --git a/exercise_files/q4a_iter_product.py b/exercise_files/q4a_iter_product.py new file mode 100755 index 0000000..867a9df --- /dev/null +++ b/exercise_files/q4a_iter_product.py @@ -0,0 +1,13 @@ +#!/usr/bin/python3 + +def product(ip_iterable): + pass + +assert product([1, 4, 21]) == 84 +assert product([-4, 2.3e12, 77.23, 982, 0b101]) == -3.48863356e+18 +assert product((-3, 11, 2)) == -66 +assert product({8, 300}) == 2400 +assert product([234, 121, 23, 945, 0]) == 0 +assert product(range(1, 6)) == 120 + +print('all tests passed') diff --git a/exercise_files/q4b_lowest_value.py b/exercise_files/q4b_lowest_value.py new file mode 100755 index 0000000..7db197c --- /dev/null +++ b/exercise_files/q4b_lowest_value.py @@ -0,0 +1,16 @@ +#!/usr/bin/python3 + +def nth_lowest(): + pass + +nums = [42, 23421341, 234.2e3, 21, 232, 12312, -2343] +assert nth_lowest(nums, 3) == 42 +assert nth_lowest(nums, 5) == 12312 + +nums = [1, -2, 4, 2, 1, 3, 3, 5] +assert nth_lowest(nums) == -2 +assert nth_lowest(nums, 4) == 3 + +assert nth_lowest('unrecognizable', 3) == 'c' + +print('all tests passed') diff --git a/exercise_files/q6a_one_char_diff.py b/exercise_files/q6a_one_char_diff.py new file mode 100755 index 0000000..9f84508 --- /dev/null +++ b/exercise_files/q6a_one_char_diff.py @@ -0,0 +1,23 @@ +#!/usr/bin/python3 + +def is_one_char_diff(word1, word2): + pass + +assert is_one_char_diff('bar', 'car') +assert is_one_char_diff('bar', 'Bat') +assert is_one_char_diff('bar', 'bar') +assert is_one_char_diff('bar', 'baZ') +assert is_one_char_diff('A', 'b') + +assert not is_one_char_diff('a', '') +assert not is_one_char_diff('bar', 'bark') +assert not is_one_char_diff('bar', 'Art') +assert not is_one_char_diff('bar', 'bot') +assert not is_one_char_diff('ab', '') + +assert is_one_char_diff('Food', 'good') +assert is_one_char_diff('food', 'fold') +assert not is_one_char_diff('food', 'Foody') +assert not is_one_char_diff('food', 'fled') + +print('all tests passed') diff --git a/exercise_files/q6b_alpha_order.py b/exercise_files/q6b_alpha_order.py new file mode 100755 index 0000000..197886b --- /dev/null +++ b/exercise_files/q6b_alpha_order.py @@ -0,0 +1,22 @@ +#!/usr/bin/python3 + +def is_alpha_order(word): + pass + +assert is_alpha_order('bot') +assert is_alpha_order('art') +assert is_alpha_order('toe') +assert is_alpha_order('AborT') + +assert not is_alpha_order('are') +assert not is_alpha_order('boat') +assert not is_alpha_order('Flee') + +#sentence +def is_alpha_order_sentence(sentence): + pass + +assert is_alpha_order_sentence('Toe got bit') +assert not is_alpha_order_sentence('All is well') + +print('all tests passed') From fb89a03cac85599f3d842f0589aa441b9bea2950 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Mon, 28 Aug 2017 19:17:52 +0530 Subject: [PATCH 04/54] link to exercise_files directory --- Exercises.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Exercises.md b/Exercises.md index e4f2385..b80cf86 100644 --- a/Exercises.md +++ b/Exercises.md @@ -10,6 +10,10 @@
+For some questions, Python program with assert statements is provided to automatically test your solution in the [exercise_files](https://github.com/learnbyexample/Python_Basics/tree/master/exercise_files) directory - for ex: [Q2a - length of integer numbers](https://github.com/learnbyexample/Python_Basics/blob/master/exercise_files/q2a_int_length.py). The directory also has sample input text files. + +
+ ## 1) Variables and Print **Q1a)** Ask user information, for ex: `name`, `department`, `college` etc and display them using print function From 16fcf0cef50e9f9549bd19270c6ca4a4a5df5e09 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Tue, 29 Aug 2017 09:22:38 +0530 Subject: [PATCH 05/54] clarified Q4a about duplicates --- Exercises.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Exercises.md b/Exercises.md index b80cf86..77bbc0e 100644 --- a/Exercises.md +++ b/Exercises.md @@ -190,6 +190,8 @@ $ ./dec_bin_oct_hex.py **Q4b)** Write a function that returns nth lowest number of a list (or iterable in general). Return the lowest if second argument not specified +*Note* that if a list contains duplicates, they should be handled before determining nth lowest + ```python >>> nums = [42, 23421341, 234.2e3, 21, 232, 12312, -2343] >>> nth_lowest(nums, 3) @@ -207,9 +209,13 @@ IndexError: list index out of range -2 >>> nth_lowest(nums, 4) 3 +>>> nth_lowest(nums, 5) +4 >>> nth_lowest('unrecognizable', 3) 'c' +>>> nth_lowest('abracadabra', 4) +'d' ```
From 43ce320e9e131b65a684f0274ce2556cf8c67eb0 Mon Sep 17 00:00:00 2001 From: learnbyexample Date: Tue, 29 Aug 2017 13:02:20 +0530 Subject: [PATCH 06/54] added exercise solutions for reference --- exercise_solutions/f1.txt | 7 +++++ exercise_solutions/f2.txt | 4 +++ exercise_solutions/q1a_usr_ip.py | 25 +++++++++++++++++ exercise_solutions/q2a_int_length.py | 22 +++++++++++++++ exercise_solutions/q2b_str_comparison.py | 13 +++++++++ exercise_solutions/q2c_str_same_letters.py | 11 ++++++++ exercise_solutions/q3a_6by7.py | 31 ++++++++++++++++++++++ exercise_solutions/q3b_dec_bin.py | 18 +++++++++++++ exercise_solutions/q4a_iter_product.py | 16 +++++++++++ exercise_solutions/q4b_lowest_value.py | 16 +++++++++++ exercise_solutions/q5a_col_sum.py | 15 +++++++++++ exercise_solutions/q5b_sum_ints.py | 14 ++++++++++ exercise_solutions/q6a_one_char_diff.py | 31 ++++++++++++++++++++++ exercise_solutions/q6b_alpha_order.py | 23 ++++++++++++++++ exercise_solutions/q7_misc.py | 8 ++++++ 15 files changed, 254 insertions(+) create mode 100644 exercise_solutions/f1.txt create mode 100644 exercise_solutions/f2.txt create mode 100755 exercise_solutions/q1a_usr_ip.py create mode 100755 exercise_solutions/q2a_int_length.py create mode 100755 exercise_solutions/q2b_str_comparison.py create mode 100755 exercise_solutions/q2c_str_same_letters.py create mode 100755 exercise_solutions/q3a_6by7.py create mode 100755 exercise_solutions/q3b_dec_bin.py create mode 100755 exercise_solutions/q4a_iter_product.py create mode 100755 exercise_solutions/q4b_lowest_value.py create mode 100755 exercise_solutions/q5a_col_sum.py create mode 100755 exercise_solutions/q5b_sum_ints.py create mode 100755 exercise_solutions/q6a_one_char_diff.py create mode 100755 exercise_solutions/q6b_alpha_order.py create mode 100755 exercise_solutions/q7_misc.py diff --git a/exercise_solutions/f1.txt b/exercise_solutions/f1.txt new file mode 100644 index 0000000..d944f3c --- /dev/null +++ b/exercise_solutions/f1.txt @@ -0,0 +1,7 @@ +8 +53 +3.14 +84 +73e2 +100 +2937 diff --git a/exercise_solutions/f2.txt b/exercise_solutions/f2.txt new file mode 100644 index 0000000..cc8fa8c --- /dev/null +++ b/exercise_solutions/f2.txt @@ -0,0 +1,4 @@ +Hello123 World 35 +341 2 +Good 13day +How are 1784 you diff --git a/exercise_solutions/q1a_usr_ip.py b/exercise_solutions/q1a_usr_ip.py new file mode 100755 index 0000000..267573f --- /dev/null +++ b/exercise_solutions/q1a_usr_ip.py @@ -0,0 +1,25 @@ +#!/usr/bin/python3 + +print('Please provide the following details') +name = input('Enter your name: ') +dept = input('Enter your department: ') +colg = input('Enter your college: ') + +op_fmt = '{:<11}: {}' + +print('\n------------------------------------') +print(op_fmt.format('Name', name)) +print(op_fmt.format('Department', dept)) +print(op_fmt.format('College', colg)) + + +####### Alternate +#print('Please provide the following details') +#labels = ('Name', 'Department', 'College') +#usr_details = [input('Enter your ' + itm + ': ') for itm in labels] +# +#itm_size = len(sorted(labels, key=len)[-1]) + 1 +#op_fmt = '{:<' + str(itm_size) + '}: {}' +#print('\n------------------------------------') +#for k,v in zip(labels, usr_details): +# print(op_fmt.format(k, v)) diff --git a/exercise_solutions/q2a_int_length.py b/exercise_solutions/q2a_int_length.py new file mode 100755 index 0000000..db7e93b --- /dev/null +++ b/exercise_solutions/q2a_int_length.py @@ -0,0 +1,22 @@ +#!/usr/bin/python3 + +def len_int(n): + if type(n) != int: + raise TypeError('provide only integer input') + + str_n = str(abs(n)) + return len(str_n) + +assert len_int(123) == 3 +assert len_int(2) == 1 +assert len_int(+42) == 2 +assert len_int(-42) == 2 +assert len_int(572342) == 6 +assert len_int(962306349871524124750813401378124) == 33 + +try: + assert len_int('a') +except TypeError as e: + assert str(e) == 'provide only integer input' + +print('all tests passed') diff --git a/exercise_solutions/q2b_str_comparison.py b/exercise_solutions/q2b_str_comparison.py new file mode 100755 index 0000000..fd8923c --- /dev/null +++ b/exercise_solutions/q2b_str_comparison.py @@ -0,0 +1,13 @@ +#!/usr/bin/python3 + +def str_cmp(s1, s2): + return s1.lower() == s2.lower() + +assert str_cmp('abc', 'Abc') +assert str_cmp('Hi there', 'hi there') +assert not str_cmp('foo', 'food') +assert str_cmp('nice', 'nice') +assert str_cmp('GoOd DaY', 'gOOd dAy') +assert not str_cmp('how', 'who') + +print('all tests passed') diff --git a/exercise_solutions/q2c_str_same_letters.py b/exercise_solutions/q2c_str_same_letters.py new file mode 100755 index 0000000..b236e54 --- /dev/null +++ b/exercise_solutions/q2c_str_same_letters.py @@ -0,0 +1,11 @@ +#!/usr/bin/python3 + +def str_anagram(s1, s2): + return sorted(s1.lower()) == sorted(s2.lower()) + +assert str_anagram('god', 'Dog') +assert str_anagram('beat', 'abet') +assert not str_anagram('beat', 'table') +assert not str_anagram('seat', 'teal') + +print('all tests passed') diff --git a/exercise_solutions/q3a_6by7.py b/exercise_solutions/q3a_6by7.py new file mode 100755 index 0000000..1b993b8 --- /dev/null +++ b/exercise_solutions/q3a_6by7.py @@ -0,0 +1,31 @@ +#!/usr/bin/python3 + +def six_by_seven(num): + if num % 42 == 0: + return 'Universe' + elif num % 7 == 0: + return 'Good' + elif num % 6 == 0: + return 'Food' + else: + return 'Oops' + +assert six_by_seven(66) == 'Food' +assert six_by_seven(13) == 'Oops' +assert six_by_seven(42) == 'Universe' +assert six_by_seven(14) == 'Good' +assert six_by_seven(84) == 'Universe' +assert six_by_seven(235432) == 'Oops' + +print('all tests passed') + +## bonus +#for num in range(1, 101): +# if num % 42 == 0: +# print(num, 'Universe') +# elif num % 7 == 0: +# print(num, 'Good') +# elif num % 6 == 0: +# print(num, 'Food') +# else: +# print(num, 'Oops') diff --git a/exercise_solutions/q3b_dec_bin.py b/exercise_solutions/q3b_dec_bin.py new file mode 100755 index 0000000..3349154 --- /dev/null +++ b/exercise_solutions/q3b_dec_bin.py @@ -0,0 +1,18 @@ +#!/usr/bin/python3 + +for n in range(1, 1001): + dec_n = str(n) + bin_n = format(n, 'b') + if dec_n == dec_n[::-1] and bin_n == bin_n[::-1]: + print(dec_n, bin_n) + + #oct_n = format(n, 'o') + #if dec_n == dec_n[::-1] and bin_n == bin_n[::-1] and oct_n == oct_n[::-1]: + # print('{0:d} {0:#b} {0:#o}'.format(n)) + + #oct_n = format(n, 'o') + #hex_n = format(n, 'x') + ##if all((dec_n == dec_n[::-1], bin_n == bin_n[::-1], oct_n == oct_n[::-1], hex_n == hex_n[::-1])): + #if dec_n == dec_n[::-1] and bin_n == bin_n[::-1] and \ + # oct_n == oct_n[::-1] and hex_n == hex_n[::-1]: + # print('{0:d} {0:#b} {0:#o} {0:#x}'.format(n)) diff --git a/exercise_solutions/q4a_iter_product.py b/exercise_solutions/q4a_iter_product.py new file mode 100755 index 0000000..84aa33c --- /dev/null +++ b/exercise_solutions/q4a_iter_product.py @@ -0,0 +1,16 @@ +#!/usr/bin/python3 + +def product(ip_iterable): + op = 1 + for n in ip_iterable: + op *= n + return op + +assert product([1, 4, 21]) == 84 +assert product([-4, 2.3e12, 77.23, 982, 0b101]) == -3.48863356e+18 +assert product((-3, 11, 2)) == -66 +assert product({8, 300}) == 2400 +assert product([234, 121, 23, 945, 0]) == 0 +assert product(range(1, 6)) == 120 + +print('all tests passed') diff --git a/exercise_solutions/q4b_lowest_value.py b/exercise_solutions/q4b_lowest_value.py new file mode 100755 index 0000000..7850568 --- /dev/null +++ b/exercise_solutions/q4b_lowest_value.py @@ -0,0 +1,16 @@ +#!/usr/bin/python3 + +def nth_lowest(ip_iterable, n=1): + return sorted(set(ip_iterable))[n-1] + +nums = [42, 23421341, 234.2e3, 21, 232, 12312, -2343] +assert nth_lowest(nums, 3) == 42 +assert nth_lowest(nums, 5) == 12312 + +nums = [1, -2, 4, 2, 1, 3, 3, 5] +assert nth_lowest(nums) == -2 +assert nth_lowest(nums, 4) == 3 + +assert nth_lowest('unrecognizable', 3) == 'c' + +print('all tests passed') diff --git a/exercise_solutions/q5a_col_sum.py b/exercise_solutions/q5a_col_sum.py new file mode 100755 index 0000000..13cea40 --- /dev/null +++ b/exercise_solutions/q5a_col_sum.py @@ -0,0 +1,15 @@ +#!/usr/bin/python3 + +with open('f1.txt', 'r', encoding='ascii') as f: + total = 0 + for line in f: + num = int(line) if type(line) == int else float(line) + #try: + # num = int(line) + #except ValueError: + # num = float(line) + total += num + + assert total == 10485.14 + +print('test passed') diff --git a/exercise_solutions/q5b_sum_ints.py b/exercise_solutions/q5b_sum_ints.py new file mode 100755 index 0000000..9050aad --- /dev/null +++ b/exercise_solutions/q5b_sum_ints.py @@ -0,0 +1,14 @@ +#!/usr/bin/python3 + +import re + +with open('f2.txt', 'r', encoding='ascii') as f: + total = 0 + for line in f: + total += sum(int(n) for n in re.findall(r'\d+', line)) + + assert total == 2298 + +#assert sum(int(n) for n in re.findall(r'\d+', open('f2.txt', encoding='ascii').read())) == 2298 + +print('test passed') diff --git a/exercise_solutions/q6a_one_char_diff.py b/exercise_solutions/q6a_one_char_diff.py new file mode 100755 index 0000000..9cb26a5 --- /dev/null +++ b/exercise_solutions/q6a_one_char_diff.py @@ -0,0 +1,31 @@ +#!/usr/bin/python3 + +def is_one_char_diff(word1, word2): + if len(word1) != len(word2): + return False + + word1, word2 = word1.lower(), word2.lower() + for i in range(len(word1)): + if word1[0:i] + word1[i+1:] == word2[0:i] + word2[i+1:]: + return True + + return False + +assert is_one_char_diff('bar', 'car') +assert is_one_char_diff('bar', 'Bat') +assert is_one_char_diff('bar', 'bar') +assert is_one_char_diff('bar', 'baZ') +assert is_one_char_diff('A', 'b') + +assert not is_one_char_diff('a', '') +assert not is_one_char_diff('bar', 'bark') +assert not is_one_char_diff('bar', 'Art') +assert not is_one_char_diff('bar', 'bot') +assert not is_one_char_diff('ab', '') + +assert is_one_char_diff('Food', 'good') +assert is_one_char_diff('food', 'fold') +assert not is_one_char_diff('food', 'Foody') +assert not is_one_char_diff('food', 'fled') + +print('all tests passed') diff --git a/exercise_solutions/q6b_alpha_order.py b/exercise_solutions/q6b_alpha_order.py new file mode 100755 index 0000000..5badf74 --- /dev/null +++ b/exercise_solutions/q6b_alpha_order.py @@ -0,0 +1,23 @@ +#!/usr/bin/python3 + +def is_alpha_order(word): + word = word.lower() + return list(word) == sorted(word) or list(word) == sorted(word, reverse=True) + +assert is_alpha_order('bot') +assert is_alpha_order('art') +assert is_alpha_order('toe') +assert is_alpha_order('AborT') + +assert not is_alpha_order('are') +assert not is_alpha_order('boat') +assert not is_alpha_order('Flee') + +# sentence +def is_alpha_order_sentence(sentence): + return all(is_alpha_order(word) for word in sentence.split()) + +assert is_alpha_order_sentence('Toe got bit') +assert not is_alpha_order_sentence('All is well') + +print('all tests passed') diff --git a/exercise_solutions/q7_misc.py b/exercise_solutions/q7_misc.py new file mode 100755 index 0000000..f59d22f --- /dev/null +++ b/exercise_solutions/q7_misc.py @@ -0,0 +1,8 @@ +#!/usr/bin/python3 + +import subprocess +# provide path to your favorite media player and file to play +subprocess.call(['vlc', r'/path/to/file']) + +import webbrowser +webbrowser.open(r'https://github.com/learnbyexample/Python_Basics') From 768acc517bcb96cca7f7ef6d477695af8082e758 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Tue, 29 Aug 2017 13:05:18 +0530 Subject: [PATCH 07/54] added link to exercise_solutions directory --- Exercises.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Exercises.md b/Exercises.md index 77bbc0e..548c9de 100644 --- a/Exercises.md +++ b/Exercises.md @@ -319,3 +319,9 @@ False **Q7a)** Play a song (**hint** use `subprocess` module) **Q7b)** Open a browser along with any link, for ex: https://github.com/learnbyexample/Python_Basics (**hint** use `webbrowser` module) + +
+ +
+ +For reference solutions, see [exercise_solutions](https://github.com/learnbyexample/Python_Basics/tree/master/exercise_solutions) directory From 30e55a88ce4813d16933faf71432e18fe2dcd37c Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Tue, 29 Aug 2017 15:17:38 +0530 Subject: [PATCH 08/54] link to Levenshtein distance wiki --- Exercises.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Exercises.md b/Exercises.md index 548c9de..3699732 100644 --- a/Exercises.md +++ b/Exercises.md @@ -257,6 +257,8 @@ $ ./extract_sum.py **Q6a)** Check if two words are same or differ by only one character (irrespective of case), input strings should have same length +See also [Levenshtein distance](https://en.wikipedia.org/wiki/Levenshtein_distance) + ```python >>> is_one_char_diff('bar', 'bar') True From 9198178e1920aee3ab8be5b0f304f3e2be6c9c96 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Sun, 24 Sep 2017 20:01:31 +0530 Subject: [PATCH 09/54] deleting list elements with slicing notation --- Lists.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Lists.md b/Lists.md index c436fe3..143acb6 100644 --- a/Lists.md +++ b/Lists.md @@ -301,10 +301,14 @@ IndexError: list index out of range * using [del](https://docs.python.org/3/reference/simple_stmts.html#del) to delete elements ```python ->>> books = ['Harry Potter', 'Sherlock Holmes', 'To Kill a Mocking Bird'] ->>> del books[1] ->>> books -['Harry Potter', 'To Kill a Mocking Bird'] +>>> nums = [1.2, -0.2, 0, 2, 4, 23] +>>> del nums[1] +>>> nums +[1.2, 0, 2, 4, 23] +# can use slicing notation as well +>>> del nums[1:4] +>>> nums +[1.2, 23] >>> list_2D = [[1, 3, 2, 10], [1.2, -0.2, 0, 2]] >>> del list_2D[0][1] From dbbeb976e6fadf8c71d2920fb4abcb65aa28981f Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Sun, 1 Oct 2017 14:23:28 +0530 Subject: [PATCH 10/54] Update Sequence_Set_Dict_data_types.md --- Sequence_Set_Dict_data_types.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Sequence_Set_Dict_data_types.md b/Sequence_Set_Dict_data_types.md index 4efa0db..d8ef979 100644 --- a/Sequence_Set_Dict_data_types.md +++ b/Sequence_Set_Dict_data_types.md @@ -384,3 +384,4 @@ Try the 'East' speciality 'rosgulla' today * [Python docs - dict](https://docs.python.org/3/library/stdtypes.html#dict) * [Python docs - pprint](https://docs.python.org/3/library/pprint.html) +* [detailed tutorial on dict](http://www.sharats.me/posts/the-python-dictionary/) From c4e6af530b093f01bbf75f9b01941953aa118a91 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Tue, 10 Oct 2017 21:22:55 +0530 Subject: [PATCH 11/54] some more details on tuple --- Sequence_Set_Dict_data_types.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Sequence_Set_Dict_data_types.md b/Sequence_Set_Dict_data_types.md index d8ef979..b5c8d50 100644 --- a/Sequence_Set_Dict_data_types.md +++ b/Sequence_Set_Dict_data_types.md @@ -5,8 +5,8 @@ * [Set](#set) * [Dictionary](#dictionary) -We have already seen Sequence types in previous chapters - strings, ranges and lists -We'll see some more operations on strings followed by Tuple, Set and Dict types in this chapter +We have already seen Sequence types in previous chapters - strings, ranges and lists. Tuple is another sequence type +We'll see some more operations on strings followed by Tuple, Set and Dict in this chapter
@@ -100,7 +100,8 @@ True ### Tuples -* Tuples can be thought of as sort of lists but immutable +* Tuples are similar to lists but immutable and useful in other ways too +* Individual elements can be both mutable/immutable ```python >>> north_dishes = ('Aloo tikki', 'Baati', 'Khichdi', 'Makki roti', 'Poha') @@ -163,6 +164,15 @@ Poha >>> b 5 +>>> c = 'foo' +>>> a, b, c = c, a, b +>>> a +'foo' +>>> b +20 +>>> c +5 + >>> def min_max(arr): ... return min(arr), max(arr) ... @@ -212,6 +222,7 @@ Poha ``` * [Python docs - tuple](https://docs.python.org/3/library/stdtypes.html#tuple) +* [Python docs - tuple tutorial](https://docs.python.org/3/tutorial/datastructures.html#tuples-and-sequences)
From 7bdac9d07875f609d4360d5f3c75e6c153a380c2 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Wed, 11 Oct 2017 16:47:51 +0530 Subject: [PATCH 12/54] clarified and added links for exception handling --- Exception_Handling_and_Debugging.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Exception_Handling_and_Debugging.md b/Exception_Handling_and_Debugging.md index 0ae2379..be784d1 100644 --- a/Exception_Handling_and_Debugging.md +++ b/Exception_Handling_and_Debugging.md @@ -37,7 +37,7 @@ while True: print("Square of entered number is: {}".format(usr_num * usr_num)) ``` -* `except` can be used for particular error (in this case `ValueError`) or without argument to handle any kind of error +* `except` can be used for particular error (in this case `ValueError`) ``` $ ./user_input_exception.py @@ -51,9 +51,10 @@ Square of entered number is: 9 **Further Reading** -* [Python docs - errors and exception handling](https://docs.python.org/3/tutorial/errors.html) -* [Python docs - raising exceptions](https://docs.python.org/3/tutorial/errors.html#raising-exceptions) +* [Python docs - errors, exception handling and raising exceptions](https://docs.python.org/3/tutorial/errors.html) * [Python docs - built-in exceptions](https://docs.python.org/3/library/exceptions.html#bltin-exceptions) +* [stackoverflow - exception message capturing](https://stackoverflow.com/questions/4690600/python-exception-message-capturing) +* [stackoverflow - avoid bare exceptions](https://stackoverflow.com/questions/14797375/should-i-always-specify-an-exception-type-in-except-statements) * [Python docs - pass statement](https://docs.python.org/3/reference/simple_stmts.html#grammar-token-pass_stmt)
From 0b1448136a07845724db53329db5a55afa657210 Mon Sep 17 00:00:00 2001 From: learnbyexample Date: Mon, 27 Nov 2017 12:20:25 +0530 Subject: [PATCH 13/54] exercise file and solution for max nested --- exercise_files/q6c_max_nested.py | 42 +++++++++++++++++++++ exercise_solutions/q6c_max_nested.py | 55 ++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100755 exercise_files/q6c_max_nested.py create mode 100755 exercise_solutions/q6c_max_nested.py diff --git a/exercise_files/q6c_max_nested.py b/exercise_files/q6c_max_nested.py new file mode 100755 index 0000000..ffb86c8 --- /dev/null +++ b/exercise_files/q6c_max_nested.py @@ -0,0 +1,42 @@ +#!/usr/bin/python3 + +def max_nested_braces(expr): + pass + +assert max_nested_braces('a*b') == 0 +assert max_nested_braces('a*b{') == -1 +assert max_nested_braces('a*{b+c}') == 1 +assert max_nested_braces('{a+2}*{b+c}') == 1 +assert max_nested_braces('a*{b+c*{e*3.14}}') == 2 +assert max_nested_braces('a*{b+c*{e*3.14}}}') == -1 +assert max_nested_braces('a*{b+c}}') == -1 +assert max_nested_braces('a*b+{}') == 1 +assert max_nested_braces('}a+b{') == -1 +assert max_nested_braces('{{a+2}*{b+c}+e}') == 2 +assert max_nested_braces('{{a+2}*{b+{c*d}}+e}') == 3 +assert max_nested_braces('{{a+2}*{{b+{c*d}}+e*d}}') == 4 +assert max_nested_braces('{{a+2}*{{b}+{c*d}}+e*d}}') == -1 + +print('all tests passed') + + +#### alternate using regular expressions + +#import re +# +#def max_nested_braces(expr): +# count = 0 +# while True: +# expr_sub = re.sub(r'\{[^{}]*\}', '', expr) +# if expr_sub == expr: +# break +# count += 1 +# expr = expr_sub +# +# if re.search(r'[{}]', expr): +# return -1 +# return count + +# for bonus, use + instead of * +#assert max_nested_braces('a*b+{}') == -1 +#assert max_nested_braces('a*{b+{}+c*{e*3.14}}') == -1 diff --git a/exercise_solutions/q6c_max_nested.py b/exercise_solutions/q6c_max_nested.py new file mode 100755 index 0000000..d8eb657 --- /dev/null +++ b/exercise_solutions/q6c_max_nested.py @@ -0,0 +1,55 @@ +#!/usr/bin/python3 + +def max_nested_braces(expr): + max_count = count = 0 + for char in expr: + if char == '{': + count += 1 + if count > max_count: + max_count = count + elif char == '}': + if count == 0: + return -1 + count -= 1 + + if count != 0: + return -1 + return max_count + +assert max_nested_braces('a*b') == 0 +assert max_nested_braces('a*b{') == -1 +assert max_nested_braces('a*{b+c}') == 1 +assert max_nested_braces('{a+2}*{b+c}') == 1 +assert max_nested_braces('a*{b+c*{e*3.14}}') == 2 +assert max_nested_braces('a*{b+c*{e*3.14}}}') == -1 +assert max_nested_braces('a*{b+c}}') == -1 +assert max_nested_braces('a*b+{}') == 1 +assert max_nested_braces('}a+b{') == -1 +assert max_nested_braces('{{a+2}*{b+c}+e}') == 2 +assert max_nested_braces('{{a+2}*{b+{c*d}}+e}') == 3 +assert max_nested_braces('{{a+2}*{{b+{c*d}}+e*d}}') == 4 +assert max_nested_braces('{{a+2}*{{b}+{c*d}}+e*d}}') == -1 + +print('all tests passed') + + +#### alternate using regular expressions + +#import re +# +#def max_nested_braces(expr): +# count = 0 +# while True: +# expr_sub = re.sub(r'\{[^{}]*\}', '', expr) +# if expr_sub == expr: +# break +# count += 1 +# expr = expr_sub +# +# if re.search(r'[{}]', expr): +# return -1 +# return count + +# for bonus, use + instead of * +#assert max_nested_braces('a*b+{}') == -1 +#assert max_nested_braces('a*{b+{}+c*{e*3.14}}') == -1 From 722d93e6e9d50fb8331fed2d7957356405c2964c Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Mon, 27 Nov 2017 12:22:06 +0530 Subject: [PATCH 14/54] removed unnecessary comments --- exercise_files/q6c_max_nested.py | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/exercise_files/q6c_max_nested.py b/exercise_files/q6c_max_nested.py index ffb86c8..13be372 100755 --- a/exercise_files/q6c_max_nested.py +++ b/exercise_files/q6c_max_nested.py @@ -18,25 +18,3 @@ def max_nested_braces(expr): assert max_nested_braces('{{a+2}*{{b}+{c*d}}+e*d}}') == -1 print('all tests passed') - - -#### alternate using regular expressions - -#import re -# -#def max_nested_braces(expr): -# count = 0 -# while True: -# expr_sub = re.sub(r'\{[^{}]*\}', '', expr) -# if expr_sub == expr: -# break -# count += 1 -# expr = expr_sub -# -# if re.search(r'[{}]', expr): -# return -1 -# return count - -# for bonus, use + instead of * -#assert max_nested_braces('a*b+{}') == -1 -#assert max_nested_braces('a*{b+{}+c*{e*3.14}}') == -1 From deeb2b0052d2c283d44e1279400e5b200b5fb71e Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Mon, 27 Nov 2017 12:25:17 +0530 Subject: [PATCH 15/54] added exercise to find max nested depth of braces --- Exercises.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Exercises.md b/Exercises.md index 3699732..7e7ca8d 100644 --- a/Exercises.md +++ b/Exercises.md @@ -314,6 +314,36 @@ True False ``` +**Q6c)** Find the maximum nested depth of curly braces + +Unbalanced or wrongly ordered braces should return `-1` + +Iterating over input string is one way to solve this, another is to use regular expressions + +```python +>>> max_nested_braces('a*b') +0 +>>> max_nested_braces('{a+2}*{b+c}') +1 +>>> max_nested_braces('{{a+2}*{{b+{c*d}}+e*d}}') +4 +>>> max_nested_braces('a*b+{}') +1 +>>> max_nested_braces('}a+b{') +-1 +>>> max_nested_braces('a*b{') +-1 +``` + +*bonus*: empty braces, i.e `{}` should return `-1` + +```python +>>> max_nested_braces('a*b+{}') +-1 +>>> max_nested_braces('a*{b+{}+c*{e*3.14}}') +-1 +``` +
## 7) Misc From 535545ddd58a84671898702d8fca9b712078c586 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Fri, 22 Dec 2017 18:03:27 +0530 Subject: [PATCH 16/54] examples for f-strings in Python v3.6 --- Functions.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/Functions.md b/Functions.md index d6a834d..22486dd 100644 --- a/Functions.md +++ b/Functions.md @@ -233,6 +233,8 @@ Error!! Not a valid input >>> op_fmt = '{} + {} = {}' >>> op_fmt.format(num1, num2, num1 + num2) '42 + 7 = 49' +>>> op_fmt.format(num1, 29, num1 + 29) +'42 + 29 = 71' # and of course the expression can be used inside print directly >>> print('{} + {} = {}'.format(num1, num2, num1 + num2)) @@ -306,7 +308,32 @@ Error!! Not a valid input 42 ``` +* similar to the `r` raw string prefix, using `f` prefix allows to represent format strings + * introduced in Python v3.6 +* similar to `str.format()`, the variables/expressions are specified within `{}` + +```python +>>> num1 = 42 +>>> num2 = 7 +>>> f'{num1} + {num2} = {num1 + num2}' +'42 + 7 = 49' +>>> print(f'{num1} + {num2} = {num1 + num2}') +42 + 7 = 49 + +>>> appx_pi = 22 / 7 +>>> f'{appx_pi:08.3f}' +'0003.143' + +>>> f'{20:x}' +'14' +>>> f'{20:#x}' +'0x14' +``` + +**Further Reading** + * [Python docs - formatstrings](https://docs.python.org/3/library/string.html#formatstrings) - for more info and examples +* [Python docs - f-strings](https://docs.python.org/3/reference/lexical_analysis.html#f-strings) - for more examples and caveats
From e583cc092cb6dd4371d07d42f4cfd9ce84348d98 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Tue, 26 Dec 2017 16:32:15 +0530 Subject: [PATCH 17/54] added examples for _ in numbers and f-strings --- Number_and_String_datatypes.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Number_and_String_datatypes.md b/Number_and_String_datatypes.md index 136ac7a..6785211 100644 --- a/Number_and_String_datatypes.md +++ b/Number_and_String_datatypes.md @@ -87,6 +87,23 @@ Variable data type is automatically determined by Python. They only need to be a 25 ``` +* `_` can be used between digits for readability + * introduced in Python v3.6 + +```bash +>>> 1_000_000 +1000000 +>>> 1_00.3_352 +100.3352 +>>> 0xff_ab1 +1047217 + +# f-strings formatting explained in a later chapter +>>> num = 34 ** 32 +>>> print(f'{num:_}') +10_170_102_859_315_411_774_579_628_461_341_138_023_025_901_305_856 +``` + **Further Reading** * [Python docs - numbers](https://docs.python.org/3/tutorial/introduction.html#numbers) @@ -162,6 +179,11 @@ Hello World >>> word = 'buffalo ' >>> print(word * 8) buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo + +# Python v3.6 allows variable interpolation with f-strings +>>> msg = f'{str1} there' +>>> msg +'Hello there' ``` * Triple quoted strings @@ -201,6 +223,7 @@ $ **Further Reading** * [Python docs - strings](https://docs.python.org/3/tutorial/introduction.html#strings) +* [Python docs - f-strings](https://docs.python.org/3/reference/lexical_analysis.html#f-strings) - for more examples and caveats * [Python docs - List of Escape Sequences and more info on strings](https://docs.python.org/3/reference/lexical_analysis.html#strings) * [Python docs - Binary Sequence Types](https://docs.python.org/3/library/stdtypes.html#binary-sequence-types-bytes-bytearray-memoryview) * [formatting triple quoted strings](https://stackoverflow.com/questions/3877623/in-python-can-you-have-variables-within-triple-quotes-if-so-how) From cbf164eaf8dbb679db08e885b074ee2bf835bd7d Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Tue, 26 Dec 2017 16:35:11 +0530 Subject: [PATCH 18/54] formatting --- Number_and_String_datatypes.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Number_and_String_datatypes.md b/Number_and_String_datatypes.md index 6785211..c6596d5 100644 --- a/Number_and_String_datatypes.md +++ b/Number_and_String_datatypes.md @@ -90,7 +90,7 @@ Variable data type is automatically determined by Python. They only need to be a * `_` can be used between digits for readability * introduced in Python v3.6 -```bash +```python >>> 1_000_000 1000000 >>> 1_00.3_352 @@ -291,5 +291,3 @@ True * [Python docs - Numeric types](https://docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex) - complete list of operations and precedence * [Python docs - String methods](https://docs.python.org/3/library/stdtypes.html#string-methods) - - From da09918a7f41d48d9e894c00b0ae7786a56dee90 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Fri, 29 Dec 2017 17:59:48 +0530 Subject: [PATCH 19/54] Create pcalc.py --- mini_projects/pcalc.py | 55 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 mini_projects/pcalc.py diff --git a/mini_projects/pcalc.py b/mini_projects/pcalc.py new file mode 100644 index 0000000..3b0a50b --- /dev/null +++ b/mini_projects/pcalc.py @@ -0,0 +1,55 @@ +#!/usr/bin/python3 + +""" +eval is used, so use at your own risk + +Examples: +$ ./pcalc.py -vx '0b101 + 3' +0b101 + 3 = 0x8 +$ ./pcalc.py '0x23' +35 +$ ./pcalc.py -f2 '76/13' +5.85 +$ ./pcalc.py '27**12' +150094635296999121 +$ echo '97 + 232' | ./pcalc.py +329 + +$ ./pcalc.py '42 + 2s' +Error: Not a valid input expression +""" + +import argparse, sys, fileinput + +parser = argparse.ArgumentParser() +parser.add_argument('arith_expr', nargs='?', default=sys.stdin, help="arithmetic expression") +parser.add_argument('-v', help="verbose, show both input and output in result", action="store_true") +parser.add_argument('-f', type=int, help="specify floating point output precision") +parser.add_argument('-b', help="output in binary format", action="store_true") +parser.add_argument('-o', help="output in octal format", action="store_true") +parser.add_argument('-x', help="output in hexadecimal format", action="store_true") +args = parser.parse_args() + +if type(args.arith_expr) != str: + args.arith_expr = fileinput.input().readline().strip() +ip_expr = args.arith_expr + +try: + result = eval(ip_expr) + + if args.f: + result = "{0:.{1}f}".format(result, args.f) + elif args.b: + result = "{:#b}".format(int(result)) + elif args.o: + result = "{:#o}".format(int(result)) + elif args.x: + result = "{:#x}".format(int(result)) + + if args.v: + print("{} = {}".format(args.arith_expr, result)) + else: + print(result) +except (NameError, SyntaxError) as e: + sys.exit("Error: Not a valid input expression") + From 95eb558ab48c3d8cda983a0f7748f0e4f790d0f6 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Tue, 20 Feb 2018 18:02:30 +0530 Subject: [PATCH 20/54] added exercise to return number from string --- Exercises.md | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/Exercises.md b/Exercises.md index 7e7ca8d..8e5b31d 100644 --- a/Exercises.md +++ b/Exercises.md @@ -49,10 +49,7 @@ College : PSG Tech # bonus: handle -ve numbers and check for input type >>> len_int(-42) 2 ->>> len_int('a') -Traceback (most recent call last): - File "", line 1, in - File "", line 3, in len_int +# len_int('a') should give TypeError: provide only integer input ``` @@ -80,6 +77,44 @@ False True ``` +**Q2d)** Returns corresponding integer or floating-point number (See [Number and String data types](./Number_and_String_datatypes.md) chapter for details) + +```python +# number input +>>> num(3) +3 +>>> num(0x1f) +31 +>>> num(3.32) +3.32 + +# string input +>>> num('123') +123 +>>> num('-78') +-78 +>>> num(" 42 \n ") +42 +>>> num('3.14') +3.14 +>>> num('3.982e5') +398200.0 + +>>> s = '56' +>>> num(s) + 44 +100 +``` + +Other than integer or floating, only string data type should be accepted. Also, provide custom error message if input cannot be converted + +```python +# num(['1', '2.3']) +TypeError: provide only string input + +# num('foo') +ValueError: could not convert string to int or float +``` +
## 3) Control structures From 0d1f355b08456ead8a18d81d2ef815abec79e251 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Tue, 20 Feb 2018 18:14:44 +0530 Subject: [PATCH 21/54] solution for returning number exercise --- exercise_solutions/q2d_to_num.py | 42 ++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 exercise_solutions/q2d_to_num.py diff --git a/exercise_solutions/q2d_to_num.py b/exercise_solutions/q2d_to_num.py new file mode 100644 index 0000000..900b65c --- /dev/null +++ b/exercise_solutions/q2d_to_num.py @@ -0,0 +1,42 @@ +#!/usr/bin/python3 + +def num(ip): + if type(ip) in (int, float): + return ip + elif type(ip) != str: + raise TypeError('provide only string input') + + try: + return int(ip) + except ValueError: + try: + return float(ip) + except ValueError: + raise ValueError('could not convert string to int or float') + +assert num(3) == 3 +assert num(0x1f) == 31 +assert num(0b101) == 5 +assert num(0o10) == 8 +assert num(3.32) == 3.32 +assert num('123') == 123 +assert num('-78') == -78 +assert num(" 42 \n ") == 42 +assert num('3.14') == 3.14 +assert num('3.982e5') == 398200.0 +s = '56' +assert num(s) + 44 == 100 +s = '8' * 10 +assert num(s) == 8888888888 + +try: + assert num('foo') +except ValueError as e: + assert str(e) == 'could not convert string to int or float' + +try: + assert num(['1', '2.3']) +except TypeError as e: + assert str(e) == 'provide only string input' + +print('all tests passed') From fec6799178584fca4227f98e75f3573c77c6dc8d Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Tue, 20 Feb 2018 18:17:33 +0530 Subject: [PATCH 22/54] testing file for returning number exercise --- exercise_files/q2d_to_num.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 exercise_files/q2d_to_num.py diff --git a/exercise_files/q2d_to_num.py b/exercise_files/q2d_to_num.py new file mode 100644 index 0000000..c5494dd --- /dev/null +++ b/exercise_files/q2d_to_num.py @@ -0,0 +1,31 @@ +#!/usr/bin/python3 + +def num(ip): + pass + +assert num(3) == 3 +assert num(0x1f) == 31 +assert num(0b101) == 5 +assert num(0o10) == 8 +assert num(3.32) == 3.32 +assert num('123') == 123 +assert num('-78') == -78 +assert num(" 42 \n ") == 42 +assert num('3.14') == 3.14 +assert num('3.982e5') == 398200.0 +s = '56' +assert num(s) + 44 == 100 +s = '8' * 10 +assert num(s) == 8888888888 + +try: + assert num('foo') +except ValueError as e: + assert str(e) == 'could not convert string to int or float' + +try: + assert num(['1', '2.3']) +except TypeError as e: + assert str(e) == 'provide only string input' + +print('all tests passed') From 21c596281157b2ec679277988befdb4454a08b58 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Mon, 5 Mar 2018 17:27:28 +0530 Subject: [PATCH 23/54] regex table description correction, formatting --- Text_Processing.md | 58 +++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/Text_Processing.md b/Text_Processing.md index f89031a..e165676 100644 --- a/Text_Processing.md +++ b/Text_Processing.md @@ -230,49 +230,49 @@ False | Meta characters | Description | | ------------- | ----------- | -| ^ | anchor, match from beginning of string | -| $ | anchor, match end of string | -| . | Match any character except newline character \n | +| `^` | anchor, match from beginning of string | +| `$` | anchor, match end of string | +| `.` | Match any character except newline character `\n` | | | | OR operator for matching multiple patterns | -| () | for grouping patterns and also extraction | -| [] | Character class - match one character among many | -| \^ | use \ to match meta characters like ^ | +| `()` | for grouping patterns and also extraction | +| `[]` | Character class - match one character among many | +| `\^` | prefix `\` to match meta characters like `^` |
| Quantifiers | Description | | ------------- | ----------- | -| * | Match zero or more times the preceding character | -| + | Match one or more times the preceding character | -| ? | Match zero or one times the preceding character | -| {n} | Match exactly n times | -| {n,} | Match at least n times | -| {n,m} | Match at least n times but not more than m times | +| `*` | Match zero or more times the preceding character | +| `+` | Match one or more times the preceding character | +| `?` | Match zero or one times the preceding character | +| `{n}` | Match exactly n times | +| `{n,}` | Match at least n times | +| `{n,m}` | Match at least n times but not more than m times |
| Character classes | Description | | ------------- | ----------- | -| [aeiou] | Match any vowel | -| \[^aeiou] | ^ inverts selection, so this matches any consonant | -| [a-f] | Match any of abcdef character | -| \d | Match a digit, same as [0-9] | -| \D | Match non-digit, same as \[^0-9] or \[^\d] | -| \w | Match alphanumeric and underscore character, same as [a-zA-Z_] | -| \W | Match non-alphanumeric and underscore character, same as \[^a-zA-Z_] or \[^\w] | -| \s | Match white-space character, same as [\ \t\n\r\f\v] | -| \S | Match non white-space character, same as \[^\s] | -| \b | word boundary, word defined as sequence of alphanumeric characters | -| \B | not a word boundary | +| `[aeiou]` | Match any vowel | +| `[^aeiou]` | `^` inverts selection, so this matches any consonant | +| `[a-f]` | Match any of abcdef character | +| `\d` | Match a digit, same as `[0-9]` | +| `\D` | Match non-digit, same as `[^0-9]` or `[^\d]` | +| `\w` | Match alphanumeric and underscore character, same as `[a-zA-Z0-9_]` | +| `\W` | Match non-alphanumeric and underscore character, same as `[^a-zA-Z0-9_]` or `[^\w]` | +| `\s` | Match white-space character, same as `[\ \t\n\r\f\v]` | +| `\S` | Match non white-space character, same as `[^\s]` | +| `\b` | word boundary, see `\w` for characters constituting a word | +| `\B` | not a word boundary |
| Compilation Flags | Description | | ------------- | ----------- | -| re.I | ignore case | -| re.M | multiline mode, ^ and $ anchors work on internal lines | -| re.S | singleline mode, . will also match \n | -| re.V | verbose mode, for better readability and adding comments | +| `re.I` | ignore case | +| `re.M` | multiline mode, `^` and `$` anchors work on internal lines | +| `re.S` | singleline mode, `.` will also match `\n` | +| `re.V` | verbose mode, for better readability and adding comments | * [Python docs - Compilation Flags](https://docs.python.org/3/howto/regex.html#compilation-flags) - for more details and long names for flags @@ -280,8 +280,8 @@ False | Variable | Description | | ------------- | ----------- | -| \1, \2, \3 etc | backreferencing matched patterns | -| \g<1>, \g<2>, \g<3> etc | backreferencing matched patterns, useful to differentiate numbers and backreferencing | +| `\1`, `\2`, `\3` etc | backreferencing matched patterns | +| `\g<1>`, `\g<2>`, `\g<3>` etc | backreferencing matched patterns, useful to differentiate numbers and backreferencing |
From cecca579bd8ebddbc17252d8ce2f8ab3450abdda Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Mon, 19 Mar 2018 16:53:50 +0530 Subject: [PATCH 24/54] added another test case --- exercise_solutions/q2c_str_same_letters.py | 1 + 1 file changed, 1 insertion(+) diff --git a/exercise_solutions/q2c_str_same_letters.py b/exercise_solutions/q2c_str_same_letters.py index b236e54..cbca962 100755 --- a/exercise_solutions/q2c_str_same_letters.py +++ b/exercise_solutions/q2c_str_same_letters.py @@ -5,6 +5,7 @@ def str_anagram(s1, s2): assert str_anagram('god', 'Dog') assert str_anagram('beat', 'abet') +assert str_anagram('Tap', 'paT') assert not str_anagram('beat', 'table') assert not str_anagram('seat', 'teal') From c0d2968a8615c10175ede667f206b3cdd74005c9 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Mon, 19 Mar 2018 16:54:49 +0530 Subject: [PATCH 25/54] added another test case --- exercise_files/q2c_str_same_letters.py | 1 + 1 file changed, 1 insertion(+) diff --git a/exercise_files/q2c_str_same_letters.py b/exercise_files/q2c_str_same_letters.py index bbce388..15f3ec4 100755 --- a/exercise_files/q2c_str_same_letters.py +++ b/exercise_files/q2c_str_same_letters.py @@ -5,6 +5,7 @@ def str_anagram(s1, s2): assert str_anagram('god', 'Dog') assert str_anagram('beat', 'abet') +assert str_anagram('Tap', 'paT') assert not str_anagram('beat', 'table') assert not str_anagram('seat', 'teal') From 72ba59178947f7da58e626c26457fafef160dd70 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Mon, 19 Mar 2018 16:58:32 +0530 Subject: [PATCH 26/54] better suggestion for bonus part --- exercise_solutions/q3a_6by7.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/exercise_solutions/q3a_6by7.py b/exercise_solutions/q3a_6by7.py index 1b993b8..557cd47 100755 --- a/exercise_solutions/q3a_6by7.py +++ b/exercise_solutions/q3a_6by7.py @@ -21,11 +21,4 @@ def six_by_seven(num): ## bonus #for num in range(1, 101): -# if num % 42 == 0: -# print(num, 'Universe') -# elif num % 7 == 0: -# print(num, 'Good') -# elif num % 6 == 0: -# print(num, 'Food') -# else: -# print(num, 'Oops') +# print(num, six_by_seven(num)) From f68af4a16cf5aaef1f8646b4ca751a8025675127 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Mon, 19 Mar 2018 17:02:11 +0530 Subject: [PATCH 27/54] typo fixed and added another test case --- Exercises.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Exercises.md b/Exercises.md index 8e5b31d..179e989 100644 --- a/Exercises.md +++ b/Exercises.md @@ -73,6 +73,8 @@ False True >>> str_anagram('beat', 'table') False +>>> str_anagram('Tap', 'paT') +True >>> str_anagram('beat', 'abet') True ``` @@ -121,11 +123,11 @@ ValueError: could not convert string to int or float **Q3a)** Write a function that returns -* 'Good' for numbers divisable by 7 -* 'Food' for numbers divisable by 6 -* 'Universe' for numbers divisable by 42 +* 'Good' for numbers divisible by 7 +* 'Food' for numbers divisible by 6 +* 'Universe' for numbers divisible by 42 * 'Oops' for all other numbers -* Only one output, divisable by 42 takes precedence +* Only one output, divisible by 42 takes precedence ```python >>> six_by_seven(66) From c353dd192e3cb7ca92025e700f058055b7437a1b Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Tue, 20 Mar 2018 18:27:13 +0530 Subject: [PATCH 28/54] these exercises now on repl.it as well --- Exercises.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Exercises.md b/Exercises.md index 179e989..7a1d0bd 100644 --- a/Exercises.md +++ b/Exercises.md @@ -12,6 +12,8 @@ For some questions, Python program with assert statements is provided to automatically test your solution in the [exercise_files](https://github.com/learnbyexample/Python_Basics/tree/master/exercise_files) directory - for ex: [Q2a - length of integer numbers](https://github.com/learnbyexample/Python_Basics/blob/master/exercise_files/q2a_int_length.py). The directory also has sample input text files. +You can also solve these exercises on [repl.it](https://repl.it/community/classrooms/52626), with an option to submit them for review. +
## 1) Variables and Print From 569c3cacca97c1249174c5cd8a482f4f960d9c99 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Wed, 21 Mar 2018 14:08:36 +0530 Subject: [PATCH 29/54] fixed typo, changed exception msg --- exercise_solutions/q2d_to_num.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/exercise_solutions/q2d_to_num.py b/exercise_solutions/q2d_to_num.py index 900b65c..d5dd9b4 100644 --- a/exercise_solutions/q2d_to_num.py +++ b/exercise_solutions/q2d_to_num.py @@ -4,7 +4,7 @@ def num(ip): if type(ip) in (int, float): return ip elif type(ip) != str: - raise TypeError('provide only string input') + raise TypeError('not a valid input') try: return int(ip) @@ -30,13 +30,13 @@ def num(ip): assert num(s) == 8888888888 try: - assert num('foo') + num('foo') except ValueError as e: assert str(e) == 'could not convert string to int or float' try: - assert num(['1', '2.3']) + num(['1', '2.3']) except TypeError as e: - assert str(e) == 'provide only string input' + assert str(e) == 'not a valid input' print('all tests passed') From b545fd862aea04edf1483e2590fa2f39ed96837a Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Wed, 21 Mar 2018 14:09:23 +0530 Subject: [PATCH 30/54] fixed typo --- exercise_solutions/q2a_int_length.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercise_solutions/q2a_int_length.py b/exercise_solutions/q2a_int_length.py index db7e93b..99a1351 100755 --- a/exercise_solutions/q2a_int_length.py +++ b/exercise_solutions/q2a_int_length.py @@ -15,7 +15,7 @@ def len_int(n): assert len_int(962306349871524124750813401378124) == 33 try: - assert len_int('a') + len_int('a') except TypeError as e: assert str(e) == 'provide only integer input' From 00a104ec889df580fb56b01963aa18407ad4e409 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Wed, 21 Mar 2018 14:13:41 +0530 Subject: [PATCH 31/54] changed exception msg for Q2d --- Exercises.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Exercises.md b/Exercises.md index 7a1d0bd..04181c8 100644 --- a/Exercises.md +++ b/Exercises.md @@ -113,7 +113,7 @@ Other than integer or floating, only string data type should be accepted. Also, ```python # num(['1', '2.3']) -TypeError: provide only string input +TypeError: not a valid input # num('foo') ValueError: could not convert string to int or float From 891874f47ded07a8f8edc6ecb343d91ba921fe33 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Thu, 22 Mar 2018 10:42:06 +0530 Subject: [PATCH 32/54] simplified solution --- exercise_solutions/q5a_col_sum.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/exercise_solutions/q5a_col_sum.py b/exercise_solutions/q5a_col_sum.py index 13cea40..4df9956 100755 --- a/exercise_solutions/q5a_col_sum.py +++ b/exercise_solutions/q5a_col_sum.py @@ -3,12 +3,7 @@ with open('f1.txt', 'r', encoding='ascii') as f: total = 0 for line in f: - num = int(line) if type(line) == int else float(line) - #try: - # num = int(line) - #except ValueError: - # num = float(line) - total += num + total += float(line) assert total == 10485.14 From 5c3be25ce98df7935039a55c43a78d92633d29d5 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Mon, 26 Mar 2018 15:52:39 +0530 Subject: [PATCH 33/54] added alternate solution --- exercise_solutions/q5a_col_sum.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/exercise_solutions/q5a_col_sum.py b/exercise_solutions/q5a_col_sum.py index 4df9956..cefbf05 100755 --- a/exercise_solutions/q5a_col_sum.py +++ b/exercise_solutions/q5a_col_sum.py @@ -8,3 +8,6 @@ assert total == 10485.14 print('test passed') + +# for small files that can fit in memory +#total = sum(float(n) for n in open('f1.txt', encoding='ascii').readlines()) From 7ea543d75a404bd194ed02f564cef38493fcc3c7 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Thu, 29 Mar 2018 15:32:09 +0530 Subject: [PATCH 34/54] added Contributing guidelines --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 95c70df..98211ee 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Use [![Join the chat at https://gitter.im/learnbyexample/scripting_course](https://badges.gitter.im/learnbyexample/scripting_course.svg)](https://gitter.im/learnbyexample/scripting_course) if you need help, have suggestions, etc +[![Join the chat at https://gitter.im/learnbyexample/scripting_course](https://badges.gitter.im/learnbyexample/scripting_course.svg)](https://gitter.im/learnbyexample/scripting_course) [![support learnbyexample](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/learnbyexample/donate)
@@ -48,6 +48,18 @@ Introduction to Python - Syntax, working with Shell commands, Files, Text Proces
+## Contributing + +* Please open an issue for typos/bugs/suggestions/etc + * Even for pull requests, open an issue for discussion before submitting PRs + * or [gitter group chat](https://gitter.im/learnbyexample/scripting_course) for discussion as well as for help/mentorship +* Share the repo with friends/colleagues, on social media, etc to help reach other learners +* Contribute by donating on [liberapay](https://liberapay.com/learnbyexample/donate) +* In case you need to reach me, use [gitter private chat](https://gitter.im/learnbyexample) + * or mail me at `echo 'bGVhcm5ieWV4YW1wbGUubmV0QGdtYWlsLmNvbQo=' | base64 --decode` + +
+ # ebook * Read as ebook on [gitbook](https://learnbyexample.gitbooks.io/python-basics/content/index.html) @@ -59,6 +71,7 @@ Introduction to Python - Syntax, working with Shell commands, Files, Text Proces * [automatetheboringstuff](https://automatetheboringstuff.com/) for getting me started with Python * [/r/learnpython/](https://www.reddit.com/r/learnpython/) - helpful forum for beginners and experienced programmers alike +* [stackoverflow](https://stackoverflow.com/) - for getting answers to pertinent questions as well as sharpening skills by understanding and answering questions * [Devs and Hackers](http://devup.in/) - helpful slack group * [Weekly Coders, Hackers & All Tech related thread](https://www.reddit.com/r/india/search?q=Weekly+Coders%2C+Hackers+%26+All+Tech+related+thread+author%3Aavinassh&restrict_sr=on&sort=new&t=all) - for suggestions and critique From ec64fb8e203f3ea98427caeed0e061049ed7677c Mon Sep 17 00:00:00 2001 From: learnbyexample Date: Tue, 3 Apr 2018 12:58:25 +0530 Subject: [PATCH 35/54] added longest word exercise --- exercise_files/poem.txt | 4 ++++ exercise_files/q7c_longest_word.py | 14 ++++++++++++++ exercise_solutions/q7c_longest_word.py | 21 +++++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 exercise_files/poem.txt create mode 100755 exercise_files/q7c_longest_word.py create mode 100755 exercise_solutions/q7c_longest_word.py diff --git a/exercise_files/poem.txt b/exercise_files/poem.txt new file mode 100644 index 0000000..8eb2255 --- /dev/null +++ b/exercise_files/poem.txt @@ -0,0 +1,4 @@ +Roses are red, +Violets are blue, +Sugar is sweet, +And so are you. diff --git a/exercise_files/q7c_longest_word.py b/exercise_files/q7c_longest_word.py new file mode 100755 index 0000000..24cec7d --- /dev/null +++ b/exercise_files/q7c_longest_word.py @@ -0,0 +1,14 @@ +#!/usr/bin/python3 + +def longest_word(): + pass + +ip_path = 'poem.txt' +assert longest_word(ip_path) == 'Violets' + +# The Scarlet Pimpernel +ip_path = 'https://www.gutenberg.org/files/60/60.txt' +assert longest_word(ip_path, True) == 'misunderstandings' + +print('all tests passed') + diff --git a/exercise_solutions/q7c_longest_word.py b/exercise_solutions/q7c_longest_word.py new file mode 100755 index 0000000..6286b2e --- /dev/null +++ b/exercise_solutions/q7c_longest_word.py @@ -0,0 +1,21 @@ +#!/usr/bin/python3 + +import urllib.request, re + +def longest_word(ip, url=False): + if url: + ip_data = urllib.request.urlopen(ip).read().decode('utf-8') + else: + ip_data = open(ip, encoding='utf-8').read() + + return sorted(re.findall(r'[a-zA-Z]+', ip_data), key=len)[-1] + +ip_path = 'poem.txt' +assert longest_word(ip_path) == 'Violets' + +# The Scarlet Pimpernel +ip_path = 'https://www.gutenberg.org/files/60/60.txt' +assert longest_word(ip_path, True) == 'misunderstandings' + +print('all tests passed') + From 49da1248199e34164a41f3226b4d39a1df2f3e18 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Tue, 3 Apr 2018 13:00:48 +0530 Subject: [PATCH 36/54] longest word exercise --- Exercises.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Exercises.md b/Exercises.md index 04181c8..cdc6565 100644 --- a/Exercises.md +++ b/Exercises.md @@ -391,6 +391,22 @@ Iterating over input string is one way to solve this, another is to use regular **Q7b)** Open a browser along with any link, for ex: https://github.com/learnbyexample/Python_Basics (**hint** use `webbrowser` module) +**Q7c)** Write a function that + +* accepts a filesystem path(default) or a url(indicated by True as second argument) +* returns the longest word(here word is defined as one or more consecutive sequence of alphabets of either case) +* assume that input encoding is **utf-8** and small enough to fit in memory and that there's only one distinct longest word + +```python +>>> ip_path = 'poem.txt' +>>> longest_word(ip_path) +'Violets' + +>>> ip_path = 'https://www.gutenberg.org/files/60/60.txt' +>>> longest_word(ip_path, True) +'misunderstandings' +``` +

From 45921aad2f8a15e36edb71f08255bac876fa5da4 Mon Sep 17 00:00:00 2001 From: learnbyexample Date: Sun, 8 Apr 2018 15:31:40 +0530 Subject: [PATCH 37/54] two more exercises --- exercise_files/f3.txt | 8 ++++++++ exercise_files/q4c_word_slices.py | 13 +++++++++++++ exercise_files/q5c_sort_by_ext.py | 13 +++++++++++++ exercise_solutions/f3.txt | 8 ++++++++ exercise_solutions/poem.txt | 4 ++++ exercise_solutions/q2d_to_num.py | 0 exercise_solutions/q4c_word_slices.py | 16 ++++++++++++++++ exercise_solutions/q5c_sort_by_ext.py | 14 ++++++++++++++ 8 files changed, 76 insertions(+) create mode 100644 exercise_files/f3.txt create mode 100755 exercise_files/q4c_word_slices.py create mode 100755 exercise_files/q5c_sort_by_ext.py create mode 100644 exercise_solutions/f3.txt create mode 100644 exercise_solutions/poem.txt mode change 100644 => 100755 exercise_solutions/q2d_to_num.py create mode 100755 exercise_solutions/q4c_word_slices.py create mode 100755 exercise_solutions/q5c_sort_by_ext.py diff --git a/exercise_files/f3.txt b/exercise_files/f3.txt new file mode 100644 index 0000000..0794f6f --- /dev/null +++ b/exercise_files/f3.txt @@ -0,0 +1,8 @@ +power.Log +foo.123.txt +list +report_12.log +baz.TXT +hello.RB +loop.do.rb +Fav_books diff --git a/exercise_files/q4c_word_slices.py b/exercise_files/q4c_word_slices.py new file mode 100755 index 0000000..562e6e7 --- /dev/null +++ b/exercise_files/q4c_word_slices.py @@ -0,0 +1,13 @@ +#!/usr/bin/python3 + +def word_slices(s): + pass + +assert word_slices('i') == ["i"] +assert word_slices('to') == ["to"] +assert word_slices('are') == ["ar", "are", "re"] +assert word_slices('boat') == ["bo", "boa", "boat", "oa", "oat", "at"] +assert word_slices('table') == ["ta", "tab", "tabl", "table", "ab", + "abl", "able", "bl", "ble", "le"] + +print('all tests passed') diff --git a/exercise_files/q5c_sort_by_ext.py b/exercise_files/q5c_sort_by_ext.py new file mode 100755 index 0000000..125ef2f --- /dev/null +++ b/exercise_files/q5c_sort_by_ext.py @@ -0,0 +1,13 @@ +#!/usr/bin/python3 + +def sort_by_ext(ip): + pass + +exp_op = ['Fav_books\n', 'list\n', 'power.Log\n', + 'report_12.log\n', 'hello.RB\n', 'loop.do.rb\n', + 'baz.TXT\n', 'foo.123.txt\n'] + +assert sort_by_ext('f3.txt') == exp_op + +print('test passed') + diff --git a/exercise_solutions/f3.txt b/exercise_solutions/f3.txt new file mode 100644 index 0000000..0794f6f --- /dev/null +++ b/exercise_solutions/f3.txt @@ -0,0 +1,8 @@ +power.Log +foo.123.txt +list +report_12.log +baz.TXT +hello.RB +loop.do.rb +Fav_books diff --git a/exercise_solutions/poem.txt b/exercise_solutions/poem.txt new file mode 100644 index 0000000..8eb2255 --- /dev/null +++ b/exercise_solutions/poem.txt @@ -0,0 +1,4 @@ +Roses are red, +Violets are blue, +Sugar is sweet, +And so are you. diff --git a/exercise_solutions/q2d_to_num.py b/exercise_solutions/q2d_to_num.py old mode 100644 new mode 100755 diff --git a/exercise_solutions/q4c_word_slices.py b/exercise_solutions/q4c_word_slices.py new file mode 100755 index 0000000..77dae84 --- /dev/null +++ b/exercise_solutions/q4c_word_slices.py @@ -0,0 +1,16 @@ +#!/usr/bin/python3 + +def word_slices(s): + size = len(s) + if size < 3: + return [s] + return [s[i:j+1] for i in range(size-1) for j in range(i+1, size)] + +assert word_slices('i') == ["i"] +assert word_slices('to') == ["to"] +assert word_slices('are') == ["ar", "are", "re"] +assert word_slices('boat') == ["bo", "boa", "boat", "oa", "oat", "at"] +assert word_slices('table') == ["ta", "tab", "tabl", "table", "ab", + "abl", "able", "bl", "ble", "le"] + +print('all tests passed') diff --git a/exercise_solutions/q5c_sort_by_ext.py b/exercise_solutions/q5c_sort_by_ext.py new file mode 100755 index 0000000..208442c --- /dev/null +++ b/exercise_solutions/q5c_sort_by_ext.py @@ -0,0 +1,14 @@ +#!/usr/bin/python3 + +def sort_by_ext(ip): + lines = open(ip, encoding='ascii').readlines() + return sorted(lines, key=lambda x: (x.split('.')[-1].lower(), x.lower())) + +exp_op = ['Fav_books\n', 'list\n', 'power.Log\n', + 'report_12.log\n', 'hello.RB\n', 'loop.do.rb\n', + 'baz.TXT\n', 'foo.123.txt\n'] + +assert sort_by_ext('f3.txt') == exp_op + +print('test passed') + From e3ba4c0780be12612b48d66376d729ce15c9038f Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Sun, 8 Apr 2018 15:44:02 +0530 Subject: [PATCH 38/54] added two more interesting exercises --- Exercises.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/Exercises.md b/Exercises.md index cdc6565..727358f 100644 --- a/Exercises.md +++ b/Exercises.md @@ -257,6 +257,24 @@ IndexError: list index out of range 'd' ``` +**Q4c)** Write a function that accepts a string input and returns slices + +* if input string is less than 3 characters long, return a list with input string as the only element +* otherwise, return list with all string slices greater than 1 character long +* order of slices should be same as shown in examples below + +```python +>>> word_slices('i') +['i'] +>>> word_slices('to') +['to'] + +>>> word_slices('are') +['ar', 'are', 're'] +>>> word_slices('table') +['ta', 'tab', 'tabl', 'table', 'ab', 'abl', 'able', 'bl', 'ble', 'le'] +``` +
## 5) File @@ -290,6 +308,38 @@ $ ./extract_sum.py 2298 ``` +**Q5c)** Sort file contents in alphabetic order based on each line's extension + +* extension here is defined as the string after the last `.` in the line +* if line doesn't have a `.`, those lines should come before lines with `.` +* sorting should be case-insensitive +* use rest of string as tie-breaker if there are more than one line with same extension +* assume input file is ASCII encoded and small enough to fit in memory + +*bonus*: instead of printing results to stdout, change the input file itself with sorted result + +```bash +$ cat f3.txt +power.Log +foo.123.txt +list +report_12.log +baz.TXT +hello.RB +loop.do.rb +Fav_books + +$ ./sort_by_ext.py +Fav_books +list +power.Log +report_12.log +hello.RB +loop.do.rb +baz.TXT +foo.123.txt +``` +
## 6) Text processing From 452b9be112ba84f7a7e6813bc8e5a82e4999d605 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Mon, 21 May 2018 09:43:19 +0530 Subject: [PATCH 39/54] added type checking assertions --- exercise_files/q2d_to_num.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/exercise_files/q2d_to_num.py b/exercise_files/q2d_to_num.py index c5494dd..ff50091 100644 --- a/exercise_files/q2d_to_num.py +++ b/exercise_files/q2d_to_num.py @@ -18,6 +18,9 @@ def num(ip): s = '8' * 10 assert num(s) == 8888888888 +assert type(num('42')) == int +assert type(num('1.23')) == float + try: assert num('foo') except ValueError as e: From 20807a12c736809bdac05e09a9036d5d715d2f84 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Mon, 21 May 2018 09:44:01 +0530 Subject: [PATCH 40/54] added type checking assertions --- exercise_solutions/q2d_to_num.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/exercise_solutions/q2d_to_num.py b/exercise_solutions/q2d_to_num.py index d5dd9b4..d840f22 100755 --- a/exercise_solutions/q2d_to_num.py +++ b/exercise_solutions/q2d_to_num.py @@ -29,6 +29,9 @@ def num(ip): s = '8' * 10 assert num(s) == 8888888888 +assert type(num('42')) == int +assert type(num('1.23')) == float + try: num('foo') except ValueError as e: From a1f1374ecd0da96745d081025d1652bab4b8c26f Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Fri, 22 Jun 2018 20:16:08 +0530 Subject: [PATCH 41/54] notes and examples for Python v3.5/v3.6/v3.7 dict --- Sequence_Set_Dict_data_types.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Sequence_Set_Dict_data_types.md b/Sequence_Set_Dict_data_types.md index b5c8d50..8b5cba8 100644 --- a/Sequence_Set_Dict_data_types.md +++ b/Sequence_Set_Dict_data_types.md @@ -305,6 +305,7 @@ True ### Dictionary * `dict` types can be thought of as unordered list of `key:value` pairs or a named list of items +* up to Python v3.5 (and some implementations of v3.6) do not retain order of insertion of dict elements ```python >>> marks = {'Rahul' : 86, 'Ravi' : 92, 'Rohit' : 75} @@ -391,8 +392,35 @@ False Try the 'East' speciality 'rosgulla' today ``` +* From Python v3.7 onwards, dict implementation will retain insertion order + * some implementations like the reference CPython implementation for v3.6 also retains the insertion order + +```python +>>> marks = {'Rahul' : 86, 'Ravi' : 92, 'Rohit' : 75, 'Rajan': 79} +>>> marks +{'Rahul': 86, 'Ravi': 92, 'Rohit': 75, 'Rajan': 79} + +>>> for name, mark in marks.items(): +... print(f'{name:5s}: {mark}') +... +Rahul: 86 +Ravi : 92 +Rohit: 75 +Rajan: 79 + +>>> del marks['Ravi'] +>>> marks +{'Rahul': 86, 'Rohit': 75, 'Rajan': 79} + +>>> marks['Ranjit'] = 65 +>>> marks +{'Rahul': 86, 'Rohit': 75, 'Rajan': 79, 'Ranjit': 65} +``` + **Further Reading** * [Python docs - dict](https://docs.python.org/3/library/stdtypes.html#dict) * [Python docs - pprint](https://docs.python.org/3/library/pprint.html) * [detailed tutorial on dict](http://www.sharats.me/posts/the-python-dictionary/) +* [Using dict to eliminate duplicates while retaining order](https://twitter.com/raymondh/status/944125570534621185) + From 587c941619d1f9839cb5cff30d8c3380ffc5c47d Mon Sep 17 00:00:00 2001 From: learnbyexample Date: Wed, 5 Sep 2018 11:21:28 +0530 Subject: [PATCH 42/54] improved regex solution --- exercise_solutions/q6c_max_nested.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/exercise_solutions/q6c_max_nested.py b/exercise_solutions/q6c_max_nested.py index d8eb657..b022a79 100755 --- a/exercise_solutions/q6c_max_nested.py +++ b/exercise_solutions/q6c_max_nested.py @@ -40,11 +40,10 @@ def max_nested_braces(expr): #def max_nested_braces(expr): # count = 0 # while True: -# expr_sub = re.sub(r'\{[^{}]*\}', '', expr) -# if expr_sub == expr: +# expr, no_of_subs = re.subn(r'\{[^{}]*\}', '', expr) +# if no_of_subs == 0: # break # count += 1 -# expr = expr_sub # # if re.search(r'[{}]', expr): # return -1 From 3176fc4e97fbed199d8bcfdf14e0dcbcda6257ce Mon Sep 17 00:00:00 2001 From: learnbyexample Date: Tue, 9 Oct 2018 09:34:38 +0530 Subject: [PATCH 43/54] added patreon image --- images/become_a_patron_button.png | Bin 0 -> 3086 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/become_a_patron_button.png diff --git a/images/become_a_patron_button.png b/images/become_a_patron_button.png new file mode 100644 index 0000000000000000000000000000000000000000..291b7bcf265521a3d062024bc4f7df927ae60e8f GIT binary patch literal 3086 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 S8x99PkF}+}MV*;%;{O2Ee#b2U literal 0 HcmV?d00001 From d3419198847c3f0b3a29ee411179ce8fa372f6d5 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Tue, 9 Oct 2018 09:36:10 +0530 Subject: [PATCH 44/54] links to patreon --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 98211ee..6f875df 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,8 @@ -[![Join the chat at https://gitter.im/learnbyexample/scripting_course](https://badges.gitter.im/learnbyexample/scripting_course.svg)](https://gitter.im/learnbyexample/scripting_course) [![support learnbyexample](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/learnbyexample/donate) +

+ + + +


@@ -54,7 +58,7 @@ Introduction to Python - Syntax, working with Shell commands, Files, Text Proces * Even for pull requests, open an issue for discussion before submitting PRs * or [gitter group chat](https://gitter.im/learnbyexample/scripting_course) for discussion as well as for help/mentorship * Share the repo with friends/colleagues, on social media, etc to help reach other learners -* Contribute by donating on [liberapay](https://liberapay.com/learnbyexample/donate) +* Contribute by donating on [patreon](https://www.patreon.com/learnbyexample) or [liberapay](https://liberapay.com/learnbyexample/donate) * In case you need to reach me, use [gitter private chat](https://gitter.im/learnbyexample) * or mail me at `echo 'bGVhcm5ieWV4YW1wbGUubmV0QGdtYWlsLmNvbQo=' | base64 --decode` From 01fe71724340daf6cceb23ab5d72923ed020a427 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Fri, 22 Feb 2019 18:43:10 +0530 Subject: [PATCH 45/54] link to Regular Expressions book --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6f875df..82d8218 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Introduction to Python - Syntax, working with Shell commands, Files, Text Processing, and more... * Suitable for a one/two day workshop for Python beginners +* Visit [Python re(gex)?](https://github.com/learnbyexample/py_regular_expressions) repo for a book on regular expressions * [Python curated resources](https://github.com/learnbyexample/scripting_course/blob/master/Python_curated_resources.md) for more complete resources list, including tutorials for beginners * For more related resources, visit [scripting course](https://github.com/learnbyexample/scripting_course) From cfe6e7d3540f858fc0be1d9e8ee0d2e8245ecd22 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Fri, 22 Feb 2019 20:54:09 +0530 Subject: [PATCH 46/54] improved regex reference table and links --- Text_Processing.md | 57 +++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/Text_Processing.md b/Text_Processing.md index e165676..c661313 100644 --- a/Text_Processing.md +++ b/Text_Processing.md @@ -226,28 +226,34 @@ False ### Regular Expressions -* Handy reference of regular expression elements +* Handy reference of regular expression (RE) elements | Meta characters | Description | | ------------- | ----------- | -| `^` | anchor, match from beginning of string | -| `$` | anchor, match end of string | +| `\A` | anchors matching to beginning of string | +| `\Z` | anchors matching to end of string | +| `^` | anchors matching to beginning of line | +| `$` | anchors matching to end of line | | `.` | Match any character except newline character `\n` | | | | OR operator for matching multiple patterns | -| `()` | for grouping patterns and also extraction | +| `(RE)` | capturing group | +| `(?:RE)` | non-capturing group | | `[]` | Character class - match one character among many | -| `\^` | prefix `\` to match meta characters like `^` | +| `\^` | prefix `\` to literally match meta characters like `^` |
-| Quantifiers | Description | +| Greedy Quantifiers | Description | | ------------- | ----------- | -| `*` | Match zero or more times the preceding character | -| `+` | Match one or more times the preceding character | -| `?` | Match zero or one times the preceding character | +| `*` | Match zero or more times | +| `+` | Match one or more times | +| `?` | Match zero or one times | +| `{m,n}` | Match `m` to `n` times (inclusive) | +| `{m,}` | Match at least m times | +| `{,n}` | Match up to `n` times (including `0` times) | | `{n}` | Match exactly n times | -| `{n,}` | Match at least n times | -| `{n,m}` | Match at least n times but not more than m times | + +Appending a `?` to greedy quantifiers makes them non-greedy
@@ -255,7 +261,7 @@ False | ------------- | ----------- | | `[aeiou]` | Match any vowel | | `[^aeiou]` | `^` inverts selection, so this matches any consonant | -| `[a-f]` | Match any of abcdef character | +| `[a-f]` | `-` defines a range, so this matches any of abcdef characters | | `\d` | Match a digit, same as `[0-9]` | | `\D` | Match non-digit, same as `[^0-9]` or `[^\d]` | | `\w` | Match alphanumeric and underscore character, same as `[a-zA-Z0-9_]` | @@ -267,21 +273,22 @@ False
-| Compilation Flags | Description | +| Flags | Description | | ------------- | ----------- | -| `re.I` | ignore case | -| `re.M` | multiline mode, `^` and `$` anchors work on internal lines | -| `re.S` | singleline mode, `.` will also match `\n` | -| `re.V` | verbose mode, for better readability and adding comments | +| `re.I` | Ignore case | +| `re.M` | Multiline mode, `^` and `$` anchors work on lines | +| `re.S` | Singleline mode, `.` will also match `\n` | +| `re.V` | Verbose mode, for better readability and adding comments | -* [Python docs - Compilation Flags](https://docs.python.org/3/howto/regex.html#compilation-flags) - for more details and long names for flags +See [Python docs - Compilation Flags](https://docs.python.org/3/howto/regex.html#compilation-flags) for more details and long names for flags
| Variable | Description | | ------------- | ----------- | -| `\1`, `\2`, `\3` etc | backreferencing matched patterns | -| `\g<1>`, `\g<2>`, `\g<3>` etc | backreferencing matched patterns, useful to differentiate numbers and backreferencing | +| `\1`, `\2`, `\3` ... `\99` | backreferencing matched patterns | +| `\g<1>`, `\g<2>`, `\g<3>` ... | backreferencing matched patterns, prevents ambiguity | +| `\g<0>` | entire matched portion |
@@ -471,14 +478,16 @@ True ### Further Reading on Regular Expressions +* [Python re(gex)?](https://github.com/learnbyexample/py_regular_expressions) - a book on regular expressions * [Python docs - re module](https://docs.python.org/3/library/re.html) * [Python docs - introductory tutorial to using regular expressions](https://docs.python.org/3/howto/regex.html) -* [developers.google - Regular Expressions tutorial](https://developers.google.com/edu/python/regular-expressions) -* [automatetheboringstuff - Regular Expressions](https://automatetheboringstuff.com/chapter7/) * [Comprehensive reference: What does this regex mean?](https://stackoverflow.com/questions/22937618/reference-what-does-this-regex-mean) +* [rexegg](https://www.rexegg.com/) - tutorials, tricks and more +* [regular-expressions](https://www.regular-expressions.info/) - tutorials and tools +* [CommonRegex](https://github.com/madisonmay/CommonRegex) - collection of common regular expressions * Practice tools - * [online regex tester](https://regex101.com/#python) shows explanations, has reference guides and ability to save and share regex - * [regexone](http://regexone.com/) - interative tutorial + * [regex101](https://regex101.com/) - visual aid and online testing tool for regular expressions, select flavor as Python before use + * [regexone](https://regexone.com/) - interative tutorial * [cheatsheet](https://www.shortcutfoo.com/app/dojos/python-regex/cheatsheet) - one can also learn it [interactively](https://www.shortcutfoo.com/app/dojos/python-regex) * [regexcrossword](https://regexcrossword.com/) - practice by solving crosswords, read 'How to play' section before you start From b2adcd06838eb62d11be5b6fd87e9ef42db4748b Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Sat, 2 Mar 2019 12:33:33 +0530 Subject: [PATCH 47/54] updated regex examples and descriptions --- Text_Processing.md | 243 ++++++++++++++++++++++++++------------------- 1 file changed, 139 insertions(+), 104 deletions(-) diff --git a/Text_Processing.md b/Text_Processing.md index c661313..5e5ab88 100644 --- a/Text_Processing.md +++ b/Text_Processing.md @@ -294,11 +294,13 @@ See [Python docs - Compilation Flags](https://docs.python.org/3/howto/regex.html ### Pattern matching and extraction -* matching/extracting sequence of characters -* use `re.search()` to see if a string contains a pattern or not -* use `re.findall()` to get a list of matching patterns -* use `re.split()` to get a list from splitting a string based on a pattern -* their syntax given below +To match/extract sequence of characters, use + +* `re.search()` to see if input string contains a pattern or not +* `re.findall()` to get a list of all matching patterns +* `re.split()` to get a list from splitting input string based on a pattern + +Their syntax is as follows: ```python re.search(pattern, string, flags=0) @@ -306,71 +308,105 @@ re.findall(pattern, string, flags=0) re.split(pattern, string, maxsplit=0, flags=0) ``` +* As a good practice, always use **raw strings** to construct RE, unless other formats are required + * this will avoid clash of backslash escaping between RE and normal quoted strings +* examples for `re.search` + ```python ->>> import re ->>> string = "This is a sample string" +>>> sentence = 'This is a sample string' ->>> bool(re.search('is', string)) +# using normal string methods +>>> 'is' in sentence True - ->>> bool(re.search('this', string)) +>>> 'xyz' in sentence False ->>> bool(re.search('this', string, re.I)) -True - ->>> bool(re.search('T', string)) +# need to load the re module before use +>>> import re +# check if 'sentence' contains the pattern described by RE argument +>>> bool(re.search(r'is', sentence)) True - ->>> bool(re.search('is a', string)) +>>> bool(re.search(r'this', sentence, flags=re.I)) True - ->>> re.findall('i', string) -['i', 'i', 'i'] +>>> bool(re.search(r'xyz', sentence)) +False ``` -* using regular expressions -* use the `r''` format when using regular expression elements +* examples for `re.findall` ```python ->>> string -'This is a sample string' - ->>> re.findall('is', string) -['is', 'is'] - ->>> re.findall('\bis', string) -[] +# match whole word par with optional s at start and e at end +>>> re.findall(r'\bs?pare?\b', 'par spar apparent spare part pare') +['par', 'spar', 'spare', 'pare'] + +# numbers >= 100 with optional leading zeros +>>> re.findall(r'\b0*[1-9]\d{2,}\b', '0501 035 154 12 26 98234') +['0501', '154', '98234'] + +# if multiple capturing groups are used, each element of output +# will be a tuple of strings of all the capture groups +>>> re.findall(r'(x*):(y*)', 'xx:yyy x: x:yy :y') +[('xx', 'yyy'), ('x', ''), ('x', 'yy'), ('', 'y')] + +# normal capture group will hinder ability to get whole match +# non-capturing group to the rescue +>>> re.findall(r'\b\w*(?:st|in)\b', 'cost akin more east run against') +['cost', 'akin', 'east', 'against'] + +# useful for debugging purposes as well before applying substitution +>>> re.findall(r't.*?a', 'that is quite a fabricated tale') +['tha', 't is quite a', 'ted ta'] +``` ->>> re.findall(r'\bis', string) -['is'] +* examples for `re.split` ->>> re.findall(r'\w+', string) -['This', 'is', 'a', 'sample', 'string'] +```python +# split based on one or more digit characters +>>> re.split(r'\d+', 'Sample123string42with777numbers') +['Sample', 'string', 'with', 'numbers'] ->>> re.split(r'\s+', string) -['This', 'is', 'a', 'sample', 'string'] +# split based on digit or whitespace characters +>>> re.split(r'[\d\s]+', '**1\f2\n3star\t7 77\r**') +['**', 'star', '**'] ->>> re.split(r'\d+', 'Sample123string54with908numbers') -['Sample', 'string', 'with', 'numbers'] +# to include the matching delimiter strings as well in the output +>>> re.split(r'(\d+)', 'Sample123string42with777numbers') +['Sample', '123', 'string', '42', 'with', '777', 'numbers'] ->>> re.split(r'(\d+)', 'Sample123string54with908numbers') -['Sample', '123', 'string', '54', 'with', '908', 'numbers'] +# use non-capturing group if capturing is not needed +>>> re.split(r'hand(?:y|ful)', '123handed42handy777handful500') +['123handed42', '777', '500'] ``` * backreferencing ```python ->>> quote = "So many books, so little time" +# whole words that have at least one consecutive repeated character +>>> words = ['effort', 'flee', 'facade', 'oddball', 'rat', 'tool'] ->>> re.search(r'([a-z]{2,}).*\1', quote, re.I) -<_sre.SRE_Match object; span=(0, 17), match='So many books, so'> +>>> [w for w in words if re.search(r'\b\w*(\w)\1\w*\b', w)] +['effort', 'flee', 'oddball', 'tool'] +``` ->>> re.search(r'([a-z])\1', quote, re.I) -<_sre.SRE_Match object; span=(9, 11), match='oo'> +* The `re.search` function returns a `re.Match` object from which various details can be extracted +like the matched portion of string, location of matched portion, etc +* **Note** that output here is shown for Python version **3.7** ->>> re.findall(r'([a-z])\1', quote, re.I) -['o', 't'] +```python +>>> re.search(r'b.*d', 'abc ac adc abbbc') + +# retrieving entire matched portion +>>> re.search(r'b.*d', 'abc ac adc abbbc')[0] +'bc ac ad' + +# capture group example +>>> m = re.search(r'a(.*)d(.*a)', 'abc ac adc abbbc') +# to get matched portion of second capture group +>>> m[2] +'c a' +# to get a tuple of all the capture groups +>>> m.groups() +('bc ac a', 'c a') ```
@@ -383,55 +419,61 @@ True re.sub(pattern, repl, string, count=0, flags=0) ``` -* simple substitutions -* `re.sub` will not change value of variable passed to it, has to be explicity assigned +* examples +* **Note** that as strings are immutable, `re.sub` will not change value of variable +passed to it, has to be explicity assigned ```python ->>> sentence = 'This is a sample string' ->>> re.sub('sample', 'test', sentence) -'This is a test string' - ->>> sentence -'This is a sample string' ->>> sentence = re.sub('sample', 'test', sentence) ->>> sentence -'This is a test string' - ->>> re.sub('/', '-', '25/06/2016') -'25-06-2016' ->>> re.sub('/', '-', '25/06/2016', count=1) -'25-06/2016' - ->>> greeting = '***** Have a great day *****' ->>> re.sub('\*', '=', greeting) -'===== Have a great day =====' +>>> ip_lines = "catapults\nconcatenate\ncat" +>>> print(re.sub(r'^', r'* ', ip_lines, flags=re.M)) +* catapults +* concatenate +* cat + +# replace 'par' only at start of word +>>> re.sub(r'\bpar', r'X', 'par spar apparent spare part') +'X spar apparent spare Xt' + +# same as: r'part|parrot|parent' +>>> re.sub(r'par(en|ro)?t', r'X', 'par part parrot parent') +'par X X X' + +# remove first two columns where : is delimiter +>>> re.sub(r'\A([^:]+:){2}', r'', 'foo:123:bar:baz', count=1) +'bar:baz' ``` * backreferencing ```python ->>> words = 'night and day' ->>> re.sub(r'(\w+)( \w+ )(\w+)', r'\3\2\1', words) -'day and night' - ->>> line = 'Can you spot the the mistakes? I i seem to not' ->>> re.sub(r'\b(\w+) \1\b', r'\1', line, flags=re.I) -'Can you spot the mistakes? I seem to not' +# remove any number of consecutive duplicate words separated by space +# quantifiers can be applied to backreferences too! +>>> re.sub(r'\b(\w+)( \1)+\b', r'\1', 'a a a walking for for a cause') +'a walking for a cause' + +# add something around the matched strings +>>> re.sub(r'\d+', r'(\g<0>0)', '52 apples and 31 mangoes') +'(520) apples and (310) mangoes' + +# swap words that are separated by a comma +>>> re.sub(r'(\w+),(\w+)', r'\2,\1', 'a,b 42,24') +'b,a 24,42' ``` * using functions in replace part of `re.sub()` +* **Note** that Python version **3.7** is used here ```python ->>> import math +>>> from math import factorial >>> numbers = '1 2 3 4 5' - >>> def fact_num(n): -... return str(math.factorial(int(n.group(1)))) +... return str(factorial(int(n[0]))) ... ->>> re.sub(r'(\d+)', fact_num, numbers) +>>> re.sub(r'\d+', fact_num, numbers) '1 2 6 24 120' ->>> re.sub(r'(\d+)', lambda m: str(math.factorial(int(m.group(1)))), numbers) +# using lambda +>>> re.sub(r'\d+', lambda m: str(factorial(int(m[0]))), numbers) '1 2 6 24 120' ``` @@ -443,35 +485,28 @@ re.sub(pattern, repl, string, count=0, flags=0) ### Compiling Regular Expressions +* Regular expressions can be compiled using `re.compile` function, which gives back a +`re.Pattern` object +* The top level `re` module functions are all available as methods for this object +* Compiling a regular expression helps if the RE has to be used in multiple +places or called upon multiple times inside a loop (speed benefit) +* By default, Python maintains a small list of recently used RE, so the speed benefit +doesn't apply for trivial use cases + ```python ->>> swap_words = re.compile(r'(\w+)( \w+ )(\w+)') ->>> swap_words -re.compile('(\\w+)( \\w+ )(\\w+)') - ->>> words = 'night and day' - ->>> swap_words.search(words).group() -'night and day' ->>> swap_words.search(words).group(1) -'night' ->>> swap_words.search(words).group(2) -' and ' ->>> swap_words.search(words).group(3) -'day' ->>> swap_words.search(words).group(4) -Traceback (most recent call last): - File "", line 1, in -IndexError: no such group - ->>> bool(swap_words.search(words)) +>>> pet = re.compile(r'dog') +>>> type(pet) + +>>> bool(pet.search('They bought a dog')) True ->>> swap_words.findall(words) -[('night', ' and ', 'day')] +>>> bool(pet.search('A cat crossed their path')) +False ->>> swap_words.sub(r'\3\2\1', words) -'day and night' ->>> swap_words.sub(r'\3\2\1', 'yin and yang') -'yang and yin' +>>> remove_parentheses = re.compile(r'\([^)]*\)') +>>> remove_parentheses.sub('', 'a+b(addition) - foo() + c%d(#modulo)') +'a+b - foo + c%d' +>>> remove_parentheses.sub('', 'Hi there(greeting). Nice day(a(b)') +'Hi there. Nice day' ```
From 51a7157e46fc687b0e62c524eaabf9981010e657 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Fri, 9 Aug 2019 17:29:10 +0530 Subject: [PATCH 48/54] improved examples and added another resource link --- Text_Processing.md | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/Text_Processing.md b/Text_Processing.md index 5e5ab88..9033677 100644 --- a/Text_Processing.md +++ b/Text_Processing.md @@ -230,10 +230,10 @@ False | Meta characters | Description | | ------------- | ----------- | -| `\A` | anchors matching to beginning of string | -| `\Z` | anchors matching to end of string | -| `^` | anchors matching to beginning of line | -| `$` | anchors matching to end of line | +| `\A` | anchor to restrict matching to beginning of string | +| `\Z` | anchor to restrict matching to end of string | +| `^` | anchor to restrict matching to beginning of line | +| `$` | anchor to restrict matching to end of line | | `.` | Match any character except newline character `\n` | | | | OR operator for matching multiple patterns | | `(RE)` | capturing group | @@ -278,7 +278,7 @@ Appending a `?` to greedy quantifiers makes them non-greedy | `re.I` | Ignore case | | `re.M` | Multiline mode, `^` and `$` anchors work on lines | | `re.S` | Singleline mode, `.` will also match `\n` | -| `re.V` | Verbose mode, for better readability and adding comments | +| `re.X` | Verbose mode, for better readability and adding comments | See [Python docs - Compilation Flags](https://docs.python.org/3/howto/regex.html#compilation-flags) for more details and long names for flags @@ -290,6 +290,8 @@ See [Python docs - Compilation Flags](https://docs.python.org/3/howto/regex.html | `\g<1>`, `\g<2>`, `\g<3>` ... | backreferencing matched patterns, prevents ambiguity | | `\g<0>` | entire matched portion | +`\0` and `\100` onwards are considered as octal values, hence cannot be used as backreference. +
### Pattern matching and extraction @@ -297,7 +299,8 @@ See [Python docs - Compilation Flags](https://docs.python.org/3/howto/regex.html To match/extract sequence of characters, use * `re.search()` to see if input string contains a pattern or not -* `re.findall()` to get a list of all matching patterns +* `re.findall()` to get a list of all matching portions +* `re.finditer()` to get an iterator of `re.Match` objects of all matching portions * `re.split()` to get a list from splitting input string based on a pattern Their syntax is as follows: @@ -305,6 +308,7 @@ Their syntax is as follows: ```python re.search(pattern, string, flags=0) re.findall(pattern, string, flags=0) +re.finditer(pattern, string, flags=0) re.split(pattern, string, maxsplit=0, flags=0) ``` @@ -409,6 +413,21 @@ like the matched portion of string, location of matched portion, etc ('bc ac a', 'c a') ``` +* examples for `re.finditer` + +```python +>>> m_iter = re.finditer(r'(x*):(y*)', 'xx:yyy x: x:yy :y') +>>> [(m[1], m[2]) for m in m_iter] +[('xx', 'yyy'), ('x', ''), ('x', 'yy'), ('', 'y')] + +>>> m_iter = re.finditer(r'ab+c', 'abc ac adc abbbc') +>>> for m in m_iter: +... print(m.span()) +... +(0, 3) +(11, 16) +``` +
### Search and Replace @@ -448,8 +467,8 @@ passed to it, has to be explicity assigned ```python # remove any number of consecutive duplicate words separated by space # quantifiers can be applied to backreferences too! ->>> re.sub(r'\b(\w+)( \1)+\b', r'\1', 'a a a walking for for a cause') -'a walking for a cause' +>>> re.sub(r'\b(\w+)( \1)+\b', r'\1', 'aa a a a 42 f_1 f_1 f_13.14') +'aa a 42 f_1 f_13.14' # add something around the matched strings >>> re.sub(r'\d+', r'(\g<0>0)', '52 apples and 31 mangoes') @@ -522,6 +541,7 @@ False * [CommonRegex](https://github.com/madisonmay/CommonRegex) - collection of common regular expressions * Practice tools * [regex101](https://regex101.com/) - visual aid and online testing tool for regular expressions, select flavor as Python before use + * [debuggex](https://www.debuggex.com) - railroad diagrams for regular expressions, select flavor as Python before use * [regexone](https://regexone.com/) - interative tutorial * [cheatsheet](https://www.shortcutfoo.com/app/dojos/python-regex/cheatsheet) - one can also learn it [interactively](https://www.shortcutfoo.com/app/dojos/python-regex) * [regexcrossword](https://regexcrossword.com/) - practice by solving crosswords, read 'How to play' section before you start From e839101a2d71aebb42649025d4d46e9a6ee26719 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Wed, 28 Aug 2019 11:33:14 +0530 Subject: [PATCH 49/54] link to my programming blog --- README.md | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 82d8218..fada36b 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,11 @@ -

- - - -

- -
- # Python Basics Introduction to Python - Syntax, working with Shell commands, Files, Text Processing, and more... * Suitable for a one/two day workshop for Python beginners * Visit [Python re(gex)?](https://github.com/learnbyexample/py_regular_expressions) repo for a book on regular expressions -* [Python curated resources](https://github.com/learnbyexample/scripting_course/blob/master/Python_curated_resources.md) for more complete resources list, including tutorials for beginners -* For more related resources, visit [scripting course](https://github.com/learnbyexample/scripting_course) +* [Python curated resources](https://github.com/learnbyexample/scripting_course/blob/master/Python_curated_resources.md) for more complete resources list, including tutorials for complete beginners to programming +* For more related resources, visit [scripting course](https://github.com/learnbyexample/scripting_course) and my programming blog https://learnbyexample.github.io
@@ -59,7 +51,6 @@ Introduction to Python - Syntax, working with Shell commands, Files, Text Proces * Even for pull requests, open an issue for discussion before submitting PRs * or [gitter group chat](https://gitter.im/learnbyexample/scripting_course) for discussion as well as for help/mentorship * Share the repo with friends/colleagues, on social media, etc to help reach other learners -* Contribute by donating on [patreon](https://www.patreon.com/learnbyexample) or [liberapay](https://liberapay.com/learnbyexample/donate) * In case you need to reach me, use [gitter private chat](https://gitter.im/learnbyexample) * or mail me at `echo 'bGVhcm5ieWV4YW1wbGUubmV0QGdtYWlsLmNvbQo=' | base64 --decode` @@ -85,3 +76,4 @@ Introduction to Python - Syntax, working with Shell commands, Files, Text Proces # License This work is licensed under a [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-nc-sa/4.0/) + From 4ef9494df8cc0922c3b0677af2cc36df531402b1 Mon Sep 17 00:00:00 2001 From: learnbyexample Date: Wed, 28 Aug 2019 12:04:07 +0530 Subject: [PATCH 50/54] removed stale image --- images/become_a_patron_button.png | Bin 3086 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 images/become_a_patron_button.png diff --git a/images/become_a_patron_button.png b/images/become_a_patron_button.png deleted file mode 100644 index 291b7bcf265521a3d062024bc4f7df927ae60e8f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3086 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 S8x99PkF}+}MV*;%;{O2Ee#b2U From 99754def3bd0af387e6eea4e630c752ec0632de2 Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Tue, 10 Dec 2019 20:29:24 +0530 Subject: [PATCH 51/54] fixed typo --- exercise_files/q2a_int_length.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercise_files/q2a_int_length.py b/exercise_files/q2a_int_length.py index 658db59..f8898f4 100755 --- a/exercise_files/q2a_int_length.py +++ b/exercise_files/q2a_int_length.py @@ -11,7 +11,7 @@ def len_int(n): assert len_int(962306349871524124750813401378124) == 33 try: - assert len_int('a') + len_int('a') except TypeError as e: assert str(e) == 'provide only integer input' From 216b25a14a86f0ef1d1ab3478333aceec1d7e98f Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Tue, 10 Dec 2019 20:41:17 +0530 Subject: [PATCH 52/54] corrected assertion text as per question --- exercise_files/q2d_to_num.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercise_files/q2d_to_num.py b/exercise_files/q2d_to_num.py index ff50091..11a270c 100644 --- a/exercise_files/q2d_to_num.py +++ b/exercise_files/q2d_to_num.py @@ -29,6 +29,6 @@ def num(ip): try: assert num(['1', '2.3']) except TypeError as e: - assert str(e) == 'provide only string input' + assert str(e) == 'not a valid input' print('all tests passed') From 7d59ab944ff96ce76b6077813c301f9e463830ca Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Tue, 29 Sep 2020 14:55:18 +0530 Subject: [PATCH 53/54] links updated and added current status of this repo --- README.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index fada36b..b8012fa 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,15 @@ Introduction to Python - Syntax, working with Shell commands, Files, Text Proces * Suitable for a one/two day workshop for Python beginners * Visit [Python re(gex)?](https://github.com/learnbyexample/py_regular_expressions) repo for a book on regular expressions -* [Python curated resources](https://github.com/learnbyexample/scripting_course/blob/master/Python_curated_resources.md) for more complete resources list, including tutorials for complete beginners to programming +* [Python resources for everybody](https://learnbyexample.github.io/py_resources/) for a curated and searchable collection, including resources for complete beginners to programming * For more related resources, visit [scripting course](https://github.com/learnbyexample/scripting_course) and my programming blog https://learnbyexample.github.io +--- + +:warning: :warning: I'm no longer actively working on this repo. I'm archiving this repo for now, might come back later to update the book to newer Python version, add more content, etc. + +--- +
# Chapters @@ -48,18 +54,16 @@ Introduction to Python - Syntax, working with Shell commands, Files, Text Proces ## Contributing * Please open an issue for typos/bugs/suggestions/etc - * Even for pull requests, open an issue for discussion before submitting PRs - * or [gitter group chat](https://gitter.im/learnbyexample/scripting_course) for discussion as well as for help/mentorship + * As this repo is no longer actively worked upon, **please do not submit pull requests** * Share the repo with friends/colleagues, on social media, etc to help reach other learners -* In case you need to reach me, use [gitter private chat](https://gitter.im/learnbyexample) - * or mail me at `echo 'bGVhcm5ieWV4YW1wbGUubmV0QGdtYWlsLmNvbQo=' | base64 --decode` +* In case you need to reach me, mail me at `echo 'bGVhcm5ieWV4YW1wbGUubmV0QGdtYWlsLmNvbQo=' | base64 --decode` or send a DM via [twitter](https://twitter.com/learn_byexample)
# ebook * Read as ebook on [gitbook](https://learnbyexample.gitbooks.io/python-basics/content/index.html) -* Download ebook for offline reading - [link](https://www.gitbook.com/book/learnbyexample/python-basics/details) +* All `legacy.gitbook.com` links are now automatically redirected to `gitbook.com`, so there's no longer an option to download ebooks for offline reading
From a958579ec569d8bd0f3c79c1f6104b27b1e5c52f Mon Sep 17 00:00:00 2001 From: Sundeep Agarwal Date: Tue, 29 Dec 2020 17:13:05 +0530 Subject: [PATCH 54/54] updated status of this project --- README.md | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b8012fa..a52652f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,17 @@ +
+ +--- + +:warning: :warning: I'm archiving this repo, as I don't intend to work on this repo further. + +I'm re-using materials in this repo for the **100 Page Python Intro** book (https://github.com/learnbyexample/100_page_python_intro). + +I'm also working on **Practice Python Projects** book (https://github.com/learnbyexample/practice_python_projects), which I had intended in this repo for the `mini_projects` folder. + +--- + +


+ # Python Basics Introduction to Python - Syntax, working with Shell commands, Files, Text Processing, and more... @@ -7,12 +21,6 @@ Introduction to Python - Syntax, working with Shell commands, Files, Text Proces * [Python resources for everybody](https://learnbyexample.github.io/py_resources/) for a curated and searchable collection, including resources for complete beginners to programming * For more related resources, visit [scripting course](https://github.com/learnbyexample/scripting_course) and my programming blog https://learnbyexample.github.io ---- - -:warning: :warning: I'm no longer actively working on this repo. I'm archiving this repo for now, might come back later to update the book to newer Python version, add more content, etc. - ---- -
# Chapters