Skip to content

Commit b6185ec

Browse files
committed
Changes and Corrections for rotational-cipher
Edits, spelling, and grammer nits.
1 parent 9580dd8 commit b6185ec

File tree

6 files changed

+120
-89
lines changed

6 files changed

+120
-89
lines changed

exercises/practice/rotational-cipher/.approaches/alphabet/content.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,28 @@ def rotate(text, key):
1616
return result
1717
```
1818

19-
The approach starts with defining the a constant which holds the whole alphabets lowercase letters.
20-
After that the function `rotate` is declared, then a variable `result` is defined with the value of an empty string.
19+
The approach starts with defining the constant `ALPHABET` which is a string of all lowercase letters.
20+
The function `rotate()` is then declared, and a variable `result` is defined as an empty string.
2121

22-
Then is all the letters from the text argument iterated over through a [`for loop`][for-loop].
23-
Then is checked if the letter is a letter, if it is a letter then is checked if it is a uppercased letter.
22+
The text argument is then iterated over via a [`for loop`][for-loop].
23+
Each element is checked to make sure it is a letter, and subsequently checked if it is uppercase or lowercase.
24+
Uppercase letters are converted to lowercase.
25+
Then index of each letter is found in the `AlPHABET` constant.
26+
The numeric key value is added to the letter index and [modulo (`%`)][modulo] 26 is used on the result.
27+
Finally, the new number is used as an index into the `AlPHABET` constant, and the resulting letter is converted back to uppercase.
2428

25-
If it is a uppercased letter then it is converted to lowe case and finds its index in the `AlPHABET` constant.
26-
Then is the key added to the index and [modulo (`%`)][modulo] 26 is used on the result.
27-
Then is the letter at the index found in the `AlPHABET` constant and the letter is converted to upcase.
29+
Lowercase letters follow the same process without the conversion steps.
2830

29-
If the letter is a lowercased letter then it does the same process but don't convert the letter to downcase and then to uppercase.
31+
If the element is not a letter (for example, space or punctuation) then it is added directly to the result string.
32+
The result string is returned once the loop finishes.
3033

31-
If the letter is not a letter then is the letter added to the result.
32-
When the loop is finished we return the result.
34+
If only English letters are needed, the constant [`string.ascii_lowercase`][ascii_lowercase] can be imported from the [`string`][string] module.
3335

34-
If you only want to use english letters so could you import the alphabet instead of defining it yourself.
35-
Since in the [`string`][string] module there is a constant called [`ascii_lowercase`][ascii_lowercase] which holds the lowercased alphabet.
3636

3737
```python
38-
import string
38+
from string import ascii_lowercase
3939

40-
AlPHABET = string.ascii_lowercase
40+
AlPHABET = ascii_lowercase
4141
```
4242

4343
[ascii_lowercase]: https://docs.python.org/3/library/string.html#string.ascii_letters

exercises/practice/rotational-cipher/.approaches/ascii-values/content.md

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,37 +14,44 @@ def rotate(text, key):
1414
return result
1515
```
1616

17-
This approach uses [ascii values][ascii], ascii stands for American Standard Code for Information Interchange.
18-
It is a character encoding standard for electronic communication.
19-
It is a 7-bit code, which means that it can represent 128 different characters.
20-
The system uses numbers to represent various characters, symbols, and other entities.
17+
This approach uses [ascii values][ascii].
18+
ASCII stands for **A**merican **S**tandard **C**ode for **I**nformation **I**nterchange.
19+
It is a 7-bit character encoding standard for electronic communication first described in 1969, becoming a formal standard in 2015.
20+
It uses numbers to represent 128 different entities including carriage returns, whitespace characters, box characters, alphabetic characters, punctuation, and the numbers 0-9.
2121

22-
In ascii can you find all the downcased letter in the range between 97 and 123.
23-
While the upcased letters are in the range between 65 and 91.
22+
In ascii, all the lowercase English letters appear between 97 and 123.
23+
While the uppercase letters are in the range between 65 and 91.
2424

25-
The reason why you might not want to do this approach is that it only supports the english alphabet.
25+
~~~~exercism/caution
2626
27-
The approach starts with defining the function `rotate`, then a variable `result` is defined with the value of an empty string.
28-
Then is all the letters from the text argument iterated over through a [`for loop`][for-loop].
29-
Then is checked if the letter is a letter, if it is a letter then is checked if it is a uppercased letter.
27+
This approach only supports the English alphabet.
28+
Non-English alphabets are not contiguous in their ascii number ranges, and are not consistently defined across platforms.
29+
For example, the Scandinavian letter: **å** has the extended ascii value of 132, but is used in combination with Latin characters that appear in the 65-91 and 97-123 ranges.
30+
This means that a shift for an extended ascii word containing **å** won't result in an accurate alphabet position for a Scandinavian language.
3031
31-
Python has a built in function called `ord` that converts a [unicode][unicode] symbol to an integer.
32-
The unicode's first 128 characters are the same as ascii.
32+
~~~~
3333

34-
If it is a uppercased letter then is [`ord`][ord] used to convert the letters to an integer and is then added with the key and then subtracted with 65.
35-
Then is the result of that [modulo (`%`)][modulo] 26 added with 65.
3634

37-
That is because we want to know which index in the alphabet the letter is.
38-
And if the number is over 26 we want to make sure that it is in the range of 0-26.
39-
So we use modulo to make sure it is in that range.
40-
To use modulo for a range we have to make sure that it starts at zero, thereby are we subtracting the integer value of the letter with 65.
41-
After that to get the back to a letter we add 65 and use the [`chr`][chr] method which converts an an unicode value to a letter.
42-
After that is the new letter added to the result.
35+
The approach starts with defining the function `rotate()`, with a variable `result` is assigned to an empty string.
36+
The elements of the text argument are then iterated over using a [`for loop`][for-loop].
37+
Each element is checked to see if it is a letter, and then is checked if it is an uppercase letter.
4338

44-
If the letter is a lowercased letter then is the same done but with the ascii value of 97 subtracted with the letter.
39+
Python has a builtin function called `ord` that converts a [unicode][unicode] symbol to an integer representation.
40+
Unicode's first 128 code points have the same numbers as their ascii counterparts.
4541

46-
If the letter is not a letter then is the letter added to the result.
47-
When the loop is finished we return the result.
42+
If the element is an uppercase letter, [`ord`][ord] is used to convert the letter to an integer.
43+
The integer is added to the numeric key and then 65 is subtracted from the total.
44+
Finally, the result is [modulo (`%`)][modulo] 26 (_to put the value within the 2) and 65 is added back.
45+
46+
This is because we want to know which letter of the alphabet the number will become.
47+
And if the new number is over 26 we want to make sure that it "wraps around" to remain in the range of 0-26.
48+
To properly use modulo for a range we have to make sure that it starts at zero, so we subtract 65.
49+
To get back to a letter in the asciii range we add 65 and use the [`chr`][chr] method to convert the value to a letter.
50+
51+
The process is the same for a lowercase letter, but with 97 subtracted to put the letter in the lowercase ascii range of 97 - 123.
52+
53+
Any element that is not a letter (_whitespace or punctuation_) is added directly to the result string.
54+
When all the elements have been looped over, the full result is returned.
4855

4956
[ascii]: https://en.wikipedia.org/wiki/ASCII
5057
[chr]: https://docs.python.org/3/library/functions.html#chr

exercises/practice/rotational-cipher/.approaches/introduction.md

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,30 @@
11
# Introduction
22

33
There are various ways to solve `rotational-cipher`.
4-
You can for example use a [ascii values][ascii], alphabet, recursion, and `str.translate`.
4+
You can for example use [ascii values][ascii], an alphabet `str` or `list`, recursion, or `str.translate`.
5+
56

67
## General guidance
78

8-
The goal of this exercise is to rotate the letters in a string by a given key.
9+
The goal of this exercise is to shift the letters in a string by a given integer key between 0 and 26.
10+
The letter in the encrypted string is shifted for as many values (or "positions") as the value of the key.
911

1012
## Approach: Using ascii values
1113

12-
This approach is very simple and easy to understand.
13-
it uses the ascii value of the letters to rotate them.
14-
There the numbers 65-91 in the ascii range represent downcased letters.
15-
While 97-123 represent upcased letters.
14+
This approach is straightforward to understand.
15+
It uses the ascii value of the letters to rotate them within the message.
16+
The numbers 65-91 in the ascii range represent lowercase Latin letters, while 97-123 represent uppercase Latin letters.
17+
18+
19+
~~~~exercism/caution
20+
21+
This approach only supports the English alphabet.
22+
Non-English alphabets are not contiguous in their ascii number ranges, and are not consistently defined across platforms.
23+
For example, the Scandinavian letter: **å** has the extended ascii value of 132, but is used in combination with Latin characters that appear in the 65-91 and 97-123 ranges.
24+
This means that a shift for an extended ascii word containing **å** won't result in an accurate alphabet position for a Scandinavian language.
25+
26+
~~~~
1627

17-
The reason why you might not want to do this approach is that it only supports the english alphabet.
18-
Say we want to use the scandinavian letter: **å**, then this approach will not work.
19-
Since **å** has the ascii value of 132.
2028

2129
```python
2230
def rotate(text, key):
@@ -34,16 +42,20 @@ def rotate(text, key):
3442

3543
For more information, check the [ascii values approach][approach-ascii-values].
3644

45+
3746
## Approach: Alphabet
3847

39-
This approach is similar to the previous one, but instead of using the ascii values, it uses the index of the letter in the alphabet.
40-
It requires the storing of a string and unless you are using two strings you have to convert the letters from upper to lower case.
48+
This approach is similar to the ascii one, but it uses the index number of each letter in an alphabet string.
49+
It requires making a string for all the letters in an alphabet.
50+
And unless two strings are used, you will have to convert individual letters from lower to upper case (or vice-versa).
51+
52+
The big advantage of this approach is the ability to use any alphabet (_although there are some issues with combining characters in Unicode._).
53+
Here, if we want to use the scandinavian letter: **å**, we can simply insert it into our string where we want it:
54+
`abcdefghijklmnopqrstuvwxyzå` and the rotation will work correctly.
4155

42-
What this approach although give is the possibility to use any alphabet.
43-
Say we want to use the scandinavian letter: **å**, then we just add it where we want it:
44-
`abcdefghijklmnopqrstuvwxyzå` and it will rotate correctly around that.
4556

4657
```python
58+
# This only uses English characters
4759
AlPHABET = "abcdefghijklmnopqrstuvwxyz"
4860

4961
def rotate(text, key):
@@ -61,14 +73,19 @@ def rotate(text, key):
6173

6274
For more information, check the [Alphabet approach][approach-alphabet].
6375

76+
6477
## Approach: Str translate
6578

66-
This approach is similar to the previous one, but instead of using the index of the letter in the alphabet, it uses the `str.translate` method.
67-
The benefit of this approach is that it has no visible loop, thereby the code becomes more concise.
68-
What to note is that the `str.translate` still loops over the `string` thereby even if it is no visible loop, it doesn't mean that a method is not looping.
79+
This approach uses the [`str.translate`][str-translate] method to create a mapping from input to shifted string instead of using the index of an alphabet string to calculate the shift.
80+
The benefit of this approach is that it has no visible loop, making the code more concise.
81+
82+
~~~~exercism/note
83+
`str.translate` **still loops over the `string`** even if it is not visibly doing so.
84+
~~~~
85+
6986

7087
```python
71-
AlPHABET = "abcdefghijklmnopqrstuvwxyz"
88+
AlPHABET = "abcdefghijklmnopqrstuvwxyz
7289

7390
def rotate(text, key):
7491
translator = AlPHABET[key:] + AlPHABET[:key]
@@ -77,13 +94,19 @@ def rotate(text, key):
7794

7895
For more information, check the [Str translate approach][approach-str-translate].
7996

97+
8098
## Approach: Recursion
8199

82-
In this approach we use a recursive function.
100+
This approach uses a recursive function.
83101
A recursive function is a function that calls itself.
84102
This approach can be more concise than other approaches, and may also be more readable for some audiences.
85103

86-
The reason why you might not want to use this approach is that Python has a [recursion limit][recursion-limit] with a default of 1000.
104+
105+
~~~~exercism/caution
106+
Python does not have any tail-call optimization and has a default [recursion limit][recursion-limit] of 1000 calls on the stack.
107+
Calculate your base case carefully to avoid errors.
108+
~~~~
109+
87110

88111
```python
89112
AlPHABET = "abcdefghijklmnopqrstuvwxyz"
@@ -103,6 +126,7 @@ def rotate(text, key):
103126

104127
For more information, check the [Recursion approach][approach-recursion].
105128

129+
106130
## Benchmark
107131

108132
For more information, check the [Performance article][article-performance].
@@ -114,3 +138,4 @@ For more information, check the [Performance article][article-performance].
114138
[approach-alphabet]: https://exercism.org/tracks/python/exercises/rotational-cipher/approaches/alphabet
115139
[article-performance]: https://exercism.org/tracks/python/exercises/rotational-cipher/articles/performance
116140
[recursion-limit]: https://docs.python.org/3/library/sys.html#sys.setrecursionlimit
141+
[str-translate]: https://docs.python.org/3/library/stdtypes.html?highlight=str%20translate#str.translate

exercises/practice/rotational-cipher/.approaches/recursion/content.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,25 @@ def rotate(text, key):
1616
return first_letter + rotate(rest, key)
1717
```
1818

19-
This approach uses a very similar approach to alphabet.
20-
And uses the same logic but instead of a loop so does this approach use [concept:python/recursion]() to solve the problem.
19+
This approach uses the same logic as that of the `alphabet` approach, but instead of a `loop`, [concept:python/recursion]() is used to parse the text and solve the problem.
2120

2221
Recursion is a programming technique where a function calls itself.
23-
It is a powerful technique, but can be more tricky to implement than a while loop.
24-
Recursion isn't that common in Python, it is more common in functional programming languages, like: [Elixir][elixir], [Haskell][haskell], and [Clojure][clojure].
22+
It is powerful, but can be more tricky to implement than a `while loop` or `for loop`.
23+
Recursive techniques are more common in functional programming languages like [Elixir][elixir], [Haskell][haskell], and [Clojure][clojure] than they are in Python.
2524

26-
Solving this exercise with recursion removes the need for a "result" variable and the instantiation of a `loop`.
25+
Solving this exercise with recursion removes the need for a `result` variable and the instantiation of a `loop`.
2726
If the number is not equal to one, we call `<letter> + rotate(rest)`.
2827
Then the `rotate` function can execute the same code again with new values.
29-
Meaning we can get a long chain or stack of `<letter> + rotate(rest)` until the rest variable is exhausted and then the code adds `""`.
28+
We can build a long chain or "stack" of `<letter> + rotate(rest)` calls until the `rest` variable is exhausted and the code adds `""`.
3029
That translates to something like this: `<letter> + <letter> + <letter> + <letter> + ""`.
3130

32-
In Python, we can't have a function call itself more than 1000 times by default.
33-
Code that exceeds this recursion limit will throw a [RecursionError][recursion-error].
34-
While it is possible to adjust the [recursion limit][recursion-limit], doing so risks crashing Python and may also crash your system.
31+
32+
~~~~exercism/note
33+
By default, we can't have a function call itself more than 1000 times.
34+
Code that exceeds this recursion limit will throw a RecursionError.
35+
While it is possible to adjust the recursion limit, doing so risks crashing Python and may also crash your system.
3536
Casually raising the recursion limit is not recommended.
37+
~~~~
3638

3739
[clojure]: https://exercism.org/tracks/clojure
3840
[elixir]: https://exercism.org/tracks/elixir

exercises/practice/rotational-cipher/.approaches/str-translate/content.md

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,45 +8,42 @@ def rotate(text, key):
88
return text.translate(str.maketrans(AlPHABET + AlPHABET.upper(), translator + translator.upper()))
99
```
1010

11-
This approach uses the [`<str>.translate`][translate] method to solve the problem.
11+
This approach uses the [`<str>.translate`][translate] method.
1212
`translate` takes a translation table as an argument.
1313
To create a translation table we use [str.`makestrans`][maketrans].
1414

15-
The approach starts with defining the a constant which holds the whole alphabets lowercase letters.
16-
Then the function `rotate` is declared.
17-
Then is the `translator` variable defined with the value of the `AlPHABET` constant [sliced][slicing] from the key to the end and then the `AlPHABET` constant sliced from the start to the key.
15+
This approach starts with defining a constant of all the lowercase letters in the alphabet.
16+
Then the function `rotate()` is declared.
17+
A `translator` variable defined with the value of the `AlPHABET` constant [sliced][slicing] from the key to the end and then sliced from the start to the key.
1818

19-
This is done so we have 2 strings which are the same but shifted by the key.
19+
This is done so we have 2 strings which are the same but shifted by the key value.
2020
Say we have the `AlPHABET` constant with the value of `abcdefghijklmnopqrstuvwxyz` and the key is 3.
2121
Then the `translator` variable will have the value of `defghijklmnopqrstuvwxyzabc`.
2222

23-
Then is the `translate` method called on the `text` argument.
24-
The `translate` method takes a translation table as an argument.
25-
To create a translation table we use str.`makestrans`maketrans.
23+
`str.translate` is then called on the `text` argument.
24+
`str.translate` takes a translation table mapping start values to transformed values as an argument.
25+
To create a translation table, `str.makestrans` is used.
26+
`makestrans` takes 2 arguments: the first is the string to be translated, and the second is the string the first argument should be translated to.
2627

27-
The `makestrans` method takes 2 arguments.
28-
The first argument is the string which holds the characters which should be translated.
29-
The second argument is the string which holds the characters which the characters from the first argument should be translated to.
28+
For our solution, the first argument is the `AlPHABET` constant + the `AlPHABET` constant in uppercase.
29+
The second argument is the `translator` variable + uppercase `translator` variable.
3030

31-
The first argument is the `AlPHABET` constant and the `AlPHABET` constant uppercased.
32-
The second argument is the `translator` variable and the `translator` variable uppercased.
31+
`makestrans` does is that it takes the [Unicode][unicode] values of the first argument and maps them to the corresponding Unicode values in the second argument, creating a `dict`.
3332

34-
What the `makestrans` does is that it takes the first argument and maps it to the second argument.
35-
It does that by creating a [dictionary], and converting the letter to [unicode][unicode].
3633

3734
```python
3835
>>> str.maketrans("abc", "def")
3936
{97: 100, 98: 101, 99: 102}
4037
```
4138

42-
The `translate` method takes the dictionary created by the `makestrans` method and uses it to translate the characters in the `text` argument.
39+
`str.translate` takes the `dict` created by `str.makestrans` and uses it to translate the characters in the `text` argument.
4340

4441
```python
4542
>>> "abc".translate({97: 100, 98: 101, 99: 102})
4643
'def'
4744
```
4845

49-
When the loop is finished we return the result.
46+
Once the `str.translate` loop completes, we return the `result`.
5047

5148
[maketrans]: https://docs.python.org/3/library/stdtypes.html#str.maketrans
5249
[slicing]: https://www.w3schools.com/python/python_strings_slicing.asp

0 commit comments

Comments
 (0)