{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 6 Strings\n", "\"Open\n", "\n", "- http://openbookproject.net/thinkcs/python/english3e/strings.html\n", "\n", "## Topics\n", "- learn in-depth about string data types\n", "- methods provided in string objects/data\n", "- operators and various operations\n", "- ways to traverse/step through characters in string\n", "\n", "## 6.1 Introduction\n", "- strings are text data; not numeric!\n", "- breifely covered string while covering data and types in an earlier chapter\n", "- unlike numbers, strings are compound data type; sequence of characters\n", "- can work with string as a single thing\n", "- string variables are objects with their own attributes and methods\n", "- help(str) to see all the methods\n", "- commonly used methods: upper(), lower(), swapcase(), capitalize(), endswith(), isdigit(), find(), center(), count(), split(), etc.\n", "\n", "## 6.2 String methods and operations\n", "- string objects/data come with dozens of methods you can invoke" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on class str in module builtins:\n", "\n", "class str(object)\n", " | str(object='') -> str\n", " | str(bytes_or_buffer[, encoding[, errors]]) -> str\n", " | \n", " | Create a new string object from the given object. If encoding or\n", " | errors is specified, then the object must expose a data buffer\n", " | that will be decoded using the given encoding and error handler.\n", " | Otherwise, returns the result of object.__str__() (if defined)\n", " | or repr(object).\n", " | encoding defaults to sys.getdefaultencoding().\n", " | errors defaults to 'strict'.\n", " | \n", " | Methods defined here:\n", " | \n", " | __add__(self, value, /)\n", " | Return self+value.\n", " | \n", " | __contains__(self, key, /)\n", " | Return key in self.\n", " | \n", " | __eq__(self, value, /)\n", " | Return self==value.\n", " | \n", " | __format__(self, format_spec, /)\n", " | Return a formatted version of the string as described by format_spec.\n", " | \n", " | __ge__(self, value, /)\n", " | Return self>=value.\n", " | \n", " | __getattribute__(self, name, /)\n", " | Return getattr(self, name).\n", " | \n", " | __getitem__(self, key, /)\n", " | Return self[key].\n", " | \n", " | __getnewargs__(...)\n", " | \n", " | __gt__(self, value, /)\n", " | Return self>value.\n", " | \n", " | __hash__(self, /)\n", " | Return hash(self).\n", " | \n", " | __iter__(self, /)\n", " | Implement iter(self).\n", " | \n", " | __le__(self, value, /)\n", " | Return self<=value.\n", " | \n", " | __len__(self, /)\n", " | Return len(self).\n", " | \n", " | __lt__(self, value, /)\n", " | Return self int\n", " | \n", " | Return the number of non-overlapping occurrences of substring sub in\n", " | string S[start:end]. Optional arguments start and end are\n", " | interpreted as in slice notation.\n", " | \n", " | encode(self, /, encoding='utf-8', errors='strict')\n", " | Encode the string using the codec registered for encoding.\n", " | \n", " | encoding\n", " | The encoding in which to encode the string.\n", " | errors\n", " | The error handling scheme to use for encoding errors.\n", " | The default is 'strict' meaning that encoding errors raise a\n", " | UnicodeEncodeError. Other possible values are 'ignore', 'replace' and\n", " | 'xmlcharrefreplace' as well as any other name registered with\n", " | codecs.register_error that can handle UnicodeEncodeErrors.\n", " | \n", " | endswith(...)\n", " | S.endswith(suffix[, start[, end]]) -> bool\n", " | \n", " | Return True if S ends with the specified suffix, False otherwise.\n", " | With optional start, test S beginning at that position.\n", " | With optional end, stop comparing S at that position.\n", " | suffix can also be a tuple of strings to try.\n", " | \n", " | expandtabs(self, /, tabsize=8)\n", " | Return a copy where all tab characters are expanded using spaces.\n", " | \n", " | If tabsize is not given, a tab size of 8 characters is assumed.\n", " | \n", " | find(...)\n", " | S.find(sub[, start[, end]]) -> int\n", " | \n", " | Return the lowest index in S where substring sub is found,\n", " | such that sub is contained within S[start:end]. Optional\n", " | arguments start and end are interpreted as in slice notation.\n", " | \n", " | Return -1 on failure.\n", " | \n", " | format(...)\n", " | S.format(*args, **kwargs) -> str\n", " | \n", " | Return a formatted version of S, using substitutions from args and kwargs.\n", " | The substitutions are identified by braces ('{' and '}').\n", " | \n", " | format_map(...)\n", " | S.format_map(mapping) -> str\n", " | \n", " | Return a formatted version of S, using substitutions from mapping.\n", " | The substitutions are identified by braces ('{' and '}').\n", " | \n", " | index(...)\n", " | S.index(sub[, start[, end]]) -> int\n", " | \n", " | Return the lowest index in S where substring sub is found, \n", " | such that sub is contained within S[start:end]. Optional\n", " | arguments start and end are interpreted as in slice notation.\n", " | \n", " | Raises ValueError when the substring is not found.\n", " | \n", " | isalnum(self, /)\n", " | Return True if the string is an alpha-numeric string, False otherwise.\n", " | \n", " | A string is alpha-numeric if all characters in the string are alpha-numeric and\n", " | there is at least one character in the string.\n", " | \n", " | isalpha(self, /)\n", " | Return True if the string is an alphabetic string, False otherwise.\n", " | \n", " | A string is alphabetic if all characters in the string are alphabetic and there\n", " | is at least one character in the string.\n", " | \n", " | isascii(self, /)\n", " | Return True if all characters in the string are ASCII, False otherwise.\n", " | \n", " | ASCII characters have code points in the range U+0000-U+007F.\n", " | Empty string is ASCII too.\n", " | \n", " | isdecimal(self, /)\n", " | Return True if the string is a decimal string, False otherwise.\n", " | \n", " | A string is a decimal string if all characters in the string are decimal and\n", " | there is at least one character in the string.\n", " | \n", " | isdigit(self, /)\n", " | Return True if the string is a digit string, False otherwise.\n", " | \n", " | A string is a digit string if all characters in the string are digits and there\n", " | is at least one character in the string.\n", " | \n", " | isidentifier(self, /)\n", " | Return True if the string is a valid Python identifier, False otherwise.\n", " | \n", " | Use keyword.iskeyword() to test for reserved identifiers such as \"def\" and\n", " | \"class\".\n", " | \n", " | islower(self, /)\n", " | Return True if the string is a lowercase string, False otherwise.\n", " | \n", " | A string is lowercase if all cased characters in the string are lowercase and\n", " | there is at least one cased character in the string.\n", " | \n", " | isnumeric(self, /)\n", " | Return True if the string is a numeric string, False otherwise.\n", " | \n", " | A string is numeric if all characters in the string are numeric and there is at\n", " | least one character in the string.\n", " | \n", " | isprintable(self, /)\n", " | Return True if the string is printable, False otherwise.\n", " | \n", " | A string is printable if all of its characters are considered printable in\n", " | repr() or if it is empty.\n", " | \n", " | isspace(self, /)\n", " | Return True if the string is a whitespace string, False otherwise.\n", " | \n", " | A string is whitespace if all characters in the string are whitespace and there\n", " | is at least one character in the string.\n", " | \n", " | istitle(self, /)\n", " | Return True if the string is a title-cased string, False otherwise.\n", " | \n", " | In a title-cased string, upper- and title-case characters may only\n", " | follow uncased characters and lowercase characters only cased ones.\n", " | \n", " | isupper(self, /)\n", " | Return True if the string is an uppercase string, False otherwise.\n", " | \n", " | A string is uppercase if all cased characters in the string are uppercase and\n", " | there is at least one cased character in the string.\n", " | \n", " | join(self, iterable, /)\n", " | Concatenate any number of strings.\n", " | \n", " | The string whose method is called is inserted in between each given string.\n", " | The result is returned as a new string.\n", " | \n", " | Example: '.'.join(['ab', 'pq', 'rs']) -> 'ab.pq.rs'\n", " | \n", " | ljust(self, width, fillchar=' ', /)\n", " | Return a left-justified string of length width.\n", " | \n", " | Padding is done using the specified fill character (default is a space).\n", " | \n", " | lower(self, /)\n", " | Return a copy of the string converted to lowercase.\n", " | \n", " | lstrip(self, chars=None, /)\n", " | Return a copy of the string with leading whitespace removed.\n", " | \n", " | If chars is given and not None, remove characters in chars instead.\n", " | \n", " | partition(self, sep, /)\n", " | Partition the string into three parts using the given separator.\n", " | \n", " | This will search for the separator in the string. If the separator is found,\n", " | returns a 3-tuple containing the part before the separator, the separator\n", " | itself, and the part after it.\n", " | \n", " | If the separator is not found, returns a 3-tuple containing the original string\n", " | and two empty strings.\n", " | \n", " | replace(self, old, new, count=-1, /)\n", " | Return a copy with all occurrences of substring old replaced by new.\n", " | \n", " | count\n", " | Maximum number of occurrences to replace.\n", " | -1 (the default value) means replace all occurrences.\n", " | \n", " | If the optional argument count is given, only the first count occurrences are\n", " | replaced.\n", " | \n", " | rfind(...)\n", " | S.rfind(sub[, start[, end]]) -> int\n", " | \n", " | Return the highest index in S where substring sub is found,\n", " | such that sub is contained within S[start:end]. Optional\n", " | arguments start and end are interpreted as in slice notation.\n", " | \n", " | Return -1 on failure.\n", " | \n", " | rindex(...)\n", " | S.rindex(sub[, start[, end]]) -> int\n", " | \n", " | Return the highest index in S where substring sub is found,\n", " | such that sub is contained within S[start:end]. Optional\n", " | arguments start and end are interpreted as in slice notation.\n", " | \n", " | Raises ValueError when the substring is not found.\n", " | \n", " | rjust(self, width, fillchar=' ', /)\n", " | Return a right-justified string of length width.\n", " | \n", " | Padding is done using the specified fill character (default is a space).\n", " | \n", " | rpartition(self, sep, /)\n", " | Partition the string into three parts using the given separator.\n", " | \n", " | This will search for the separator in the string, starting at the end. If\n", " | the separator is found, returns a 3-tuple containing the part before the\n", " | separator, the separator itself, and the part after it.\n", " | \n", " | If the separator is not found, returns a 3-tuple containing two empty strings\n", " | and the original string.\n", " | \n", " | rsplit(self, /, sep=None, maxsplit=-1)\n", " | Return a list of the words in the string, using sep as the delimiter string.\n", " | \n", " | sep\n", " | The delimiter according which to split the string.\n", " | None (the default value) means split according to any whitespace,\n", " | and discard empty strings from the result.\n", " | maxsplit\n", " | Maximum number of splits to do.\n", " | -1 (the default value) means no limit.\n", " | \n", " | Splits are done starting at the end of the string and working to the front.\n", " | \n", " | rstrip(self, chars=None, /)\n", " | Return a copy of the string with trailing whitespace removed.\n", " | \n", " | If chars is given and not None, remove characters in chars instead.\n", " | \n", " | split(self, /, sep=None, maxsplit=-1)\n", " | Return a list of the words in the string, using sep as the delimiter string.\n", " | \n", " | sep\n", " | The delimiter according which to split the string.\n", " | None (the default value) means split according to any whitespace,\n", " | and discard empty strings from the result.\n", " | maxsplit\n", " | Maximum number of splits to do.\n", " | -1 (the default value) means no limit.\n", " | \n", " | splitlines(self, /, keepends=False)\n", " | Return a list of the lines in the string, breaking at line boundaries.\n", " | \n", " | Line breaks are not included in the resulting list unless keepends is given and\n", " | true.\n", " | \n", " | startswith(...)\n", " | S.startswith(prefix[, start[, end]]) -> bool\n", " | \n", " | Return True if S starts with the specified prefix, False otherwise.\n", " | With optional start, test S beginning at that position.\n", " | With optional end, stop comparing S at that position.\n", " | prefix can also be a tuple of strings to try.\n", " | \n", " | strip(self, chars=None, /)\n", " | Return a copy of the string with leading and trailing whitespace remove.\n", " | \n", " | If chars is given and not None, remove characters in chars instead.\n", " | \n", " | swapcase(self, /)\n", " | Convert uppercase characters to lowercase and lowercase characters to uppercase.\n", " | \n", " | title(self, /)\n", " | Return a version of the string where each word is titlecased.\n", " | \n", " | More specifically, words start with uppercased characters and all remaining\n", " | cased characters have lower case.\n", " | \n", " | translate(self, table, /)\n", " | Replace each character in the string using the given translation table.\n", " | \n", " | table\n", " | Translation table, which must be a mapping of Unicode ordinals to\n", " | Unicode ordinals, strings, or None.\n", " | \n", " | The table must implement lookup/indexing via __getitem__, for instance a\n", " | dictionary or list. If this operation raises LookupError, the character is\n", " | left untouched. Characters mapped to None are deleted.\n", " | \n", " | upper(self, /)\n", " | Return a copy of the string converted to uppercase.\n", " | \n", " | zfill(self, width, /)\n", " | Pad a numeric string with zeros on the left, to fill a field of the given width.\n", " | \n", " | The string is never truncated.\n", " | \n", " | ----------------------------------------------------------------------\n", " | Static methods defined here:\n", " | \n", " | __new__(*args, **kwargs) from builtins.type\n", " | Create and return a new object. See help(type) for accurate signature.\n", " | \n", " | maketrans(x, y=None, z=None, /)\n", " | Return a translation table usable for str.translate().\n", " | \n", " | If there is only one argument, it must be a dictionary mapping Unicode\n", " | ordinals (integers) or characters to Unicode ordinals, strings or None.\n", " | Character keys will be then converted to ordinals.\n", " | If there are two arguments, they must be strings of equal length, and\n", " | in the resulting dictionary, each character in x will be mapped to the\n", " | character at the same position in y. If there is a third argument, it\n", " | must be a string, whose characters will be mapped to None in the result.\n", "\n" ] } ], "source": [ "# let's see built-in documentation on str\n", "help(str)" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "HELLO THERE BEAUTIFUL WORLD!\n" ] } ], "source": [ "# let's use some of the methods provided for string objects/data\n", "ss = \"Hello there beautiful World!\"\n", "tt = ss.upper()\n", "print(tt)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello there beautiful World!\n" ] } ], "source": [ "print(ss)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello there beautiful world!\n" ] } ], "source": [ "print(tt.capitalize())" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['HELLO', 'THERE', 'BEAUTIFUL', 'WORLD!']\n" ] } ], "source": [ "alist = tt.split()\n", "print(alist)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# examples of some methods\n", "ss.count('o')" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "hELLO THERE BEAUTIFUL wORLD!\n" ] } ], "source": [ "print(ss.swapcase())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 6.3 Operators on string\n", "- **\\*** and **+** operators work on string data type as well\n", "- **\\+** : concatenates\n", "- **\\*** : repeats/multiplies" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "a = \"ABC\"" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "a = a + \"D\" + \"E \" + \"F \" + \"1 \" + \"2\" + a" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "DE F 1 2ABCDE F 1 2DE F 1 2ABC\n" ] } ], "source": [ "print(a)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'AAAAA'" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"A\"*5" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "AGTAGTAGTAGTAGTAGTAGTAGTAGTAGT\n" ] } ], "source": [ "gene = \"AGT\"*10\n", "print(gene)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!\n" ] } ], "source": [ "print(\"hello world!\"*10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 6.4 working with parts of a string\n", "- string can be sliced using [ index ] or [ inclStartIndex : ExclEndIndex : step] bracket operator\n", "- negative indices are allowed\n", "- len( ) built-in function gives the length of a string" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "# examples\n", "s = \"Pirates of the Caribbean\"" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'i'" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# access the second character\n", "s[1]" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Pirates of the Caribbean'" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s[:]" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'irates of the Caribbean'" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s[1:]" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Pirates\n" ] } ], "source": [ "# print just the pirates \n", "print(s[0:7])" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "the startst at 11\n", "the \n" ] } ], "source": [ "# print \"the\" from string s\n", "theIndex = s.find(\"the\")\n", "print('the startst at', theIndex)\n", "print(s[theIndex:theIndex+4])" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "# TODO\n", "# print Caribbean from string s - hint use find function" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "lastSpace = s.rfind(' ')\n", "print(lastSpace)" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "n\n" ] } ], "source": [ "# print the last character\n", "print(s[-1])" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": [ "# print string in reverse order\n", "reversedS = s[-1::-1]" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ ".\n" ] } ], "source": [ "ss = \"Pirates of the Caribbean.\"\n", "print(ss[len(ss)-1])" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "palindrome\n" ] } ], "source": [ "# test whether a given string is palindrome\n", "a= \"racecar\"\n", "print ('palindrome') if a==a[::-1] else print('not palindrome')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 6.5 string is immutable\n", "- string objects/variables can't be modified in place!\n", "- you must reassign or make a copy to update strings" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "a = 'hello'" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "'str' object does not support item assignment", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0ma\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'H'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: 'str' object does not support item assignment" ] } ], "source": [ "a[0] = 'H'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 6.6 string traversal \n", "- it's a common practice to go through every character of a given string\n", "- can use both for and while loop to traverse a string" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "P i r a t e s o f t h e C a r i b b e a n " ] } ], "source": [ "# example using for loop\n", "# traversing string using index\n", "for i in range(len(s)):\n", " print(s[i], end=' ')" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "P i r a t e s o f t h e C a r i b b e a n " ] } ], "source": [ "# range-based loop traversing each character\n", "for c in s:\n", " print(c, end=' ')" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [], "source": [ "someStr = \"\"\"afAdf@#456'\"\"\"" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a f A d f @ # 4 5 6 ' " ] } ], "source": [ "# example using while loop\n", "i = 0\n", "while i < len(someStr):\n", " print(someStr[i], end=' ')\n", " i += 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 6.7 string comparison\n", "- strings can be compared using comparison operators\n", "- comparison operators are **==, !=, <=, >=, <, >**\n", "- compares lexicographically using ASCII values\n", " - see [ASCII table](http://www.asciitable.com/) for values\n", "- ord('c') provides ASCII value of the given character\n", "- two strings are compared character by character in corresponding positions" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "65 97\n" ] } ], "source": [ "# find ascii values of lower a and upper A\n", "print(ord('A'), ord('a'))" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n" ] } ], "source": [ "# string comparison examples\n", "print(\"apple\" == \"Apple\")" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n" ] } ], "source": [ "print(\"apple\" >= \"ball\")" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n" ] } ], "source": [ "# greater and less than returns True if first two corresponding\n", "#characters have valid order\n", "print(\"apple\" >= \"Apple\")" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n" ] } ], "source": [ "# since A is <= a; result is True\n", "# eventhough b is not less than B or c\n", "print('Abc' <= 'aBC')" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n" ] } ], "source": [ "# for equality all characters have to match\n", "print(\"apple\" == \"Apple\") # false" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n" ] } ], "source": [ "# for inequalify any one pair of unmatched characters will do\n", "print('apple' != 'applE')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 6.8 in and not in operators\n", "- help quickly test for membership\n", "- can be used to check if a substring is in a string" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n" ] } ], "source": [ "print(\"p\" in \"apple\")" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n" ] } ], "source": [ "print(\"pe\" in \"apple\")" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n" ] } ], "source": [ "print(\"aple\" not in \"apple\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 6.9 cleaning up strings\n", "- often times working with strings involve removing punctuations and unwanted characters\n", "- traverse the string by removing any encountered punctations" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\"Well, I never did!\", said Alice.\n" ] } ], "source": [ "# create a new string removing punctuations from the following string\n", "ss = '\"Well, I never did!\", said Alice.'\n", "print(ss)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "97 122 65 90\n" ] } ], "source": [ "# one solution is to use ASCII value of each character between A..Z and a..z\n", "print(ord('a'), ord('z'), ord('A'), ord('Z'))" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Well I never did said Alice\n" ] } ], "source": [ "newStr = ''\n", "for c in ss:\n", " if ord(c) == ord(' '): # keep space\n", " newStr += c\n", " elif ord(c) >= ord('A') and ord(c) <= ord('Z'):\n", " newStr += c\n", " elif ord(c) >= ord('a') and ord(c) <= ord('z'):\n", " newStr += c\n", "print(newStr)" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "well i never did said alice\n" ] } ], "source": [ "# convert newStr to lowercase for case insensitive operations\n", "newStr1 = newStr.lower()\n", "print(newStr1)" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['well', 'i', 'never', 'did', 'said', 'alice']\n" ] } ], "source": [ "# convert sentence into list of tokens/terms/words\n", "words = newStr1.split()\n", "print(words)" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "well\n", "i\n", "never\n", "did\n", "said\n", "alice\n" ] } ], "source": [ "# traverse through list of words\n", "for w in words:\n", " print(w)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on module string:\n", "\n", "NAME\n", " string - A collection of string constants.\n", "\n", "MODULE REFERENCE\n", " https://docs.python.org/3.7/library/string\n", " \n", " The following documentation is automatically generated from the Python\n", " source files. It may be incomplete, incorrect or include features that\n", " are considered implementation detail and may vary between Python\n", " implementations. When in doubt, consult the module reference at the\n", " location listed above.\n", "\n", "DESCRIPTION\n", " Public module variables:\n", " \n", " whitespace -- a string containing all ASCII whitespace\n", " ascii_lowercase -- a string containing all ASCII lowercase letters\n", " ascii_uppercase -- a string containing all ASCII uppercase letters\n", " ascii_letters -- a string containing all ASCII letters\n", " digits -- a string containing all ASCII decimal digits\n", " hexdigits -- a string containing all ASCII hexadecimal digits\n", " octdigits -- a string containing all ASCII octal digits\n", " punctuation -- a string containing all ASCII punctuation characters\n", " printable -- a string containing all ASCII characters considered printable\n", "\n", "CLASSES\n", " builtins.object\n", " Formatter\n", " Template\n", " \n", " class Formatter(builtins.object)\n", " | Methods defined here:\n", " | \n", " | check_unused_args(self, used_args, args, kwargs)\n", " | \n", " | convert_field(self, value, conversion)\n", " | \n", " | format(*args, **kwargs)\n", " | \n", " | format_field(self, value, format_spec)\n", " | \n", " | get_field(self, field_name, args, kwargs)\n", " | # given a field_name, find the object it references.\n", " | # field_name: the field being looked up, e.g. \"0.name\"\n", " | # or \"lookup[3]\"\n", " | # used_args: a set of which args have been used\n", " | # args, kwargs: as passed in to vformat\n", " | \n", " | get_value(self, key, args, kwargs)\n", " | \n", " | parse(self, format_string)\n", " | # returns an iterable that contains tuples of the form:\n", " | # (literal_text, field_name, format_spec, conversion)\n", " | # literal_text can be zero length\n", " | # field_name can be None, in which case there's no\n", " | # object to format and output\n", " | # if field_name is not None, it is looked up, formatted\n", " | # with format_spec and conversion and then used\n", " | \n", " | vformat(self, format_string, args, kwargs)\n", " | \n", " | ----------------------------------------------------------------------\n", " | Data descriptors defined here:\n", " | \n", " | __dict__\n", " | dictionary for instance variables (if defined)\n", " | \n", " | __weakref__\n", " | list of weak references to the object (if defined)\n", " \n", " class Template(builtins.object)\n", " | Template(template)\n", " | \n", " | A string class for supporting $-substitutions.\n", " | \n", " | Methods defined here:\n", " | \n", " | __init__(self, template)\n", " | Initialize self. See help(type(self)) for accurate signature.\n", " | \n", " | safe_substitute(*args, **kws)\n", " | \n", " | substitute(*args, **kws)\n", " | \n", " | ----------------------------------------------------------------------\n", " | Data descriptors defined here:\n", " | \n", " | __dict__\n", " | dictionary for instance variables (if defined)\n", " | \n", " | __weakref__\n", " | list of weak references to the object (if defined)\n", " | \n", " | ----------------------------------------------------------------------\n", " | Data and other attributes defined here:\n", " | \n", " | braceidpattern = None\n", " | \n", " | delimiter = '$'\n", " | \n", " | flags = \n", " | \n", " | idpattern = '(?a:[_a-z][_a-z0-9]*)'\n", " | \n", " | pattern = re.compile('\\n \\\\$(?:\\n (?P\\\\$)...ced>(?a:[...\n", "\n", "FUNCTIONS\n", " capwords(s, sep=None)\n", " capwords(s [,sep]) -> string\n", " \n", " Split the argument into words using split, capitalize each\n", " word using capitalize, and join the capitalized words using\n", " join. If the optional second argument sep is absent or None,\n", " runs of whitespace characters are replaced by a single space\n", " and leading and trailing whitespace are removed, otherwise\n", " sep is used to split and join the words.\n", "\n", "DATA\n", " __all__ = ['ascii_letters', 'ascii_lowercase', 'ascii_uppercase', 'cap...\n", " ascii_letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'\n", " ascii_lowercase = 'abcdefghijklmnopqrstuvwxyz'\n", " ascii_uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n", " digits = '0123456789'\n", " hexdigits = '0123456789abcdefABCDEF'\n", " octdigits = '01234567'\n", " printable = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTU...\n", " punctuation = '!\"#$%&\\'()*+,-./:;<=>?@[\\\\]^_`{|}~'\n", " whitespace = ' \\t\\n\\r\\x0b\\x0c'\n", "\n", "FILE\n", " /Users/rbasnet/anaconda3/lib/python3.7/string.py\n", "\n", "\n" ] } ], "source": [ "# next solution using string library\n", "# string library provides range of different types of characters as data\n", "import string\n", "help(string)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'!\"#$%&\\'()*+,-./:;<=>?@[\\\\]^_`{|}~'" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# string library has data that can be useful, e.g.\n", "string.punctuation" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'\"Well, I never did!\", said Alice.'" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ss" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Well I never did said Alice\n" ] } ], "source": [ "newStr = ''\n", "for c in ss:\n", " if c in string.ascii_lowercase:\n", " newStr += c\n", " elif c in string.ascii_uppercase:\n", " newStr += c\n", " elif c == ' ':\n", " newStr += ' '\n", " \n", "print(newStr)" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [], "source": [ "# write a function that removes all the punctations except for space\n", "# returns new cleaned up string\n", "def cleanUp(someStr):\n", " newStr = ''\n", " for c in someStr:\n", " if c.islower():\n", " newStr += c\n", " elif c.isupper():\n", " newStr += c\n", " elif c.isspace():\n", " newStr += c\n", " return newStr" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Well I never did said Alice\n" ] } ], "source": [ "s = cleanUp(ss)\n", "print(s)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 6.10 string formatting\n", "- format method\n", "- use {} as replacement field\n", "- numbers in curly braces are optional; determine which argument gets substituted\n", "- each of the replace fields can also contain a format specification\n", " - < left alignment, > right, and ^ center, e.g. {1:<10}\n", " - 10 is width\n", " - type conversion such as f for float (.2f two decimal places), x for hex, etc." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "name = \"Arthur\"\n", "age = 25" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "His name is Arthur!\n" ] } ], "source": [ "s1 = \"His name is {}!\".format(name)\n", "print(s1)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "His name is Arthur!\n" ] } ], "source": [ "# newer syntax\n", "print(f\"His name is {name}!\")" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "His name is Arthur and Arthur is 25 years old.\n" ] } ], "source": [ "# note age and name are provided in reverse order\n", "print(\"His name is {1} and {1} is {0} years old.\".format(age, name))" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4 x 5.5 = 22.0 and 4 ^ 5.5 = 2048.00\n" ] } ], "source": [ "n1 = 4\n", "n2 = 5.5\n", "s3 = \"{0} x {1} = {2} and {0} ^ {1} = {3:.2f}\".format(n1, n2, n1*n2, n1**n2)\n", "print(s3)" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Pi to three decimal places is 3.142\n" ] } ], "source": [ "# formating decimal/float values to certian decimal points\n", "print(\"Pi to three decimal places is {0:.3f}\".format(3.1415926))" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "123456789 123456789 123456789 123456789 123456789 123456789\n", "|||Paris ||| Whitney ||| Hilton|||Born in 1981|||\n" ] } ], "source": [ "n1 = \"Paris\"\n", "n2 = \"Whitney\"\n", "n3 = \"Hilton\"\n", "print(\"123456789 123456789 123456789 123456789 123456789 123456789\")\n", "print(\"|||{0:<15}|||{1:^15}|||{2:>15}|||Born in {3}|||\"\n", " .format(n1,n2,n3,1981))" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The decimal value 16 converts to hex value 0x10\n" ] } ], "source": [ "# formatting decimal int to hexadecimal number\n", "print(\"The decimal value {0} converts to hex value 0x{0:x}\".format(16))" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The decimal value 8 converts to hex value 0b1000\n" ] } ], "source": [ "# formatting decimal int to binary number\n", "print(\"The decimal value {0} converts to binary value 0b{0:b}\".format(8))" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The decimal value 8 converts to octal value 0o10\n" ] } ], "source": [ "# formatting decimal int to octal number\n", "print(\"The decimal value {0} converts to octal value 0o{0:o}\".format(8))" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Dear Paris Hilton.\n", " Paris, I have an interesting money-making proposition for you!\n", " If you deposit $10 million into my bank account, I can\n", " double your money ...\n", "\n", "\n", "Dear Bill Jeff.\n", " Bill, I have an interesting money-making proposition for you!\n", " If you deposit $10 million into my bank account, I can\n", " double your money ...\n", "\n" ] } ], "source": [ "letter = \"\"\"\n", "Dear {0} {2}.\n", " {0}, I have an interesting money-making proposition for you!\n", " If you deposit $10 million into my bank account, I can\n", " double your money ...\n", "\"\"\"\n", "print(letter.format(\"Paris\", \"Whitney\", \"Hilton\"))\n", "print(letter.format(\"Bill\", \"Warren\", \"Jeff\"))" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " i i**2 i**3 i**5 i**10 i**20\n", " 1 1 1 1 1 1\n", " 2 4 8 32 1024 1048576\n", " 3 9 27 243 59049 3486784401\n", " 4 16 64 1024 1048576 1099511627776\n", " 5 25 125 3125 9765625 95367431640625\n", " 6 36 216 7776 60466176 3656158440062976\n", " 7 49 343 16807 282475249 79792266297612001\n", " 8 64 512 32768 1073741824 1152921504606846976\n", " 9 81 729 59049 3486784401 12157665459056928801\n", " 10 100 1000 100000 10000000000 100000000000000000000\n" ] } ], "source": [ "layout = \"{0:>4}{1:>6}{2:>6}{3:>8}{4:>13}{5:>24}\"\n", "\n", "print(layout.format(\"i\", \"i**2\", \"i**3\", \"i**5\", \"i**10\", \"i**20\"))\n", "for i in range(1, 11):\n", " print(layout.format(i, i**2, i**3, i**5, i**10, i**20))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 6.11 Exercises\n", "\n", "1. print a neat looking multiplication table like this:\n", "
\n",
    "        1   2   3   4   5   6   7   8   9  10  11  12\n",
    "  :--------------------------------------------------\n",
    " 1:     1   2   3   4   5   6   7   8   9  10  11  12\n",
    " 2:     2   4   6   8  10  12  14  16  18  20  22  24\n",
    " 3:     3   6   9  12  15  18  21  24  27  30  33  36\n",
    " 4:     4   8  12  16  20  24  28  32  36  40  44  48\n",
    " 5:     5  10  15  20  25  30  35  40  45  50  55  60\n",
    " 6:     6  12  18  24  30  36  42  48  54  60  66  72\n",
    " 7:     7  14  21  28  35  42  49  56  63  70  77  84\n",
    " 8:     8  16  24  32  40  48  56  64  72  80  88  96\n",
    " 9:     9  18  27  36  45  54  63  72  81  90  99 108\n",
    "10:    10  20  30  40  50  60  70  80  90 100 110 120\n",
    "11:    11  22  33  44  55  66  77  88  99 110 121 132\n",
    "12:    12  24  36  48  60  72  84  96 108 120 132 144\n",
    "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "2. Write a program that determines whether a given string is palindrome. Palindrome is a word, phrase, or sequence that reads the same backward as forward, e.g., madam or nurses run or race car." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "2.1 Convert Exercise 2 into a function and write at least two test cases." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "3. Write a program that calculates number of trials required to guess a 3 digit pass code 777 (starting from 000, 001, 002, 003, 004, 005..., 010, etc.) using some brute force technique." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "3.1. Convert Exercise 3 into a function and write at least 3 test cases." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "4. Write a function that calculates the [run-length encoding](https://en.wikipedia.org/wiki/Run-length_encoding) of a given string. Run-length is a lossless data compression in which runs of data are stored as a single data value and count, rather than the original run. Assume that the data contains alphabets (upper and lowercase) only and are case insisitive.\n", "E.g.: \n", " - aaaabbc -> 4a2b1c\n", " - Abcd -> 1a1b1c1d" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "# 4 solution\n", "# Algorithm:\n", "# for each character:\n", "# if the current character is same as the previous one\n", "# increment count\n", "# else \n", "# print the count and the previous character\n", "# reset count and previous character\n", "# \n", "\n", "def run_length_encoding(text):\n", " # check for corner case\n", " if not text: # if text is empty!\n", " return ''\n", " \n", " encoding = ''\n", " # FIXME: implement the algorithm\n", " \n", " \n", " return encoding\n", " " ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "ename": "AssertionError", "evalue": "", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# unit testing for run_length_encoding\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0mrun_length_encoding\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m''\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m''\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0mrun_length_encoding\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'aaaabbc'\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m'4a2b1c'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0mrun_length_encoding\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'abcd'\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m'1a2b3c4d'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0mrun_length_encoding\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'zzaazyyyYY'\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m'2z2a1z5y'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mAssertionError\u001b[0m: " ] } ], "source": [ "# unit testing for run_length_encoding\n", "assert run_length_encoding('') == ''\n", "assert run_length_encoding('aaaabbc') == '4a2b1c'\n", "assert run_length_encoding('abcd') == '1a2b3c4d'\n", "assert run_length_encoding('zzaazyyyYY') == '2z2a1z5y'\n", "# FIXME: Write few more test cases; what corner cases can you think of \n", "# that would break run_length_encoding function?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "5. Write a function that decodes the given run-length encoded compressed data, i.e. decompresses the compressed data to the original string.\n", "e.g. \n", " - '' -> ''\n", " - '1a2b3c' -> 'abbccc'\n", " - '10a' -> 'aaaaaaaaaa'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Kattis problems\n", "1. Avion - https://open.kattis.com/problems/avion\n", "- Apaxiaans - https://open.kattis.com/problems/apaxiaaans\n", "- Hissing Microphone - https://open.kattis.com/problems/hissingmicrophone\n", "- Reversed Binary Numbers - https://open.kattis.com/problems/reversebinary\n", "- Kemija - https://open.kattis.com/problems/kemija08\n", "- Simon Says - https://open.kattis.com/problems/simonsays\n", "- Simon Says - https://open.kattis.com/problems/simon\n", "- Quite a Problem - https://open.kattis.com/problems/quiteaproblem\n", "- Eligibility - https://open.kattis.com/problems/eligibility\n", "- Charting Progress - https://open.kattis.com/problems/chartingprogress\n", "- Pig Latin - https://open.kattis.com/problems/piglatin\n", "- Battle Simulation - https://open.kattis.com/problems/battlesimulation\n", "- Palindromic Password - https://open.kattis.com/problems/palindromicpassword\n", "- Image Decoding - https://open.kattis.com/problems/imagedecoding" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.3" } }, "nbformat": 4, "nbformat_minor": 2 }