Как разбить строку по пробелам в Go? (Split string on whitespace)
Лучшее решение: strings.Fields()
В Go есть встроенная функция strings.Fields(), которая идеально подходит для вашей задачи. Она разбивает строку по любому количеству пробельных символов (пробелы, табуляции, переносы строк, возврат каретки и т.д.) и автоматически удаляет пустые элементы.
package main
import (
"fmt"
"strings"
)
func main() {
s := "hello world\tfoo\nbar"
parts := strings.Fields(s)
fmt.Printf("%q\n", parts) // ["hello" "world" "foo" "bar"]
fmt.Println(len(parts)) // 4
}
Как это работает?
Функция strings.Fields() использует определение пробельных символов из Юникода (Unicode whitespace). Она:
- Пропускает начальные и конечные пробелы
- Разбивает строку по одному или нескольким пробельным символам
- Не включает пустые строки в результат
Когда это не подходит?
Если вам нужно разделить строку только по одному конкретному символу (например, только по пробелу, но не по табуляции), используйте strings.Split() с фильтрацией пустых строк:
package main
import (
"fmt"
"strings"
)
func main() {
s := "hello world\tfoo"
parts := strings.FieldsFunc(s, func(r rune) bool {
return r == ' ' // только пробел
})
fmt.Printf("%q\n", parts) // ["hello" "" "" "world\tfoo"]
}
Производительность
strings.Fields() работает очень быстро — это нативная функция, написанная на Go. Она в разы быстрее, чем regexp. Если вам нужно разбить миллионы строк, используйте именно её.
Дополнительные возможности
Если вам нужен более гибкий контроль над разделителями, используйте strings.FieldsFunc(). Она принимает функцию, которая определяет, является ли символ разделителем:
package main
import (
"fmt"
"strings"
"unicode"
)
func main() {
s := "hello,world;foo:bar"
parts := strings.FieldsFunc(s, func(r rune) bool {
return r == ',' || r == ';' || r == ':'
})
fmt.Printf("%q\n", parts) // ["hello" "world" "foo" "bar"]
}
Также можно использовать unicode.IsSpace() для точного совпадения с поведением strings.Fields():
parts := strings.FieldsFunc(s, unicode.IsSpace)
Это даст тот же результат, что и strings.Fields().
Альтернатива: bufio.Scanner для построчной обработки
Если вы работаете с большими текстами или потоками данных, рассмотрите bufio.Scanner с кастомной функцией разделения. Это позволяет обрабатывать строку по словам без загрузки всего текста в память:
package main
import (
"bufio"
"fmt"
"strings"
)
func main() {
s := "hello world\tfoo\nbar"
scanner := bufio.NewScanner(strings.NewReader(s))
scanner.Split(bufio.ScanWords) // предопределённый splitter для слов
var words []string
for scanner.Scan() {
words = append(words, scanner.Text())
}
fmt.Printf("%q\n", words) // ["hello" "world" "foo" "bar"]
}
Этот подход особенно полезен, когда:
- Строка очень длинная (сотни мегабайт)
- Вы читаете данные из файла или сети
- Нужно обрабатывать слова по мере поступления, а не все сразу
bufio.ScanWords использует то же определение пробельных символов, что и strings.Fields(), но работает лениво — не создаёт весь слайс заранее.
Важно: Для простых случаев strings.Fields() всё же предпочтительнее из-за простоты и скорости. Используйте bufio.Scanner только когда память или потоковая обработка критичны.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги