1

From a string, I am trying to replace each character with another character, 13 letters ahead in the alphabet. For example, "ABC" would return "NOP".

However, when I get to the end of the alphabet, I can't find a way to loop the index, so that it goes from index [-1] to [0] again and onwards. For example - When I type in "XYZ" it returns "", but it should return "KLM".

Can anyone think of a solution to this?

def rot13(string)   
alphabet = ("a".."z").to_a   
big_alphabet = ("A".."Z").to_a   
result = []   
split_string = string.chars   
alphabet.each_with_index do |item,index|
        if string.include?(alphabet[index])
          result << alphabet[index+13]
        elsif string.include?(big_alphabet[index])
          result << big_alphabet[index+13]   
end 
end 
return result.join 
end
    
2
  • You're trying to implement caesar cipher. Commented Apr 6, 2016 at 10:33
  • More specifically, ROT13 Commented Apr 6, 2016 at 11:37

6 Answers 6

2

Here's the simplest thing that can work (utilizing the little-used String#tr). Gracefully handles non-letters too.

def rot13(str)
  alphabet     = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
  replacements = 'nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM'
  str.tr(alphabet, replacements)
end

rot13('abc') # => "nop"
rot13('nOp 123') # => "aBc 123"
Sign up to request clarification or add additional context in comments.

2 Comments

It can even be shortened to str.tr('a-zA-Z', 'n-za-mN-ZA-M')
@Stefan: oh, nice :)
2

I don't understand your entire code, but if that works for the beginning of the alphabets, then you should perhaps change all index + 13 to (index + 13) % 26, and it should work.

Comments

2

Based on your "source" alphabet:

alphabet = ('a'..'z').to_a
#=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
#    "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]

You could use Array#rotate to create the "destination" alphabet:

alphabet13 = alphabet.rotate(13)
#=> ["n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
#    "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"]

Build a replacement hash by zip-ing both arrays:

replacement = alphabet.zip(alphabet13).to_h
#=> {"a"=>"n", "b"=>"o", "c"=>"p", "d"=>"q", "e"=>"r", "f"=>"s", "g"=>"t",
#    "h"=>"u", "i"=>"v", "j"=>"w", "k"=>"x", "l"=>"y", "m"=>"z",
#    "n"=>"a", "o"=>"b", "p"=>"c", "q"=>"d", "r"=>"e", "s"=>"f", "t"=>"g",
#    "u"=>"h", "v"=>"i", "w"=>"j", "x"=>"k", "y"=>"l", "z"=>"m"}

And use gsub to perform the substitution:

'abc xyz'.gsub(/[a-z]/, replacement)
#=> "nop klm"

You can also use Regexp.union(replacement.keys) instead of the hard coded /[a-z]/.

Replacing the uppercase characters can be done in a separate step or by incorporating them into the replacement hash. I leave that to you.

Comments

1

You can build a hash first, mapping a to n, n to a, A to N, N to A, etc.

Then you simply remap your letters using this hash.

def remap input
    a1 = ("a".."m").to_a
    a2 = ("n".."z").to_a
    a3 = ("A".."M").to_a
    a4 = ("N".."Z").to_a
    letter_map = (a1 + a2 + a3 + a4).zip(a2 + a1 + a4 + a3).to_h

    input.split('').map {|x| letter_map[x] || x}.join
end

If there's no mapping for the letter (eg space, punctuation, digits), you simply use the original letter.

2.2.1 :125 > remap 'john smith'
=> "wbua fzvgu"
2.2.1 :126 > remap 'i love you!'
=> "v ybir lbh!"

Comments

0

You could do this

def rot13(string)
  string.each_codepoint.map { |c|
    new_c = c + 13 # Increment in alphabets
    if ((c.between?('a'.ord, 'z'.ord) && new_c > 'z'.ord) || (c.between?('A'.ord, 'Z'.ord) && new_c > 'Z'.ord))
      new_c -= 26 # This would keep the character within desired range
    end
    new_c.chr
  }.join('')
end

Comments

0
def rot13(str)    
    str.map{|x| x.tr('a-zA-Z', 'n-za-mN-ZA-M')}   
end

1 Comment

Code-only answers are generally frowned upon on this site. Could you please edit your answer to include some comments or explanation of your code? Explanations should answer questions like: What does it do? How does it do it? Where does it go? How does it solve OP's problem? See: How to anwser. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.