Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions python2/koans/about_string_manipulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,38 +10,38 @@ def test_use_format_to_interpolate_variables(self):
value1 = 'one'
value2 = 2
string = "The values are {0} and {1}".format(value1, value2)
self.assertEqual(__, string)
self.assertEqual("The values are one and 2", string)

def test_formatted_values_can_be_shown_in_any_order_or_be_repeated(self):
value1 = 'doh'
value2 = 'DOH'
string = "The values are {1}, {0}, {0} and {1}!".format(value1, value2)
self.assertEqual(__, string)
self.assertEqual("The values are DOH, doh, doh and DOH!", string)

def test_any_python_expression_may_be_interpolated(self):
import math # import a standard python module with math functions

decimal_places = 4
string = "The square root of 5 is {0:.{1}f}".format(math.sqrt(5), \
decimal_places)
self.assertEqual(__, string)
self.assertEqual("The square root of 5 is 2.2361", string)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

27 string = "The square root of 5 is {0:.{1}f}".format(math.sqrt(5), \decimal_places)
I'm not sure about what the {0:.{1}f exactly does

See this and this.

In short {0:.{1}f} is saying: get the argument {0}, but add formatting to it, interpreting as a floating point value (the f) and such that the precision (number of digits after the decimal point) is whatever the value of the {1} argument says (in this case, 4).

I hope that helps. Play with it a little, it's very similar to C-language string formatting.

Copy link
Collaborator

@glpuga glpuga Dec 11, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given:

days = dict()
days["Mercury"] = 87.96
days["Venus"] = 224.68
days["Earth"] = 365.26
days["Mars"] = 686.98

Printing this with:

for key,value in days.items():
     print("{0} {1}".format(key, value))

Looks ugly for a user interface (try). Give me a code snippet that prints this in tidy columns, using 10 characters for the planet name field width, and 20 for the period revolution days, with 3 for the precision. It should look like this:

Mercury        87.960
Earth         365.260
Venus         224.680
Mars          686.980

PS: Notice the rows are not in the same order as I added them to the dict...why?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think is ordering by the key with a higher value, but I'm not sure.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think is ordering by the key with a higher value, but I'm not sure.

Think again https://github.com/stevendes/python_koans/pull/6/files#diff-7ff6c7eb24ff198b3e2fab6c93748dd2R36

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about the code I asked above?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So it's because the dictionary doesn't really have an order?


def test_you_can_get_a_substring_from_a_string(self):
string = "Bacon, lettuce and tomato"
self.assertEqual(__, string[7:10])
self.assertEqual("let", string[7:10])

def test_you_can_get_a_single_character_from_a_string(self):
string = "Bacon, lettuce and tomato"
self.assertEqual(__, string[1])
self.assertEqual("a", string[1])

def test_single_characters_can_be_represented_by_integers(self):
self.assertEqual(__, ord('a'))
self.assertEqual(__, ord('b') == (ord('a') + 1))
self.assertEqual(97, ord('a'))
self.assertEqual(True, ord('b') == (ord('a') + 1))

def test_strings_can_be_split(self):
string = "Sausage Egg Cheese"
words = string.split()
self.assertEqual([__, __, __], words)
self.assertEqual(["Sausage", "Egg", "Cheese"], words)

def test_strings_can_be_split_with_different_patterns(self):
import re # import python regular expression library
Expand All @@ -51,26 +51,26 @@ def test_strings_can_be_split_with_different_patterns(self):

words = pattern.split(string)

self.assertEqual([__, __, __, __], words)
self.assertEqual(["the", "rain", "in", "spain"], words)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

50 pattern = re.compile(',|;')
I'm also not sure how this works

This is an example of a Regular Expression (regexp, for short). Notice that the re module is imported first. See this for an introduction. You'll see more of this later, don't worry.

In short, split splits the string into sub-strings separated by instances of pattern, whereas the pattern ,|; matches whenever you find a , OR a ;.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: Say I have a string with a human readable list of ingredients: "flour, tomato souse, 2 eggs, cheese, ham, and olives". Find a regex pattern that will split that string into a list of ingredients for a machine, such as [ "flour", "tomato souse", "2 eggs", "cheese", "ham", "olives"]

Copy link
Owner Author

@stevendes stevendes Dec 11, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could that be pattern=re.compile(,) ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nop, there are spaces and and 'and" too! You'll need a pattern that matches those too.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think my best option is pattern=re.compile(,|and), because including the space separates the 2 and the eggs


# `pattern` is a Python regular expression pattern which matches
# ',' or ';'

def test_raw_strings_do_not_interpret_escape_characters(self):
string = r'\n'
self.assertNotEqual('\n', string)
self.assertEqual(__, string)
self.assertEqual(__, len(string))
self.assertEqual("\\n", string)
self.assertEqual(2, len(string))

# Useful in regular expressions, file paths, URLs, etc.

def test_strings_can_be_joined(self):
words = ["Now", "is", "the", "time"]
self.assertEqual(__, ' '.join(words))
self.assertEqual("Now is the time", ' '.join(words))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notice the difference between " ".join(words) and "".join(words).

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The string at the start is the separator, right?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right. If you execute 'SEP'.join(words) you'll get 'NowSEPisSEPtheSEPtime'.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same with any other string.


def test_strings_can_change_case(self):
self.assertEqual(__, 'guido'.capitalize())
self.assertEqual(__, 'guido'.upper())
self.assertEqual(__, 'TimBot'.lower())
self.assertEqual(__, 'guido van rossum'.title())
self.assertEqual(__, 'ToTaLlY aWeSoMe'.swapcase())
self.assertEqual("Guido", 'guido'.capitalize())
self.assertEqual("GUIDO", 'guido'.upper())
self.assertEqual("timbot", 'TimBot'.lower())
self.assertEqual("Guido Van Rossum", 'guido van rossum'.title())
self.assertEqual("tOtAlLy AwEsOmE", 'ToTaLlY aWeSoMe'.swapcase())