82 lines
2.7 KiB
Text
82 lines
2.7 KiB
Text
Rebol [
|
|
Title: "Rot-13"
|
|
URL: http://rosettacode.org/wiki/Rot-13
|
|
]
|
|
|
|
; Test data has upper and lower case characters as well as characters
|
|
; that should not be transformed, like numbers, spaces and symbols.
|
|
|
|
text: "This is a 28-character test!"
|
|
|
|
print "Using cipher table:"
|
|
|
|
; I build a set of correspondence lists here. 'x' is the letters from
|
|
; A-Z, in both upper and lowercase form. Note that REBOL can iterate
|
|
; directly over the alphabetic character sequence in the for loop. 'y'
|
|
; is the cipher form, 'x' rotated by 26 characters (remember, I have
|
|
; the lower and uppercase forms together). 'r' holds the final result,
|
|
; built as I iterate across the 'text' string. I search for the
|
|
; current character in the plaintext list ('x'), if I find it, I get
|
|
; the corresponding character from the ciphertext list
|
|
; ('y'). Otherwise, I pass the character through untransformed, then
|
|
; return the final string.
|
|
|
|
rot-13: func [
|
|
"Encrypt or decrypt rot-13 with tables."
|
|
text [string!] "Text to en/decrypt."
|
|
/local x y r i c
|
|
] [
|
|
x: copy "" for i #"a" #"z" 1 [append x rejoin [i uppercase i]]
|
|
y: rejoin [copy skip x 26 copy/part x 26]
|
|
r: copy ""
|
|
|
|
repeat i text [append r either c: find/case x i [y/(index? c)][i]]
|
|
r
|
|
]
|
|
|
|
; Note that I am setting the 'text' variable to the result of rot-13
|
|
; so I can reuse it again on the next call. The rot-13 algorithm is
|
|
; reversible, so I can just run it again without modification to decrypt.
|
|
|
|
print [" Encrypted:" text: rot-13 text]
|
|
print [" Decrypted:" text: rot-13 text]
|
|
|
|
|
|
print "Using parse:"
|
|
|
|
clamp: func [
|
|
"Contain a value within two enclosing values. Wraps if necessary."
|
|
x v y
|
|
][
|
|
x: to-integer x v: to-integer v y: to-integer y
|
|
case [v < x [y - v] v > y [v - y + x - 1] true v]
|
|
]
|
|
|
|
; I'm using REBOL's 'parse' word here. I set up character sets for
|
|
; upper and lower-case letters, then let parse walk across the
|
|
; text. It looks for matches to upper-case letters, then lower-case,
|
|
; then skips to the next one if it can't find either. If a matching
|
|
; character is found, it's mathematically incremented by 13 and
|
|
; clamped to the appropriate character range. parse changes the
|
|
; character in place in the string, hence this is a destructive
|
|
; operation.
|
|
|
|
rot-13: func [
|
|
"Encrypt or decrypt rot-13 with parse."
|
|
text [string!] "Text to en/decrypt. Note: Destructive!"
|
|
] [
|
|
u: charset [#"A" - #"Z"]
|
|
l: charset [#"a" - #"z"]
|
|
|
|
parse text [some [
|
|
i: ; Current position.
|
|
u (i/1: to-char clamp #"A" i/1 + 13 #"Z") | ; Upper case.
|
|
l (i/1: to-char clamp #"a" i/1 + 13 #"z") | ; Lower case.
|
|
skip]] ; Ignore others.
|
|
text
|
|
]
|
|
|
|
; As you see, I don't need to re-assign 'text' anymore.
|
|
|
|
print [" Encrypted:" rot-13 text]
|
|
print [" Decrypted:" rot-13 text]
|