 In this video we are going to briefly review the string methods and operations. So let's start by creating a new notebook and let's call it string method for short. So let's also take the same example we saw in the previous video, which is simply a string with the Latin sentence ... you know it from many example texts on the web and so on. So in a previous video we ended with the notion that the string data type is a so-called immutable data type. That means after the object, a string object is created in memory, the ones and zeros inside the object cannot be changed anymore. We contrast this with, for example, the list data type, which is a mutable data type, an example of a mutable data type. And in the video, who am I and how many, we saw that when we use a list object we can actually replace individual elements inside the list after the list has been created. And we cannot do that with the string data type. So let's go ahead and look at an example. So first, before we have another coding example, let's briefly go ahead and draw a memory diagram of what happened when we execute the code that I just showed you in the JupyterLab environment. So what's going to happen is we first get a box here in memory, the object. It is of type string, str. And it basically models somehow the text lorem ipsum. So let's put that in here. And then after the object is created, we assign the name text in the global scope to this object. So what does it mean for this object here to be immutable? Well, it means nothing that is or anything that is in here can never be changed anymore. So let's change it or let's presumably change it. So let's go ahead and use a string method that we have seen a couple of times before. For example, the lower method. So I'm going to invoke the lower method on the text object here. And we get back text that is lower case. Okay, the entire sentence now is lower case. So basically the only thing that changes is the starting L, which goes from uppercase to lower case. So if we go ahead and we go ahead and simply look at what text is after we invoked the lower method, we see that text is still uppercase here. So in other words, text itself has not been changed. This is how we see that in code and the output in JupyterLab. But let's see what's going to happen in the environment in the memory. So when we call the, in this case, the lower method that is attached to any object of type string, what is going to happen is we get back another object, of course, also of type string. And here, lowerm ipsum will be written with a lower case L. And now we are basically getting a reference to this object back. And in our example, let's look at the code here. In the third cell here, what I'm going to do with the return value of the method, I'm not doing anything with it, right? We are not saving it away. But let's assume we are going to save that in a variable. Let's call it lower simply. Now if we go ahead and look at the lower variable, it is basically the object that was created in the step before. And let's assume this is what we did here in the memory diagram. Well, what this is going to do is it will create a new variable in the global scope called lower. And this is now going to reference this object here. Okay? But the important idea is that we now have two objects, very similar indeed, but two objects. So let's take this one step further. So let's go ahead and take the lower cased object. And let's go ahead and lower case it one more time. So on the lower object, which is a string object, I'm going to invoke the lower method, which also gives me something back. Now, in the extreme case, in this case here, in the edge case, so to say where the word is or the sentence is already all lower case, what is going to happen in memory is the following. We get back another object, also of type string, for sure. Also within it, lower case, we get back a reference to this object. And this time we are not going to store it away. So that means, since we don't store away a reference to it, well, at some point in the future, the garbage collector will come along and will simply remove this object from the memory. So for those of you who watch this video and may have some previous knowledge in Python, maybe some expert knowledge as well, you may wonder that does this really happen and the answer is no. So in this case, because we're not changing it, we get back the same object. However, the best way to think of how these objects work in general is to assume that whenever we invoke a method, we get back a new object, with in this case has the exact same ones and zeros inside them as the previous one. That is basically the mental model I want to give you with, so that if you use this way of reasoning about code, you will always get the result in your program that you expect. So the memory diagrams is always a little bit of a simplification of what is going on really in the memory, but this is the mental model that I want you to get. So that is usually what we see when we call methods on immutable objects. So what do we mean by that? Well, whenever we call a method on an immutable object and the string data type is only one example of that, then usually the method is going to return to us some other object. And we will see in a future video when we talk about the list data type in detail, a mutable data type, then we will see that methods that change an object in place, they don't have a return value. That is a big conceptual difference. So we note down that a method called on an immutable data type usually has a return value and this could be another object with the same ones and zeros, the same semantic value. So that is an important idea here. So let's go ahead and look at a couple of other methods. So for example, text objects, so string objects have a method on them that is called find. And find can be used to find in this case either an individual character or maybe a so-called substring inside the text object. So let's go ahead and try to find, let's say, the letter O. And if we look at this version of the text above, so the uppercase version, the tidal case version, now what we see is the first occurrence of the lower case O is the second character in the word or in the sentence here. So we get back the index one because by now we know that a Python is zero base, so the index one means second position here. So now let's go ahead and see what is going to happen when we look for some character that is not even in the string. So let's look for uppercase X, for example. And here we get back negative one. So the negative one is what a programmer would refer to as a so-called sentinel value. So it's a value that in the context of the find method does not have a real semantic meaning, so what does it really mean to be at index negative one here? So the negative one is just a dummy value, a so-called sentinel value that indicates that the character here is not in the string. Now you may wonder, negative one as we saw in the previous video could be the index negative one, which would be the first character because we're talking about strings coming from the right-hand side. So it would be the dot. So let's compare that. Just a little review. If I take the text object and I index into that with negative one, I get back a period. I personally don't like that we get back negative one here. So this is what I would actually prefer that is my taste of a programming language is that I would get an error message here. So one of the red error messages. Why would I personally prefer that? Well, if I get back a negative one, an object, so in this case negative one that could be somehow interpreted in this case as an index, then this could be a source of semantic errors in your programs because you're looking for some character and the computer program does not find it. It gives you back negative one and maybe you are going to use whatever result you get from the find method in the next line of code to index into something and then it's still going to work because negative one is unfortunately a valid index. So I would personally prefer to get a so-called loud error message. So loud error just means the program just complains to you and it stops basically and we could. We have seen in another previous video how to handle such errors, right? Using the try statement, the try accept statement we can always use to catch errors and do something only if the error occurs. However, here we get back what I sometimes in my notes refer to as a silent error. So it's not really an error here. It's just Python's way of saying we didn't find something here but you simply have to be careful, right? Because negative one could be interpreted. It also works as an index. That is the big problem here. And also just a little side note. The find method also accepts an argument that is longer than the actual character or one character. So for example, I could look for the term Ipsum and I get back index six which means that the seventh character starts the word Ipsum in all lower case. And here also maybe a variant. Let's say if you want to look for the first O that comes after the first O here. So let's say you want to look for the second O in this text object. What you could do is you could provide the find method a second argument which is the start value. So let's provide the start value one. We also get back one because if we start to look at index one then we will find the same O. However, if we start with at the position one plus one in this case, so two really, the index two, then we get back 13 because the next O, which is the first O in the word Dolor, is at the index 13. And then also we could have a third argument which is the upper limit excluded in the range in which we want to search. So if you want to search, let's say some character, but you only want to search in the first half of a sentence, then you could simply set the second or the third argument here to basically half of the length of the text object. Okay, so you have to be a bit careful here, but you can use the find method in all various ways. You probably are going to need it for one of the exercises. So just get used to that, but that is the find method. Another method, let's mention that briefly, is the so-called count method. So let's say if instead of finding the first O, I want to count how many O's are in the text object here, I can simply use the count method. Okay, so a couple of other methods that I don't want to show here because we have seen them in previous videos are of course all the methods that regard the lower and uppercasing, so there is a dot lower method as we saw above, there is a dot uppercase method as well, there is a dot tidal method. Another method, a string method that we have seen previously is for example, the split method, the strip method, sorry, the strip method strips away leading and ending white space and then comes a method that we have not seen in this course, which is the split method. So if I say text.split, what I get back is a list of the individual words in the sentence. So how does the split method work? The split method by default, so if I don't give it an argument, so by default it simply goes ahead and takes whatever text it is invoked on and it simply splits the text into many other string objects separated by white space. So whenever in the actual sentence here, let's say text, there is white space in between something, the white space is used as the default delimiter and now we get back as we see a list of string objects. However, you could also go ahead and give the split method an argument. So let's go ahead and let's split at all the O's, for example, and then I get back a list where all the remains outside the O are there and of course for example, the white space is now part of the word here because white space is not a delimiter here, so we basically are doing something that in this case would probably not be very meaningful, but sometimes you want to split a long string, not by white space. So another very popular example probably is assuming you have watched the previous video or the video two videos ago where we saw that we can create a multi-line string where we also saw how to load in the entire contents from a text file from disk you could basically split a big string at the new line characters and then you get back a list of all the lines, this is also sometimes very useful. And also something that may be useful is the following it's the opposite of split, it's the so-called join method, so let's go ahead and create a list first and let's put in the list a couple of words like this will be a contents let's do it like this and it's also maybe let's leave it that other way but this is just a list of strings and let's say I want to join these words together what I could do is and now comes into play that what I showed you when we started the discussion on strings I showed you that it's sometimes very valuable to simply use a so-called empty string so starting and ending double quotes and on the empty string which is a this is a literal which evaluates into a string object you can of course call methods as well so let's call the dot join method on it and the join method takes as an argument an iterable and a list object is a iterable so we can loop over it and then what it's going to do is the join method is going to join together the words from the list from the iterable and as the delimiter it's going to use whatever we give it here okay so in this case the empty string so nothing basically so this will be this will be basically joined together into one string without any spaces and now if you go ahead and instead of the empty string I give it a string with one space in it I get back one string object so previously I have one two three four five string objects in the list but now I get back one string object that is important that has that consists of all the words joined together okay so this is often something that you see when yeah you want to before you want to print something out let's say you're given some parts and you want to join them together before printing out you often see that in real life code so let's continue and let's assign that to a variable let's say sentence and that simply also look at what sentence is and let's say I want to replace something in a string what you could do is you could use another string method the so-called replace method so let's invoke the replace method on the sentence object here and let's replace the word will be so these two words let's replace this series with simply the word is now what I get back is the word this is a sentence okay however one thing that I just want to remind you of if we look at the actual sentence we still have will be in it okay and the reason why is as we learned at the beginning of this video the string data type is an immutable data type therefore methods that give back some version some probably yeah other string a string that is derived from a string on which we invoke the method then we always get back a new string object and we never get back the same object as we invoke the method on with a different value in it okay so that's kind of important here this is also what you see here okay the methods above some of them returned indices quite naturally but here we have another example of a method returning another string that is basically a version of the actual string we started with and because the method or the string data type is immutable we get back a new string object okay that is the replace method and in the notes you will find a couple of more methods that are not so popular so I will leave it up to you to read it but these are the most important methods on a string and now let's look at something very much related to methods but still different let's look at um um operations so string operations so whenever I use the term method then what I always mean is we simply call a method that is attached to a data type just like that using the dot operator but when I talk about operations what I usually mean is we do something with a string and some operator that is why we call it an operation so let's say I take my sentence and note how we forgot eventually the period at the end of the sentence and let's say I want to add a period at the end what I could do is I could say simply plus and let's add another string to it with a dot the period and now I get back a new string which basically gives me back a string with a dot in it so here we are starting with one string that we already had in memory we create a second string on the fly but only has a dot in it and the two together they are added together and they give me a third memory which is basically the combination of the two and this is also a concept that we have seen before so this is also what we call concatenation so before we called it list concatenation because we saw it in the context of list objects now we call it string concatenation but concatenation really means simply take two things concatenate them together quite easy and of course what we saw with list concatenation was that we could also multiply something, multiply a list object now we can also multiply with integer numbers any string object so let's maybe go ahead and multiply the string high like this we get back 5 highs and then I could also go ahead and say add and say students and this is going to say hi hi hi and so on students so the operations work here just as well just like in the context of list basically let's look at a for to end this video let's look at a special kind of operator so let's look at the relational operators that compare left and the right hand operand so let's maybe make a new section here and let's call it comparison so let's simply go ahead and make an example so that we understand that so let's try to compare apples bananas usually this is not a good comparison so let's go ahead and say apple and let's compare it and by saying is lower than banana and indeed I get a true and the reason why is because the letter a comes before the letter b in the alphabet okay so that is why apple is smaller however if we go ahead and we lower case apple and we compare it with apple case or title case banana I get back a false okay and that may look weird but just note that you will also find that in the second half of chapter 6 in the book but I'm not going to talk about that here in detail in order to model a character you need to do that as a programmer you need to do that by some by using some convention and basically what you can think of is just as we saw in the videos on the binary representation of integers you have a certain sequence of zeros and ones that make up some integer numbers some whole number what you can then do is you can add another layer on top of that and you can basically by convention assign every number every integer number a letter okay and it turns out that the numbers going from zero to 127 so seven bit numbers are usually used to model the so-called ASCII character set sometimes they also use eight bits so it depends on how many special characters you want to add and it turns out that all the uppercase letters are assigned to numbers that are smaller than all the numbers of lowercase letters and therefore because the numbers that corresponds to the uppercase a or corresponds to the lowercase a here is bigger than the number that corresponds to the uppercase b that is why apple is in this case not smaller than banana so one work around here could of course be the following if you have a situation like that if you want to sort for alphabetical order here you could simply go ahead and say let's use the lower method on both sides and this make sure that we are only comparing lowercase characters of course so if in a program you need to compare that and probably you will need that in one of the exercises as well then you simply do the comparison by lower casing the words first let's do one more example of comparison to get another rule down that is very simple and then let's end the video so let's go ahead and compare a couple of names these are going to be german names because that is the example I just could make up easily so let's compare the name for may the month may which is my in german let's compare that for example to the german last name which is called mayer so both may and mayer the name have the same starting sequence the first three letters so now the question is which of the two should come first and the rule is the one that is shorter wins so if you go ahead then the month will simply be smaller than mayer and you could extend that if you go ahead and we say is that smaller than mayer written with a y in german language there are different ways of how to spell the last name mayer there is even another version in the german language written with an e i like this and of course also because the german language is quite nice there is of course also mayer with e y here in it and as we see we can chain the different operators together this is called an example of operator chaining something that we also saw in previous video and this is a comparison a chain comparison that is simply true because all the names that come to the left are smaller than the names that come to the right ok so this is how string methods and operations work and in the next video we will look briefly into the topic of so called string interpolation and then we will end the discussion on strings so i will see you in the next video