1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
// Package caesar implements the Caesar cipher.
//
// The Caesar cipher is a basic monoalphabetic substitution cipher where each
// letter in the plaintext is shifted by a fixed distance to form the
// ciphertext. A ciphertext can be decrypted by reversing the shift.
package caesar
import (
"strings"
)
// A RuneRange represents a range of runes that are to be shifted.
//
// Since runes encompass the entire UTF-8 space, we don't necessarily want to
// apply the Caesar shift to all runes in a plaintext lest we end up with
// unprintable or otherwise difficult characters.
type RuneRange struct {
// Start represents the beginning of the range (inclusive).
Start rune
// End represents the end of the range (inclusive).
End rune
}
// contains checks whether r is in the rune range.
func (rr RuneRange) contains(r rune) bool {
return r >= rr.Start && r <= rr.End
}
// size calculates the size of the range.
func (rr RuneRange) size() int {
return int(rr.End-rr.Start) + 1
}
// shift shifts r by d within the range, modulo the size of the range.
func (rr RuneRange) shift(r rune, d int) rune {
pos := int(r - rr.Start)
for d < 0 {
d = rr.size() + d
}
newPos := (pos + d) % rr.size()
return rr.Start + rune(newPos)
}
// A Coder encodes and decodes Caesar cipher messages according to its key and
// valid rune ranges.
//
// Its zero value doesn't do any shifting, so both Encode and Decode are simply
// the identity function.
type Coder struct {
// Key determines the shift (+Key for encoding, -Key for decoding).
Key int
// Ranges determine which rune ranges should be shifted.
Ranges []RuneRange
}
// Encode takes the message and returns a Caesar shifted version.
func (c Coder) Encode(msg string) string {
return strings.Map(c.shifter(c.Key), msg)
}
// Decode takes a shifted message and returns a plaintext version.
func (c Coder) Decode(msg string) string {
return strings.Map(c.shifter(-c.Key), msg)
}
type shiftFunc func(rune) rune
// shifter returns a shiftFunc for the coder's rune ranges.
func (c Coder) shifter(delta int) shiftFunc {
return func(r rune) rune {
for _, rr := range c.Ranges {
if rr.contains(r) {
return rr.shift(r, delta)
}
}
return r
}
}
// DefaultCoder is a Coder which uses the historical key of 3 and encodes
// uppercase and lowercase characters a-z and the digits 0-9.
//
// DefaultCoder is used by Encode and Decode.
//
// Define your own Coder to use custom rune ranges or keys.
var DefaultCoder = Coder{
Key: 3,
Ranges: []RuneRange{
{Start: 'a', End: 'z'},
{Start: 'A', End: 'Z'},
{Start: '0', End: '9'},
},
}
// Encode encodes msg using DefaultCoder.
func Encode(msg string) string {
return DefaultCoder.Encode(msg)
}
// Decode decodes msg using DefaultCoder.
func Decode(msg string) string {
return DefaultCoder.Decode(msg)
}
|