exercism/go/simple-cipher/cipher.go

144 lines
3.0 KiB
Go

package cipher
import (
"regexp"
"strings"
)
// Cipher is an interface for all ciphers
type Cipher interface {
Encode(string) string
Decode(string) string
}
// ShiftCipher is a cipher that shifts all letters a fixed distance
type ShiftCipher struct {
width int
}
// NewShift returns a new ShiftCipher
func NewShift(w int) *ShiftCipher {
if w == 0 || w < -25 || w > 25 {
return nil
}
c := new(ShiftCipher)
c.width = w
return c
}
// Encode encodes a string using the current ShiftCipher
func (c *ShiftCipher) Encode(s string) string {
var ret string
s = strings.ToLower(s)
re := regexp.MustCompile("[^a-z]")
s = re.ReplaceAllString(s, "")
for i := range s {
newChar := s[i] + byte(c.width)
if newChar < 'a' {
newChar = 'z' - ('a' - newChar) + 1
}
if newChar > 'z' {
newChar = 'a' + (newChar - 'z') - 1
}
ret = ret + string(newChar)
}
return ret
}
// Decode decodes a string using the current ShiftCipher
func (c *ShiftCipher) Decode(s string) string {
var ret string
s = strings.ToLower(s)
re := regexp.MustCompile("[^a-z]")
s = re.ReplaceAllString(s, "")
for i := range s {
newChar := s[i] - byte(c.width)
if newChar < 'a' {
newChar = 'z' - ('a' - newChar) + 1
}
if newChar > 'z' {
newChar = 'a' + (newChar - 'z') - 1
}
ret = ret + string(newChar)
}
return ret
}
// A CeasarCipher is a ShiftCipher, just hardcoded at 3
type CeasarCipher struct {
c *ShiftCipher
}
// NewCaesar creates a new CaesarCipher
func NewCaesar() *CeasarCipher {
c := new(CeasarCipher)
c.c = NewShift(3)
return c
}
// Encode just calls the shift cipher in the caesar cipher
func (c *CeasarCipher) Encode(s string) string {
return c.c.Encode(s)
}
// Decode just calls the shift cipher in the caesar cipher
func (c *CeasarCipher) Decode(s string) string {
return c.c.Decode(s)
}
// VigenereCipher a cipher where each character can have a different shift width
type VigenereCipher struct {
key string
}
// Encode encodes the given string
func (c *VigenereCipher) Encode(s string) string {
var ret string
s = strings.ToLower(s)
re := regexp.MustCompile("[^a-z]")
s = re.ReplaceAllString(s, "")
for i := range s {
keyChar := c.key[i%len(c.key)] - 'a'
newChar := s[i] + keyChar
if newChar < 'a' {
newChar = 'z' - ('a' - newChar) + 1
}
if newChar > 'z' {
newChar = 'a' + (newChar - 'z') - 1
}
ret = ret + string(newChar)
}
return ret
}
// Decode decodes the given string
func (c *VigenereCipher) Decode(s string) string {
var ret string
s = strings.ToLower(s)
re := regexp.MustCompile("[^a-z]")
s = re.ReplaceAllString(s, "")
for i := range s {
keyChar := c.key[i%len(c.key)] - 'a'
newChar := s[i] - keyChar
if newChar < 'a' {
newChar = 'z' - ('a' - newChar) + 1
}
if newChar > 'z' {
newChar = 'a' + (newChar - 'z') - 1
}
ret = ret + string(newChar)
}
return ret
}
// NewVigenere returns a new Vigenere Cipher
func NewVigenere(key string) *VigenereCipher {
re := regexp.MustCompile("[^a-z]")
if len(key) < 3 || re.MatchString(key) {
return nil
}
c := new(VigenereCipher)
c.key = key
return c
}