Guru's please help improve ROT13 algorithm !
[1/4] from: apwing:zonnet:nl at: 14-Dec-2003 19:39
Hi all,
today I found a website having a lot of implementations in different programming languages
of the ROT13 algorithm http://www.miranda.org/~jkominek/rot13/
Now I'm only a REBOL newbie, but I guess the REBOL implementation could be much better.
Also the person who wrote it says the wrong things about REBOL (I think). Apart from
that it was written in 1998, so REBOL has improved since as well.
Perhaps you guru's can help improve?
Met vriendelijke groet / with kind regards,
Arie van Wingerden
http://home.zonnet.nl/rebolution
[2/4] from: SunandaDH:aol at: 14-Dec-2003 14:21
There is a ROT-13 implementation by Allen Kamp in the Script Library:
http://www.rebol.org/cgi-bin/cgiwrap/rebol/view-script.r?script=rot-13.r
Sunanda.
[3/4] from: joel::neely::fedex::com at: 14-Dec-2003 15:24
I submitted a cleaner one (than what's on the ROT13 page) along with
some remarks, and copied the list here, and then saw Sunanda's reply:
[SunandaDH--aol--com] wrote:
WRT that version, I'll add my $0.02...
rot-13: func [
{Converts a string to or from Rot-13}
data [any-string!]
/local scrambled rot-chars rot-char
][
rot-chars:
{anabobcpcdqderefsfgtghuhivijwjkxklylmzmANABOBCPCDQDEREFSFGTGHUHIVIJWJKXKLYLMZM}
scrambled: copy ""
foreach char data [
if none? (rot-char: select/case rot-chars char) [rot-char: char]
insert tail scrambled :rot-char
]
return scrambled
]
My suggestions follow:
1) I prefer to avoid typo-prone strings when I can.
2) Both the above and my submission to the ROT13 site would benefit
from comments explaining the construction of the translation
string as related to SELECT/CASE. It is a nice REBOL-ism that
we only need 39 characters per case as opposed to 52!
3) I'd rather initialize the result as an empty string with the full
(known) length preallocated to avoid excessive memory management
overhead for longer arguments.
4) The use of the get-word (:ROT-CHAR) is surprising (but marginally
defensible by speed?)
5) The if-none-then-use-default pattern is a great opportunity to use
another REBOL-ism, ANY.
I did a little benchmarking with four versions:
code
- is the version from my earlier post,
if/get
- replaces the FOREACH body with
if none? cc: select/case xlate ch [cc: ch]
insert tail result :cc
similar to the version in the script library
if
- simply replaces the get-word (:CC) with the word itself
if none? cc: select/case xlate ch [cc: ch]
insert tail result cc
either
- evaluates the replacement character as an expression
as the last argument of the INSERT
insert tail result
either none? cc: select/case xlate ch [ch] [cc]
The results of a quick timing test (50,000 evaluations of each
function on a 243-character string) are
>> rot13/time-it 50000 datum
code: 108.356
if/get: 132.24
if: 133.502
either: 137.117
The use of the get-word saves about 1% to the run-time of the function
(if/get vs is). The time for EITHER vs IF was a bit of a surprise to
me, because it added another 3-4% to the run time.
Comparing the object/method version vs a stand-alone function, we can
pull a REBOL-persistence-of-series trick:
rot13: func [s [string!] /local result xlate] [
if empty? xlate: "" [
for ch #"a" #"m" 1 [append xlate reduce [ch ch + 13 ch]]
for ch #"A" #"M" 1 [append xlate reduce [ch ch + 13 ch]]
]
result: make string! length? s
foreach ch s [
insert tail result any [select/case xlate ch ch]
]
result
]
(not that I'd ever write somehing like that, for several reasons ;-)
or embed the translation strings in place of the local XLATE, and get
the following timings:
>> fn-vs-obj 50000 datum
method: 108.255
stateful: 107.405
stateless: 107.514
where "stateful" is the above ROT13 function, and "stateless" uses the
literal instead of persistence.
Any critiques or suggestions for improvement to my object-based version
are welcome!
-jn-
[4/4] from: apwing:zonnet:nl at: 15-Dec-2003 15:13
Hi guys,
thanks a lot for all the comments and the debate that followed. I think that things have
been put into a better perspective now :-)
Met vriendelijke groet / with kind regards,
Arie van Wingerden
http://home.zonnet.nl/rebolution
----- Original Message -----
From: Joel Neely
To: [rebol-list--rebol--com]
Sent: Sunday, December 14, 2003 10:24 PM
Subject: [REBOL] Re: Guru's please help improve ROT13 algorithm !
I submitted a cleaner one (than what's on the ROT13 page) along with
some remarks, and copied the list here, and then saw Sunanda's reply:
[SunandaDH--aol--com] wrote:
WRT that version, I'll add my $0.02...
rot-13: func [
{Converts a string to or from Rot-13}
data [any-string!]
/local scrambled rot-chars rot-char
][
rot-chars:
{anabobcpcdqderefsfgtghuhivijwjkxklylmzmANABOBCPCDQDEREFSFGTGHUHIVIJWJKXKLYLMZM}
scrambled: copy ""
foreach char data [
if none? (rot-char: select/case rot-chars char) [rot-char: char]
insert tail scrambled :rot-char
]
return scrambled
]
My suggestions follow:
1) I prefer to avoid typo-prone strings when I can.
2) Both the above and my submission to the ROT13 site would benefit
from comments explaining the construction of the translation
string as related to SELECT/CASE. It is a nice REBOL-ism that
we only need 39 characters per case as opposed to 52!
3) I'd rather initialize the result as an empty string with the full
(known) length preallocated to avoid excessive memory management
overhead for longer arguments.
4) The use of the get-word (:ROT-CHAR) is surprising (but marginally
defensible by speed?)
5) The if-none-then-use-default pattern is a great opportunity to use
another REBOL-ism, ANY.
I did a little benchmarking with four versions:
" code" - is the version from my earlier post,
"if/get" - replaces the FOREACH body with
if none? cc: select/case xlate ch [cc: ch]
insert tail result :cc
similar to the version in the script library
" if" - simply replaces the get-word (:CC) with the word itself
if none? cc: select/case xlate ch [cc: ch]
insert tail result cc
"either" - evaluates the replacement character as an expression
as the last argument of the INSERT
insert tail result
either none? cc: select/case xlate ch [ch] [cc]
The results of a quick timing test (50,000 evaluations of each
function on a 243-character string) are
>> rot13/time-it 50000 datum
code: 108.356
if/get: 132.24
if: 133.502
either: 137.117
The use of the get-word saves about 1% to the run-time of the function
(if/get vs is). The time for EITHER vs IF was a bit of a surprise to
me, because it added another 3-4% to the run time.
Comparing the object/method version vs a stand-alone function, we can
pull a REBOL-persistence-of-series trick:
rot13: func [s [string!] /local result xlate] [
if empty? xlate: "" [
for ch #"a" #"m" 1 [append xlate reduce [ch ch + 13 ch]]
for ch #"A" #"M" 1 [append xlate reduce [ch ch + 13 ch]]
]
result: make string! length? s
foreach ch s [
insert tail result any [select/case xlate ch ch]
]
result
]
(not that I'd ever write somehing like that, for several reasons ;-)
or embed the translation strings in place of the local XLATE, and get
the following timings:
>> fn-vs-obj 50000 datum
method: 108.255
stateful: 107.405
stateless: 107.514
where "stateful" is the above ROT13 function, and "stateless" uses the
literal instead of persistence.
Any critiques or suggestions for improvement to my object-based version
are welcome!
-jn-