Rotating Letters in a String So That Each Letter Is Shifted to Another Letter by N Places

Rotating letters in a string so that each letter is shifted to another letter by n places

Try this:

def play_pass(str, n)
letters = ('a'..'z').to_a
str.chars.map {|x| letters.include?(x.downcase) ?
letters[letters.find_index(x.down_case) + n - letters.size] : x}.join
end

p play_pass("abcdefghijklmnopqrstuvwxyz", 2)

Output

"cdefghijklmnopqrstuvwxyzab"
[Finished in 0.3s]

How it works

letters is an array of chars a to z just the way OP has in his code.
We iterate over all chars in str, and find its index in letters array. Then we add n to that index to get the shifted character. To avoid falling off the array, we subtract letters.size (in this case 26), so that the our lookup into letters is done using value between 0 and 25.

For example: In the scenario that OP pointed out, if the character to be shifted was y, then, adding 2 to its index in letters will give us shifted index 26 (24 is index of y in letters array, 2 is number characters we are shifting in the test case) - To make letters behave like circular array, and not encounter index out of bound type of exception, we subtract letters.size from 26 shifted index. Thus, we get index 0, which represents char a which is what we are interested in.

Another example is case of a - Here the shifted index will be 0 + 2 = 2. When we subtract letters.size from it, we get -24. Ruby allows negative indexes wherein lookup of array element is done from reverse, and it will resolve to correct element. Index -1 is same as Index (size-1), similarly, index value of -size is equal to index 0.

How to shift each letter of the string by a given number of letters?

Do you mean something like ROT13:

pax$ echo 'hello there' | tr '[a-z]' '[n-za-m]'
uryyb gurer

pax$ echo 'hello there' | tr '[a-z]' '[n-za-m]' | tr '[a-z]' '[n-za-m]'
hello there

For a more general solution where you want to provide an arbitrary rotation (0 through 26), you can use:

#!/usr/bin/bash

dual=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
phrase='hello there'
rotat=13
newphrase=$(echo $phrase | tr "${dual:0:26}" "${dual:${rotat}:26}")
echo ${newphrase}

JS: how to shift each letter in the given string N places down in the alphabet?

You need to pass an argument to the fromCharCode method using the String object. Try:

function CaesarCipher(str, num) {    // you can comment this line    str = str.toLowerCase();
var result = ''; var charcode = 0;
for (var i = 0; i < str.length; i++) { charcode = (str[i].charCodeAt()) + num; result += String.fromCharCode(charcode); } return result;
}console.log(CaesarCipher('test', 2));

Function That Receives and Rotates Character - Caesar Cipher

def rotate(letter, rot):
shift = 97 if letter.islower() else 65
return chr((ord(letter) + rot - shift) % 26 + shift)

letter = input('Enter a letter: ')
rot = int(input('Enter a number: '))
print(rotate(letter, rot))

Crazy Challenge: Rotating Letters in Python Encipher Function

Your problem is here:

new_ord = new_ord - (2*n)

The idea is that when you go past z, you have to remove exactly the whole alphabet and not remove twice what you just added.

Try:

new_ord = new_ord - 26

Ruby Cyphering Leads to non Alphanumeric Characters

The reason you get the verbose output is because Ruby is running with UTF-8 encoding, and your conversion has just produced gibberish characters (an invalid character sequence under UTF-8 encoding).

ASCII characters A-Z are represented by decimal numbers (ordinals) 65-90, and a-z is 97-122. When you add 127 you push all the characters into 8-bit space, which makes them unrecognizable for proper UTF-8 encoding.

That's why Ruby inspect outputs the encoded strings in quoted form, which shows each character as its hexadecimal number "\xC7...".

If you want to get some semblance of characters out of this, you could re-encode the gibberish into ISO8859-1, which supports 8-bit characters.

Here's what you get if you do that:

s = "\xC7\xE4\xEB\xEB\xEE \xF6\xEE\xF1\xEB\xE3!"
>> s.encoding
=> #<Encoding:UTF-8>

# Re-encode as ISO8859-1.
# Your terminal (and Ruby) is using UTF-8, so Ruby will refuse to print these yet.
>> s.force_encoding('iso8859-1')
=> "\xC7\xE4\xEB\xEB\xEE \xF6\xEE\xF1\xEB\xE3!"

# In order to be able to print ISO8859-1 on an UTF-8 terminal, you have to
# convert them back to UTF-8 by re-encoding. This way your terminal (and Ruby)
# can display the ISO8859-1 8-bit characters using UTF-8 encoding:
>> s.encode('UTF-8')
=> "Çäëëî öîñëã!"

# Another way is just to repack the bytes into UTF-8:
>> s.bytes.pack('U*')
=> "Çäëëî öîñëã!"

Of course the proper way to do this, is not to let the numbers overflow into 8-bit space under any circumstance. Your encryption algorithm has a bug, and you need to ensure that the output is in the 7-bit ASCII range.

A better solution

Like @tadman suggested, you could use tr instead:

AZ_SEQUENCE = *'A'..'Z' + *'a'..'z'

"Hello world!".tr(AZ_SEQUENCE.join, AZ_SEQUENCE.rotate(127).join)
=> "eBIIL tLOIA!

Rotating strings in Python

You can slice and add strings:

>>> s = 'HELLO'
>>> s[-1] + s[:-1]
'OHELL'

This gives you the last character:

>>> s[-1]
'O'

and this everything but the last:

>>> s[:-1]
'HELL'

Finally, add them with +.



Related Topics



Leave a reply



Submit