<jupyter_start><jupyter_text>1.0.2. String Manipulation  Learning Objectives* [Immutability](Immutability)* [Slicing](Slicing)* [Operators and methods](Operators)* [Iteration](Iteration)  Immutability Let's remember!* Strings are a **sequence** of case sensitive characters* They are a type of object.* We compare strings with ==, >, < etc.We can create strings with the use of single, double or triple quotes! They all provide the same functionality, except the triple quotes enable us to write multi-line strings.<jupyter_code># remember a string is in quotation marks !
# Using single quotations can be problematic, here, the apostrophe ends the string early
print('What's the problem here?')
# we can use double quotations
print("What's the problem here?")
# or backslash if we have single and double quotes
print("What\'s the \"problem\" here?")
# Triple quotes for multi-line strings
print('''What's the
        problem here? ''')<jupyter_output><empty_output><jupyter_text>Before we move one, let's look at **indexing**:* Since strings are a sequence of characters, we might want to get what character is at a certain position. We're going to tell Python, I want to know the character, at this certain position or at this certain index, inside my sting.* Square brackets used to perform **indexing** into a string to get the value at a certain index/position<jupyter_code>s = "abc"

print(s[0])    # evaluates to "a"
print(s[1])    # evaluates to "b"
print(s[2])    # evaluates to "c"
print(s[-1])   # evaluates to "c"
print(s[-2])   # evaluates to "b"
print(s[-3])  # evaluates to "a"<jupyter_output><empty_output><jupyter_text>Now we get to the idea of **immutability**. String objects are **immutable**, whichs means that a value (character) from a string cannot be updated. We can verify this by trying to update a part of the string which will led us to an error.<jupyter_code># Can not reassign 
example = "Hello world!"
print(type(example))
example[0] = "M"
# One possible solution is to create a new string object with necessary modifications:

example_1 = "Hello world!"
example_2 = "M"+ example_1[1:] # this an example of slicing, which we are about to see
print("example_1 = ", example_1, "\nexample_2 = ", example_2)
s = "hello"
s[0] = 'y'   # gives an error
s = 'y'+s[1:len(s)]   # is allowed, s bound to new object
print(s)<jupyter_output><empty_output><jupyter_text>_Source on page 7:_ ([Click here](https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-0001-introduction-to-computer-science-and-programming-in-python-fall-2016/lecture-slides-code/MIT6_0001F16_Lec3.pdf))  Slicing Sometimes, we might want to get a **substring**. So we want to:* start at the first character and go halfway into the string or* take a few characters in between or* skip every other letter or something like that in our string.In order to do these more complicated operation, we use **slicing**. In our daily life, let's think of a birthday cake. You want only a slice of it and basically get a slice. _Source:_ ([Click here](https://www.superhealthykids.com/wp-content/uploads/2020/05/VanillaStrawberryCake2-745x496.jpg)) * We can slice strings using: **[start:stop:step]*** If give two numbers:     **[start:stop]**, step=1 by default* You can also omit numbers and leave just colonsThis notation here should seem a little bit familiar, because we saw it last lecture when we did it with range.We had a start, stop, and a step. The notation was a little bit different, because, in range, we had open-close parentheses and commas in between. But except for that, this sort of works the same.<jupyter_code># range(start, stop, step)
x = range(1, 6)
for n in x:
    print(n)
s = "abcdefgh"

print(s[3:6])     # evaluates to "def", same as s[3:6:1]
print(s[3:6:1])   # evaluates to "def", same as above
print(s[3:6:2])   # evaluates to "df"
print(s[::])      # evaluates to "abcdefgh", same as s[0:len(s):1]
print(s[:])       # evaluates to "abcdefgh", same as s[0:len(s)] step=1 by default
print(s[::-1])    # evaluates to "hgfedbca", same as s[-1:-(len(s)+1):-1]
print(s[4:1:-2])  # evaluates to "ec"

x = range(1)
print(x)<jupyter_output><empty_output><jupyter_text>**Your Turn!**What does the code below print? Guess and run the cell to see the answer!<jupyter_code>s = "6.00 is 6.0001 and 6.0002"
new_str = ""
new_str += s[-1]
new_str += s[0]
new_str += s[4::30]    
new_str += s[13:10:-1]
print(new_str)<jupyter_output><empty_output><jupyter_text>Operators and methods We can do more than just concatenate two strings together or do these little tests on them. Today we're going to start introducing the idea of a **function** or a procedure. We'll focus on function next lecture but for now, you can think of a **function** as sort of a procedure that does something for you. We'll look at some functions in this notebook and you can find the rest at:https://docs.python.org/2/library/stdtypes.htmlstring-methods [Source](https://medium.com/@kuanzhasulan/python-functions-352137dd4d84)As seen above, a function basically takes in an input and gives an output. It does some calculations or operations with the input and we get an output in return. Let's think about a snack machine. Here are the arguments according to the diagram shown above:* **Input:** putting money, pushing the button* **Function:** the machine gets what you wanted and a specific item drops into the output slot * **Output:** a specific item [Source for the machine](https://www.candymachines.com/Seaga-Infinity-INF5S-Snack-Vending-Machine-P2641.aspx) len()* len() is a function used to retrieve the **length** of the string in the parentheses. That's going to tell you how many characters are in the string. These characters are going to be letters, digits, special characters, spaces, and so on. So it's just going to count how many characters are in a string.<jupyter_code>s = "abc"    # define a string variable called 's' 
len(s)       # evaluates to 3<jupyter_output><empty_output><jupyter_text>upper()<jupyter_code># .upper() method makes all caps (not inplace)
print(s.upper())
print(s)
# if we want to change x itself, we must reassign it
print(s)

s = s.upper()

print(s)<jupyter_output><empty_output><jupyter_text>lower()<jupyter_code># .lower() method makes all lowercase (not inplace)
print(s.lower())<jupyter_output><empty_output><jupyter_text>split()The split method breaks up a string at the specified __separator__ and returns a list of strings. A separator is just a commonly occuring value in your object. If your string was a piece of paper, the separators are the dotted lines where you should cut across. When dealing with strings, the recurring characters are referred to as __delimiters__. If no argument is given, it assumes a whitespace, ' ', to be the delimiter. This will __split a sentence into a list of words__. You can set other delimiters if you would like.<jupyter_code>x = "Hello World"

# split() method splits on space as default or desired separator
print(x.split())

# we gave a specific seperator "o"
print(x.split("o"))
grocery = 'Milk, Chicken, Bread'

# splits at space as default
print(grocery.split())

# splits at comma+space ', '
print(grocery.split(', '))

# Splitting at ':'
print(grocery.split(':'))<jupyter_output><empty_output><jupyter_text>.format * The .format method (A method is a function associated with an object) is a way of inserting something into a string.* This can be other strings or a variable taken from elsewhere in your code.* The syntax used is detailed below.* When using .format to add in a float to a string, we can specify the width and precision of the decimal.<jupyter_code># default prints in order
print("The {} {} {}".format("fox", "brown", "quick"))
# can index
print("The {2} {1} {0}".format("fox", "brown", "quick"))
# can use variable keys for readability
print("The {q} {b} {f}".format(f="fox", b="brown", q="quick"))
# create long decimal
result = 100/777
print(result, end = "\n\n")

# use value:width.precisionf for formatting
# width is minimum length of string, padded with whitespace if necessary
# precision is decimal places
print("The result was {:1.3f}".format(result))
print("The result was {r:1.3f}".format(r=result))
print("The result was {r:1.7f}".format(r=result))
print("The result was {r:8.3f}".format(r=result))<jupyter_output><empty_output><jupyter_text>Iteration We can apply for loops, very easily, to write very nice, readable code when dealing with strings.* for LOOPS RECAPfor loops have a **loop variable** that iterates over a set of values: * **range** is a way to iterate over numbers, but a for loop variable can **iterate over any set of values**, not just numbers!These two code snippets below do the same thing but the bottom one is more __"pythonic”__:<jupyter_code>s = "abcdefghi"

for index in range(len(s)):
    if s[index] == 'i' or s[index] == 'u':
        print("There is an i or u")
     
        
for char in s:
    if char == 'i' or char == 'u':
        print("There is an i or u")<jupyter_output><empty_output><jupyter_text>Note: Brief description of iterables in Python The output of the range() function and strings are referred to as __iterables__. An iterable is any Python object capable of returning its members one at a time, permitting it to be iterated over in a loop. Most of the objects in Python are iterable. All sequences like strings, lists, tuples and dictionaries are iterable. Strings have some characters as its members and we can iterate its members in a loop. [Click here for more information about iterables](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Iterables.html:~:text=Definition%3A,over%20in%20a%20for%2Dloop)<jupyter_code>string = 'London'

for member in string:
    print(member)<jupyter_output><empty_output><jupyter_text>Are you confused? Now, let's give an example from daily life. Suppose, a group of 5 boys are standing in a line. You're pointing at the first boy and ask him about his name. Then, he replied. After that, you ask the next boy and so on. The below picture will illustrate the thing. ([Source](https://medium.com/@kuanzhasulan/python-functions-352137dd4d84))In this case, you are the **Iterator**!!!! Obviously, the group of boys is the **iterable** element.---  CODE EXAMPLE: ROBOT CHEERLEADERS_Source:_  ([Click here](https://www.programmersought.com/images/613/1e4c176c84dfdfc4a5eaa207fda3a05d.gif))<jupyter_code>an_letters = "aefhilmnorsxAEFHILMNORSX"

word = input("I will cheer for you! Enter a word: ")
times = int(input("Enthusiasm level (1-10): "))

i = 0
while i < len(word):
    char = word[i]
    if char in an_letters:
        print("Give me an " + char + "! " + char)
    else:
        print("Give me a " + char + "! " + char)
    i += 1

print("What does that spell?")
for i in range(times):
    print(word, "!!!")<jupyter_output><empty_output><jupyter_text>_Source on page 10:_ ([Click here](https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-0001-introduction-to-computer-science-and-programming-in-python-fall-2016/lecture-slides-code/MIT6_0001F16_Lec3.pdf))**Your Turn!**Can you change the code example "ROBOT CHEERLEADERS" according to the image above? Simply add for loop!<jupyter_code>## Your code is here!<jupyter_output><empty_output><jupyter_text>**Your Turn!**How many times will the code below print "common letter"? Guess and run the cell to see the answer!<jupyter_code>s1 = "this make sense"
s2 = "i get this now!"
if len(s1) == len(s2):
    for char1 in s1:
        for char2 in s2:
            if char1 == char2:
                print("common letter")
                break<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11170212765957446, 'fraction_numerical': 0.017501715854495538, 'mean_word_length': 4.773650321941555, 'pattern_counts': {'":': 0, '<': 63, '<?xml version=': 0, '>': 62, 'https://': 9, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '15', 'dir': 'jupyter-structured-clean-dedup', 'id': '496513', 'license': 'MIT', 'n_tokens_mistral': 3745, 'n_tokens_neox': 3544, 'n_words': 1458, 'path': 'English/3. String Manipulation.ipynb', 'repo_name': 'haticeaydinn/MIT-Python-Course', 'size': '11656'}