Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

rot13.gno

1.66 Kb · 50 lines
 1// Package rot13 ports Go's classic ROT13 example — the one used to teach
 2// strings.Map and io.Reader in the standard library docs — to gno as a reusable
 3// pure package. The core is a pure letter-rotation cipher over ASCII: ROT13
 4// shifts each letter 13 places, which (since the alphabet has 26 letters)
 5// makes ROT13 its own inverse. Caesar generalizes it to any shift.
 6//
 7// Everything here is pure strings/unicode logic: no state, no randomness,
 8// no clock.
 9//
10// A live demo of this package is at
11// [r/moul/x/daily/rot13demo](/r/moul/x/daily/rot13demo/v0).
12package rot13
13
14import "strings"
15
16// Rot13 applies the ROT13 substitution cipher, rotating ASCII letters by 13
17// and leaving every other byte untouched. Because 13 is half of 26,
18// Rot13(Rot13(s)) == s — the cipher is its own inverse. This mirrors the
19// canonical strings.Map example from the Go docs.
20func Rot13(s string) string {
21	return strings.Map(rot13Rune, s)
22}
23
24// rot13Rune is the mapping function handed to strings.Map — the heart of the
25// classic example.
26func rot13Rune(r rune) rune {
27	switch {
28	case r >= 'a' && r <= 'z':
29		return 'a' + (r-'a'+13)%26
30	case r >= 'A' && r <= 'Z':
31		return 'A' + (r-'A'+13)%26
32	}
33	return r
34}
35
36// Caesar generalizes ROT13 to an arbitrary shift. Negative and large shifts
37// are normalized into [0,26). Only ASCII letters move; anything else passes
38// through unchanged. Caesar(s, 13) is exactly Rot13(s).
39func Caesar(s string, shift int) string {
40	sh := rune(((shift % 26) + 26) % 26)
41	return strings.Map(func(r rune) rune {
42		switch {
43		case r >= 'a' && r <= 'z':
44			return 'a' + (r-'a'+sh)%26
45		case r >= 'A' && r <= 'Z':
46			return 'A' + (r-'A'+sh)%26
47		}
48		return r
49	}, s)
50}