Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement Caesar cipher-like text substitution in Vim?

Tags:

vim

I was doing some puzzle where each English letter is replaced by the one two letters down the alphabet. For example, the word apple is to be transformed into crrng, as a + 2 → c, b + 2 → d, etc.

In Python, I was able to implement this transformation using the maketrans() string method. I wonder: Is it possible to do the same via search and replace in Vim?

like image 892
hari Avatar asked Oct 07 '11 07:10

hari


1 Answers

1. If the alphabetic characters are arranged sequentially in the target encoding (as is the case for ASCII and some alphabets in UTF-8, like English), one can use the following substitution command:

:%s/./\=nr2char(char2nr(submatch(0))+2)/g

(Before running the command, make sure that the encoding option is set accordingly.)

However, this replacement implements a non-circular letter shift. A circular shift can be implemented by two substitutions separately handling lowercase and uppercase letters:

:%s/\l/\=nr2char(char2nr('a') + (char2nr(submatch(0)) - char2nr('a') + 2) % 26)/g
:%s/\u/\=nr2char(char2nr('A') + (char2nr(submatch(0)) - char2nr('A') + 2) % 26)/g

2. Another way is to translate characters using the tr() function. Let us assume that the variable a contains lowercase characters of an alphabet arranged in correct order, and the variable a1 hold the string of characters corresponding to those in a (below is an example for English letters).

:let a = 'abcdefghijklmnopqrstuvwxyz'
:let a1 = a[2:] . a[:1]

To avoid typing the whole alphabet by hand, the value of a can be produced as follows:

:let a = join(map(range(char2nr('a'), char2nr('z')), 'nr2char(v:val)'), '')

Then, to replace each letter on a line by the letter two positions down the alphabet, one can use the following substitution:

:%s/.*/\=tr(submatch(0), a . toupper(a), a1 . toupper(a1))
like image 82
ib. Avatar answered Oct 11 '22 13:10

ib.