Проблема, знакомая каждому разработчику
Представьте: вы пишете парсер логов, обрабатываете пользовательский ввод из формы или готовите данные для API. Строки приходят с лишними пробелами в начале и конце. Если их не убрать — баги, сломанные сравнения, кривые JSON и потерянные часы дебага. Это классическая задача, которая на Stack Overflow собрала тысячи просмотров. Сегодня мы разберем ее на Go — быстро, элегантно и без сюрпризов.
В этом руководстве вы узнаете:
- Как использовать стандартную библиотеку
stringsдля обрезки пробелов. - Чем отличается
TrimSpaceотTrimLeftиTrimRight. - Как написать свою кастомную функцию для нестандартных whitespace-символов.
- Как не наступить на грабли с Unicode и табуляцией.
Поехали!
Быстрый старт: strings.TrimSpace
Самый простой и популярный способ убрать пробелы с обоих концов строки — использовать функцию strings.TrimSpace из стандартного пакета strings. Она удаляет все символы, которые Go считает "пробельными" (whitespace): обычные пробелы, табуляции, переводы строк, возвраты каретки и даже вертикальные табуляции.
Вот как это выглядит в коде:
package main
import (
"fmt"
"strings"
)
func main() {
raw := " Привет, мир! \n\t"
cleaned := strings.TrimSpace(raw)
fmt.Printf("Исходная: %q\n", raw)
fmt.Printf("Очищенная: %q\n", cleaned)
}
Вывод:
Исходная: " Привет, мир! \n\t"
Очищенная: "Привет, мир!"
Обратите внимание: %q в fmt.Printf показывает строку с escape-последовательностями — это удобно для отладки, чтобы видеть скрытые символы.
Когда использовать: в 90% случаев этого достаточно. Если вам нужно просто "почистить" строку от мусора по краям — берите TrimSpace.
Тонкая настройка: TrimLeft и TrimRight
Иногда нужно обрезать пробелы только слева или только справа. Для этого в Go есть strings.TrimLeft и strings.TrimRight. Но есть нюанс: они работают не с "пробельными символами" по умолчанию, а с переданным набором символов.
Пример:
package main
import (
"fmt"
"strings"
)
func main() {
s := " \t\n Hello "
// Обрезаем только слева (пробелы, табуляции, переводы строк)
left := strings.TrimLeft(s, " \t\n")
fmt.Printf("Слева: %q\n", left)
// Обрезаем только справа (только пробелы)
right := strings.TrimRight(s, " ")
fmt.Printf("Справа: %q\n", right)
}
Вывод:
Слева: "Hello "
Справа: " \t\n Hello"
Важно: TrimLeft и TrimRight удаляют все символы из второго аргумента, пока не встретят символ, которого там нет. Если вы укажете только пробел " ", то табуляция \t останется нетронутой.
Аналог TrimSpace для одной стороны
Если вам нужно обрезать все whitespace только слева или только справа, но лень перечислять все символы, можно написать небольшую обертку:
func trimLeftSpace(s string) string {
return strings.TrimLeft(s, " \t\n\r\v\f")
}
func trimRightSpace(s string) string {
return strings.TrimRight(s, " \t\n\r\v\f")
}
Или, для тех, кто любит краткость, использовать strings.TrimSpace с хитростью:
// Обрезаем только слева: сначала реверсим, потом TrimSpace, потом реверсим обратно
func trimLeftSpace(s string) string {
runes := []rune(s)
for i, r := range runes {
if !unicode.IsSpace(r) {
return string(runes[i:])
}
}
return ""
}
Но второй вариант — для понимания алгоритма, на практике проще использовать strings.TrimLeft с полным набором символов.
Продвинутый уровень: TrimFunc и кастомные критерии
Go предоставляет функцию strings.TrimFunc, которая позволяет задать любое правило для удаления символов. Вы передаете функцию, которая возвращает true, если символ нужно удалить.
Пример: удаляем все пробелы и знаки пунктуации с краев строки.
package main
import (
"fmt"
"strings"
"unicode"
)
func main() {
s := "!!! Hello, World! ???"
// Кастомная функция: удаляем пробелы и знаки препинания
cleaned := strings.TrimFunc(s, func(r rune) bool {
return unicode.IsSpace(r) || unicode.IsPunct(r)
})
fmt.Printf("Результат: %q\n", cleaned)
}
Вывод:
Результат: "Hello, World"
Когда это нужно: если вы работаете с нестандартными разделителями, например, с символами из других алфавитов или специфическими управляющими кодами.
Подводные камни: Unicode, rune и производительность
Go из коробки хорошо работает с UTF-8. Функции из пакета strings оперируют рунами (rune), поэтому кириллица, иероглифы и эмодзи обрабатываются корректно.
Но есть один момент: strings.TrimSpace использует определение whitespace из Unicode. Это значит, что он удаляет не только стандартный пробел U+0020, но и, например, неразрывный пробел U+00A0 (который часто встречается в HTML).
Проверим:
package main
import (
"fmt"
"strings"
)
func main() {
// Неразрывный пробел (U+00A0) в начале и конце
s := "\u00A0Привет\u00A0"
cleaned := strings.TrimSpace(s)
fmt.Printf("Исходная: %U %U\n", []rune(s)[0], []rune(s)[len([]rune(s))-1])
fmt.Printf("Очищенная: %q\n", cleaned)
}
Вывод:
Исходная: U+00A0 U+00A0
Очищенная: "Привет"
Работает! Но если вам нужно удалить только обычные пробелы и оставить неразрывные — используйте TrimLeft/TrimRight с явным списком " ".