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
|
|
|
)
|
|
|
|
|
2023-11-05 05:52:58 +03:00
|
|
|
// ErrInvalidString - Определение пользовательской ошибки для недопустимой строки.
|
2023-10-30 15:21:12 +03:00
|
|
|
var ErrInvalidString = errors.New("invalid string")
|
|
|
|
|
2023-11-05 05:52:58 +03:00
|
|
|
// state - Тип-перечисление для представления состояния автомата.
|
2023-11-05 05:10:52 +03:00
|
|
|
type state int
|
|
|
|
|
|
|
|
const (
|
|
|
|
start state = iota
|
|
|
|
escape
|
|
|
|
number
|
|
|
|
)
|
|
|
|
|
2023-11-05 05:52:58 +03:00
|
|
|
// 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)
|
|
|
|
|
2023-11-05 15:14:44 +03:00
|
|
|
//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:52:58 +03:00
|
|
|
// Если первый символ является цифрой, возвращаем ошибку "недопустимой строки".
|
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 {
|
2023-11-05 05:52:58 +03:00
|
|
|
// Если функция 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)
|
2023-11-05 05:52:58 +03:00
|
|
|
currentState = start
|
2023-11-05 05:10:52 +03:00
|
|
|
}
|
|
|
|
case number:
|
|
|
|
if unicode.IsDigit(char) {
|
2023-11-05 15:14:44 +03:00
|
|
|
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 15:14:44 +03:00
|
|
|
|
2023-11-05 05:10:52 +03:00
|
|
|
case escape:
|
2023-11-05 06:02:28 +03:00
|
|
|
// Если предыдущий символ - обратный слэш, добавляем текущий в результат.
|
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
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-11-05 05:52:58 +03:00
|
|
|
// repeatRune - Функция для повторения символа заданное количество раз.
|
2023-11-05 05:10:52 +03:00
|
|
|
func repeatRune(char rune, numOfRepeat int) (string, error) {
|
|
|
|
if numOfRepeat > 0 {
|
2023-11-05 05:52:58 +03:00
|
|
|
// Повторяем символ заданное количество раз и возвращаем строку.
|
2023-11-05 05:10:52 +03:00
|
|
|
return strings.Repeat(string(char), numOfRepeat-1), nil
|
|
|
|
}
|
|
|
|
if numOfRepeat == 0 {
|
2023-11-05 05:52:58 +03:00
|
|
|
// Если количество повторений равно нулю, возвращаем ошибку "нулевое повторение".
|
2023-11-05 05:10:52 +03:00
|
|
|
return "", errors.New("zero repeat")
|
|
|
|
}
|
2023-11-05 05:52:58 +03:00
|
|
|
// Возвращаем пустую строку для отрицательных значений numOfRepeat.
|
|
|
|
return "", errors.New("negative repeat")
|
2023-10-30 15:21:12 +03:00
|
|
|
}
|