<jupyter_start><jupyter_text>Working with stringsRecall from the previous section that strings can be entered with single, double or triple quotes:```python  'All', "of", '''these''', """are  valid strings"""```**Unicode:** Python supports unicode strings - however for the most part this will be ignored in here. If you are workign in an editor that supports unicode you can use non-ASCII characters in strings (or even for variable names). Alternatively typing something like `"\u00B3"` will give you the string "³" (superscript-3).   The Print Statement As seen previously, The `print()` function prints all of its arguments as strings, separated by spaces and follows by a linebreak:    - print("Hello World")    - print("Hello",'World')    - print("Hello", )Note that `print` is different in old versions of Python (2.7) where it was a statement and did not need parentheses around its arguments.<jupyter_code>print("Hello","World")<jupyter_output>Hello World<jupyter_text>The print has some optional arguments to control where and how to print. This includes `sep` the separator (default space) and `end` (end charcter) and `file` to write to a file. When writing to a file, setting the argument `flush=True` may be useful to force the function to write the output immediately. Without this Python may buffer the output which helps to improve the speed for repeated calls to print(), but isn't helpful if you are, for example, wanting to see the output immediately during debugging)<jupyter_code>print("Hello","World",sep='...',end='!!',flush=True)<jupyter_output>Hello...World!!<jupyter_text>String FormatingThere are lots of methods for formating and manipulating strings built into python. Some of these are illustrated here.String concatenation is the "addition" of two strings. Observe that while concatenating there will be no space between the strings.<jupyter_code>string1='World'
string2='!'
print('Hello' + " " + string1 + string2)<jupyter_output>Hello World!<jupyter_text>The `%` operator is used to format a string inserting the value that comes after. It relies on the string containing a format specifier that identifies where to insert the value. The most common types of format specifiers are:    - %s -> string    - %d -> Integer    - %f -> Float    - %o -> Octal    - %x -> Hexadecimal    - %e -> exponential    These will be very familiar to anyone who has ever written a C or Java program and follow nearly exactly the same rules as the [`printf()`](https://en.wikipedia.org/wiki/Printf_format_string) function.<jupyter_code>print("Hello %s" % string1)
print("Actual Number = %d" %18)
print("Float of the number = %f" %18)
print("Octal equivalent of the number = %o" %18)
print("Hexadecimal equivalent of the number = %x" %18)
print("Exponential equivalent of the number = %e" %18)<jupyter_output>Hello World
Actual Number = 18
Float of the number = 18.000000
Octal equivalent of the number = 22
Hexadecimal equivalent of the number = 12
Exponential equivalent of the number = 1.800000e+01<jupyter_text>When referring to multiple variables parentheses is used. Values are inserted in the order they appear in the parantheses (more on tuples in the next section)<jupyter_code>print("Hello %s %s. This meaning of life is %d" %(string1,string2,42))<jupyter_output>Hello World !. This meaning of life is 42<jupyter_text>We can also specify the width of the field and the number of decimal places to be used. For example:<jupyter_code>print('Print width 10: |%10s|'%'x')
print('Print width 10: |%-10s|'%'x') # left justified
print("The number pi = %.2f to 2 decimal places"%3.1415)
print("More space pi = %10.2f"%3.1415)
print("Pad pi with 0 = %010.2f"%3.1415) # pad with zeros<jupyter_output>Print width 10: |         x|
Print width 10: |x         |
The number pi = 3.14 to 2 decimal places
More space pi =       3.14
Pad pi with 0 = 0000003.14<jupyter_text>Other String Methods Multiplying a string by an integer simply repeats it<jupyter_code>print("Hello World! "*5)<jupyter_output>Hello World! Hello World! Hello World! Hello World! Hello World!<jupyter_text>FormattingStrings can be tranformed by a variety of functions that are all methods on a string. That is they are called by putting the function name with a `.` after the string. They include:* Upper vs lower case: `upper()`, `lower()`, `captialize()`, `title()` and `swapcase()` with mostly the obvious meaning. Note that `capitalize` makes the first letter of the string a capital only, while `title` selects upper case for the first letter of every word.* Padding strings: `center(n)`, `ljust(n)` and `rjust(n)` each place the string into a longer string of length n  padded by spaces (centered, left-justified or right-justified respectively). `zfill(n)` works similarly but pads with leading zeros.* Stripping strings: Often we want to remove spaces, this is achived with the functions `strip()`, `lstrip()`, and `rstrip()` respectively to remove from spaces from the both end, just left or just the right respectively. An optional argument can be used to list a set of other characters to be removed.<jupyter_code>s="heLLo wORLd!"
print(s.capitalize(),"vs",s.title())
print("upper: '%s'"%s.upper(),"lower: '%s'"%s.lower(),"and swapped: '%s'"%s.swapcase())
print('|%s|' % "Hello World".center(30)) # center in 30 characters
print('|%s|'% "     lots of space             ".strip()) # remove leading and trailing whitespace
print('%s without leading/trailing d,h,L or ! = |%s|',s.strip("dhL!"))
print("Hello World".replace("World","Class"))<jupyter_output>Hello world! vs Hello World!
upper: 'HELLO WORLD!' lower: 'hello world!' and swapped: 'HEllO WorlD!'
|         Hello World          |
|lots of space|
%s without leading/trailing d,h,L or ! = |%s| eLLo wOR
Hello Class<jupyter_text>Inspecting StringsThere are also lost of ways to inspect or check strings. Examples of a few of these are given here:* Checking the start or end of a string: `startswith("string")` and `endswith("string")` checks if it starts/ends with the string given as argument* Capitalisation: There are boolean counterparts for all forms of capitalisation, such as `isupper()`, `islower()` and `istitle()`* Character type: does the string only contain the characters  * 0-9: `isdecimal()`. Note there is also `isnumeric()` and `isdigit()` which are effectively the same function except for certain unicode characters  * a-zA-Z: `isalpha()` or combined with digits: `isalnum()`  * non-control code: `isprintable()` accepts anything except '\n' an other ASCII control codes  * \t\n \r (white space characters): `isspace()`  * Suitable as variable name: `isidentifier()`* Find elements of string: `s.count(w)` finds the number of times w occurs in s, while `s.find(w)` and `s.rfind(w)` find the first and last position of the string w in s.<jupyter_code>s="Hello World"
print("The length of '%s' is"%s,len(s),"characters") # len() gives length
s.startswith("Hello") and s.endswith("World") # check start/end
# count strings
print("There are %d 'l's but only %d World in %s" % (s.count('l'),s.count('World'),s))
print('"el" is at index',s.find('el'),"in",s) #index from 0 or -1<jupyter_output>The length of 'Hello World' is 11 characters
There are 3 'l's but only 1 World in Hello World
"el" is at index 1 in Hello World<jupyter_text>String comparison operationsStrings can be compared in lexicographical order with the usual comparisons. In addition the `in` operator checks for substrings:<jupyter_code>'abc' < 'bbc' <= 'bbc'
"ABC" in "This is the ABC of Python"<jupyter_output><empty_output><jupyter_text>Accessing parts of strings Strings can be indexed with square brackets. Indexing starts from zero in Python. And the `len()` function provides the length of a string<jupyter_code>s = '123456789'
print("The string '%s' string is %d characters long" % (s, len(s)) )
print('First character of',s,'is',s[0])
print('Last character of',s,'is',s[len(s)-1])<jupyter_output>The string '123456789' string is 9 characters long
First character of 123456789 is 1
Last character of 123456789 is 9<jupyter_text>Negative indices can be used to start counting from the back<jupyter_code>print('First character of',s,'is',s[-len(s)])
print('Last character of',s,'is',s[-1])<jupyter_output>First character of 123456789 is 1
Last character of 123456789 is 9<jupyter_text>Finally a substring (range of characters) an be specified as using $a:b$ to specify the characters at index $a,a+1,\ldots,b-1$. Note that the last charcter is *not* included.<jupyter_code>print("First three characters",s[0:3])
print("Next three characters",s[3:6])<jupyter_output>First three characters 123
Next three characters 456<jupyter_text>An empty beginning and end of the range denotes the beginning/end of the string:<jupyter_code>print("First three characters", s[:3])
print("Last three characters", s[-3:])<jupyter_output>First three characters 123
Last three characters 789<jupyter_text>Breaking appart stringsWhen processing text, the ability to split strings appart is particularly useful. * `partition(separator)`: breaks a string into three parts based on a separator* `split()`: breaks string into words separated by white-space (optionally takes a separator as argument)* `join()`: joins the result of a split using string as separator<jupyter_code>s = "one -> two  ->  three"
print( s.partition("->") )
print( s.split() )
print( s.split(" -> ") )
print( ";".join( s.split(" -> ") ) )<jupyter_output>('one ', '->', ' two  ->  three')
['one', '->', 'two', '->', 'three']
['one', 'two ', ' three']
one;two ; three<jupyter_text>Strings are immutableIt is important that strings are constant, immutable values in Python. While new strings can easily be created it is not possible to modify a string:<jupyter_code>s='012345'
sX=s[:2]+'X'+s[3:] # this creates a new string with 2 replaced by X
print("creating new string",sX,"OK")
sX=s.replace('2','X') # the same thing
print(sX,"still OK")
s[2] = 'X' # an error!!!<jupyter_output>creating new string 01X345 OK
01X345 still OK
{'fraction_non_alphanumeric': 0.11724137931034483, 'fraction_numerical': 0.02208895552223888, 'mean_word_length': 5.289126335637963, 'pattern_counts': {'":': 0, '<': 52, '<?xml version=': 0, '>': 65, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, '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': '16', 'dir': 'jupyter-structured-clean-dedup', 'id': '132498', 'license': 'CC-BY-3.0', 'n_tokens_mistral': 3159, 'n_tokens_neox': 2935, 'n_words': 1262, 'path': 'Intro-to-Python/02.ipynb', 'repo_name': 'ClemensHa/python_notebook_tutorial', 'size': '10005'}