77 lines
1.4 KiB
Go
77 lines
1.4 KiB
Go
package unpackstring
|
|
|
|
import (
|
|
"errors"
|
|
"strconv"
|
|
"strings"
|
|
"unicode"
|
|
)
|
|
|
|
var ErrInvalidString = errors.New("invalid string")
|
|
|
|
type state int
|
|
|
|
const (
|
|
start state = iota
|
|
escape
|
|
number
|
|
)
|
|
|
|
func Unpack(str string) (string, error) {
|
|
var currentState state = start
|
|
var result strings.Builder
|
|
numOfRepeat := 1
|
|
|
|
var runeArray = []rune(str)
|
|
|
|
if len(runeArray) > 0 && unicode.IsDigit(runeArray[0]) {
|
|
return "first rune is digit", ErrInvalidString
|
|
}
|
|
|
|
for i, char := range runeArray {
|
|
|
|
switch currentState {
|
|
case start:
|
|
if unicode.IsDigit(char) {
|
|
currentState = number
|
|
numOfRepeat, _ = strconv.Atoi(string(char))
|
|
repStr, err := repeatRune(runeArray[i-1], numOfRepeat)
|
|
if err != nil {
|
|
res := result.String()
|
|
result.Reset()
|
|
result.WriteString(res[0 : len(res)-1])
|
|
}
|
|
result.WriteString(repStr)
|
|
} else if char == '\\' {
|
|
currentState = escape
|
|
} else {
|
|
currentState = start
|
|
result.WriteRune(char)
|
|
}
|
|
case number:
|
|
if unicode.IsDigit(char) {
|
|
return "", ErrInvalidString
|
|
}
|
|
currentState = start
|
|
result.WriteRune(char)
|
|
case escape:
|
|
result.WriteRune(char)
|
|
currentState = start
|
|
}
|
|
|
|
}
|
|
|
|
return result.String(), nil
|
|
|
|
}
|
|
|
|
func repeatRune(char rune, numOfRepeat int) (string, error) {
|
|
if numOfRepeat > 0 {
|
|
return strings.Repeat(string(char), numOfRepeat-1), nil
|
|
}
|
|
if numOfRepeat == 0 {
|
|
return "", errors.New("zero repeat")
|
|
}
|
|
return "", nil
|
|
}
|