June 2018 Update
This commit is contained in:
parent
ba8067c3b7
commit
22f33d4004
5278 changed files with 84726 additions and 14379 deletions
|
|
@ -1,72 +1,95 @@
|
|||
package main
|
||||
import "fmt"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Compress a string to a list of output symbols.
|
||||
func compress(uncompressed string) []int {
|
||||
// Build the dictionary.
|
||||
dictSize := 256
|
||||
dictionary := make(map[string]int)
|
||||
for i := 0; i < 256; i++ {
|
||||
dictionary[string(i)] = i
|
||||
}
|
||||
// Build the dictionary.
|
||||
dictSize := 256
|
||||
// We actually want a map of []byte -> int but
|
||||
// slices are not acceptable map key types.
|
||||
dictionary := make(map[string]int, dictSize)
|
||||
for i := 0; i < dictSize; i++ {
|
||||
// Ugly mess to work around not having a []byte key type.
|
||||
// Using `string(i)` would do utf8 encoding for i>127.
|
||||
dictionary[string([]byte{byte(i)})] = i
|
||||
}
|
||||
|
||||
w := ""
|
||||
result := make([]int, 0)
|
||||
for _, c := range []byte(uncompressed) {
|
||||
wc := w + string(c)
|
||||
if _, ok := dictionary[wc]; ok {
|
||||
w = wc
|
||||
} else {
|
||||
result = append(result, dictionary[w])
|
||||
// Add wc to the dictionary.
|
||||
dictionary[wc] = dictSize
|
||||
dictSize++
|
||||
w = string(c)
|
||||
}
|
||||
}
|
||||
var result []int
|
||||
var w []byte
|
||||
for i := 0; i < len(uncompressed); i++ {
|
||||
c := uncompressed[i]
|
||||
wc := append(w, c)
|
||||
if _, ok := dictionary[string(wc)]; ok {
|
||||
w = wc
|
||||
} else {
|
||||
result = append(result, dictionary[string(w)])
|
||||
// Add wc to the dictionary.
|
||||
dictionary[string(wc)] = dictSize
|
||||
dictSize++
|
||||
//w = []byte{c}, but re-using wc
|
||||
wc[0] = c
|
||||
w = wc[:1]
|
||||
}
|
||||
}
|
||||
|
||||
// Output the code for w.
|
||||
if w != "" {
|
||||
result = append(result, dictionary[w])
|
||||
}
|
||||
return result
|
||||
if len(w) > 0 {
|
||||
// Output the code for w.
|
||||
result = append(result, dictionary[string(w)])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Decompress a list of output ks to a string.
|
||||
func decompress(compressed []int) string {
|
||||
// Build the dictionary.
|
||||
dictSize := 256
|
||||
dictionary := make(map[int]string)
|
||||
for i := 0; i < 256; i++ {
|
||||
dictionary[i] = string(i)
|
||||
}
|
||||
type BadSymbolError int
|
||||
|
||||
w := string(compressed[0])
|
||||
result := w
|
||||
for _, k := range compressed[1:] {
|
||||
var entry string
|
||||
if x, ok := dictionary[k]; ok {
|
||||
entry = x
|
||||
} else if k == dictSize {
|
||||
entry = w + w[:1]
|
||||
} else {
|
||||
panic(fmt.Sprintf("Bad compressed k: %d", k))
|
||||
}
|
||||
func (e BadSymbolError) Error() string {
|
||||
return fmt.Sprint("Bad compressed symbol ", int(e))
|
||||
}
|
||||
|
||||
result += entry
|
||||
// Decompress a list of output symbols to a string.
|
||||
func decompress(compressed []int) (string, error) {
|
||||
// Build the dictionary.
|
||||
dictSize := 256
|
||||
dictionary := make(map[int][]byte, dictSize)
|
||||
for i := 0; i < dictSize; i++ {
|
||||
dictionary[i] = []byte{byte(i)}
|
||||
}
|
||||
|
||||
// Add w+entry[0] to the dictionary.
|
||||
dictionary[dictSize] = w + entry[:1]
|
||||
dictSize++
|
||||
var result strings.Builder
|
||||
var w []byte
|
||||
for _, k := range compressed {
|
||||
var entry []byte
|
||||
if x, ok := dictionary[k]; ok {
|
||||
//entry = x, but ensuring any append will make a copy
|
||||
entry = x[:len(x):len(x)]
|
||||
} else if k == dictSize && len(w) > 0 {
|
||||
entry = append(w, w[0])
|
||||
} else {
|
||||
return result.String(), BadSymbolError(k)
|
||||
}
|
||||
result.Write(entry)
|
||||
|
||||
w = entry
|
||||
}
|
||||
return result
|
||||
if len(w) > 0 {
|
||||
// Add w+entry[0] to the dictionary.
|
||||
w = append(w, entry[0])
|
||||
dictionary[dictSize] = w
|
||||
dictSize++
|
||||
}
|
||||
w = entry
|
||||
}
|
||||
return result.String(), nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
compressed := compress("TOBEORNOTTOBEORTOBEORNOT")
|
||||
fmt.Println(compressed)
|
||||
decompressed := decompress(compressed)
|
||||
fmt.Println(decompressed)
|
||||
compressed := compress("TOBEORNOTTOBEORTOBEORNOT")
|
||||
fmt.Println(compressed)
|
||||
decompressed, err := decompress(compressed)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println(decompressed)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue