-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrle.go
62 lines (55 loc) · 1.36 KB
/
rle.go
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
package rle
import (
"fmt"
"io"
"strings"
)
// RunLengthEncoding takes a string and returns a string representing the run
// length encoding of that string. Run length encoding is a text compression
// algorithm which replaces runs of n identical characters c with "cn".
//
// As an alternative to using a rune slice, the Go spec recommends using a
// []byte to store the result and appending to it with [utf8.AppendRune].
func RunLengthEncoding(s string) string {
if s == "" {
return s
}
stringReader := strings.NewReader(s)
var result []rune
var last rune
var buffer rune
var err error
count := 0
for {
buffer, _, err = stringReader.ReadRune()
if err == io.EOF {
// The following alternatives do not work because of the historical
// behavior of "string()"
//
// result = append(result, rune(string(count)))
// result = append(result, []rune(string(count))...)
countString := fmt.Sprintf("%d", count)
result = append(result, []rune(countString)...)
break
}
if err != nil {
panic(err)
}
if len(result) == 0 {
result = append(result, buffer)
count = 1
last = buffer
continue
}
if buffer != last {
countString := fmt.Sprintf("%d", count)
result = append(result, []rune(countString)...)
result = append(result, buffer)
last = buffer
count = 1
} else {
count += 1
}
}
return string(result)
}