unpack_string/unpack.go

104 lines
3.2 KiB
Go
Raw Permalink Normal View History

2023-10-30 15:32:15 +03:00
package unpackstring
2023-10-30 15:21:12 +03:00
import (
"errors"
2023-11-05 05:10:52 +03:00
"strconv"
"strings"
"unicode"
2023-10-30 15:21:12 +03:00
)
// ErrInvalidString - Определение пользовательской ошибки для недопустимой строки.
2023-10-30 15:21:12 +03:00
var ErrInvalidString = errors.New("invalid string")
// state - Тип-перечисление для представления состояния автомата.
2023-11-05 05:10:52 +03:00
type state int
const (
start state = iota
escape
number
)
// Unpack - Функция для распаковки строки в заданном формате.
2023-11-01 03:41:17 +03:00
func Unpack(str string) (string, error) {
2023-11-05 05:10:52 +03:00
var currentState state = start
var result strings.Builder
numOfRepeat := 1
var runeArray = []rune(str)
//re, _ := regexp.Compile(`^\d|\d{2,}`)
//
//if re.MatchString(str) == true {
// return "", ErrInvalidString
//}
2023-11-05 05:10:52 +03:00
if len(runeArray) > 0 && unicode.IsDigit(runeArray[0]) {
// Если первый символ является цифрой, возвращаем ошибку "недопустимой строки".
2023-11-05 05:10:52 +03:00
return "first rune is digit", ErrInvalidString
2023-11-01 23:05:25 +03:00
}
2023-11-01 03:41:17 +03:00
2023-11-05 05:10:52 +03:00
for i, char := range runeArray {
2023-11-01 03:41:17 +03:00
2023-11-05 05:10:52 +03:00
switch currentState {
case start:
if unicode.IsDigit(char) {
currentState = number
numOfRepeat, _ = strconv.Atoi(string(char))
2023-11-05 05:22:54 +03:00
repStr, err := repeatRune(runeArray[i-1], numOfRepeat)
if err != nil {
// Если функция repeatRune возвращает ошибку, удаляем последний символ из результата.
2023-11-05 05:22:54 +03:00
res := result.String()
result.Reset()
result.WriteString(res[0 : len(res)-1])
}
result.WriteString(repStr)
2023-11-05 05:10:52 +03:00
} else if char == '\\' {
currentState = escape
} else {
result.WriteRune(char)
currentState = start
2023-11-05 05:10:52 +03:00
}
case number:
if unicode.IsDigit(char) {
var n = strconv.Itoa(numOfRepeat)
numOfRepeat, _ = strconv.Atoi(n + string(char))
repStr, err := repeatRune(runeArray[i-2], numOfRepeat)
if err != nil {
// Если функция repeatRune возвращает ошибку, удаляем последний символ из результата.
res := result.String()
result.Reset()
result.WriteString(res[0 : len(res)-1])
}
result.WriteString(repStr)
} else {
result.WriteRune(char)
currentState = start
2023-11-05 05:10:52 +03:00
}
2023-11-05 05:10:52 +03:00
case escape:
// Если предыдущий символ - обратный слэш, добавляем текущий в результат.
2023-11-05 05:10:52 +03:00
result.WriteRune(char)
2023-11-05 05:26:52 +03:00
currentState = start
2023-11-05 05:10:52 +03:00
}
2023-11-01 23:05:25 +03:00
2023-11-01 03:41:17 +03:00
}
2023-11-05 05:10:52 +03:00
return result.String(), nil
}
// repeatRune - Функция для повторения символа заданное количество раз.
2023-11-05 05:10:52 +03:00
func repeatRune(char rune, numOfRepeat int) (string, error) {
if numOfRepeat > 0 {
// Повторяем символ заданное количество раз и возвращаем строку.
2023-11-05 05:10:52 +03:00
return strings.Repeat(string(char), numOfRepeat-1), nil
}
if numOfRepeat == 0 {
// Если количество повторений равно нулю, возвращаем ошибку "нулевое повторение".
2023-11-05 05:10:52 +03:00
return "", errors.New("zero repeat")
}
// Возвращаем пустую строку для отрицательных значений numOfRepeat.
return "", errors.New("negative repeat")
2023-10-30 15:21:12 +03:00
}