Как проверить, содержит ли строка подстроку в Go?
Использование strings.Contains — самый простой и правильный способ
В Go для проверки, содержит ли строка подстроку, используется функция strings.Contains из стандартного пакета strings. Она возвращает true, если подстрока найдена, и false в противном случае. Это самый простой, читаемый и рекомендуемый подход.
Вот как исправить ваш пример:
package main
import (
"fmt"
"strings"
)
func main() {
str := "Hello, World!"
substr := "World"
if strings.Contains(str, substr) {
fmt.Println("Подстрока найдена!")
} else {
fmt.Println("Подстрока не найдена")
}
}
// Вывод: Подстрока найдена!
Разница между Contains, Index и Count
Все эти функции находятся в пакете strings, но имеют разные цели:
- strings.Contains(str, substr) — возвращает
bool. Оптимален для простой проверки наличия подстроки. - strings.Index(str, substr) — возвращает
int(индекс первого вхождения) или-1, если подстрока не найдена. Используйте, если нужно узнать позицию подстроки. - strings.Count(str, substr) — возвращает
int(количество непересекающихся вхождений). Используйте, если нужно подсчитать, сколько раз встречается подстрока.
Пример с Index:
str := "Hello, World! World!"
substr := "World"
index := strings.Index(str, substr)
if index != -1 {
fmt.Printf("Подстрока найдена на позиции %d\n", index)
} else {
fmt.Println("Подстрока не найдена")
}
// Вывод: Подстрока найдена на позиции 7
Пример с Count:
str := "Hello, World! World!"
substr := "World"
count := strings.Count(str, substr)
fmt.Printf("Подстрока встречается %d раз(а)\n", count)
// Вывод: Подстрока встречается 2 раз(а)
Учёт регистра
Все функции из пакета strings по умолчанию чувствительны к регистру. Если нужно выполнить поиск без учёта регистра, преобразуйте обе строки к нижнему или верхнему регистру с помощью strings.ToLower или strings.ToUpper:
str := "Hello, World!"
substr := "world" // обратите внимание: маленькая буква w
// Чувствительный к регистру — вернёт false
fmt.Println(strings.Contains(str, substr)) // false
// Без учёта регистра
lowerStr := strings.ToLower(str)
lowerSubstr := strings.ToLower(substr)
fmt.Println(strings.Contains(lowerStr, lowerSubstr)) // true
Для частого использования можно написать небольшую вспомогательную функцию:
func containsCaseInsensitive(s, substr string) bool {
return strings.Contains(
strings.ToLower(s),
strings.ToLower(substr),
)
}
Производительность
Все три функции (Contains, Index, Count) внутри реализованы с использованием алгоритма Рабина-Карпа или аналогичных эффективных алгоритмов поиска подстрок. Для большинства практических задач разница в производительности незначительна. Однако:
strings.Contains— самая быстрая, если нужно только узнать, есть ли подстрока (она останавливается при первом же совпадении).strings.Index— немного медленнее, так как вычисляет точную позицию.strings.Count— самая медленная, так как сканирует всю строку полностью.
Поэтому для проверки наличия подстроки всегда используйте strings.Contains.
Проверка нескольких подстрок
Если нужно проверить, содержит ли строка хотя бы одну из нескольких подстрок, можно использовать цикл или функцию strings.ContainsAny (но она проверяет отдельные символы, а не подстроки). Для подстрок лучше написать так:
str := "Hello, Go!"
substrings := []string{"Hello", "Python", "Java"}
found := false
for _, sub := range substrings {
if strings.Contains(str, sub) {
found = true
break
}
}
if found {
fmt.Println("Строка содержит хотя бы одну из подстрок")
}
Или используйте strings.ContainsAny для поиска любого из набора символов (не подстрок):
str := "Hello, Go!"
// Проверяет, содержит ли str хотя бы один из символов 'a', 'b', 'c'
fmt.Println(strings.ContainsAny(str, "abc")) // true (буква 'o' не входит, но 'l' входит? нет, 'l' не входит в "abc")
// Правильный пример: ищем символы 'H', 'e', 'l'
fmt.Println(strings.ContainsAny(str, "Hel")) // true
Заключение
Для 99% случаев используйте strings.Contains. Это идиоматичный, эффективный и читаемый способ проверки наличия подстроки в Go. Помните про регистр и выбирайте подходящую функцию под конкретную задачу.
Регулярные выражения для сложного поиска
Если вам нужно выполнить более сложный поиск (например, с шаблонами, группами символов или повторениями), можно использовать пакет regexp. Однако для простой проверки на наличие подстроки это избыточно и медленнее, чем strings.Contains.
Пример с регулярным выражением:
package main
import (
"fmt"
"regexp"
)
func main() {
str := "Hello, World! My email is test@example.com"
// Проверяем, содержит ли строка email-адрес (упрощённый паттерн)
matched, _ := regexp.MatchString(`\w+@\w+\.\w+`, str)
fmt.Println("Содержит email:", matched) // true
// Поиск подстроки с префиксом "W" и любыми символами после
matched2, _ := regexp.MatchString(`W.*d`, str)
fmt.Println("Содержит 'W...d':", matched2) // true
}
Когда использовать regexp вместо strings.Contains
- Поиск по шаблону (например, все слова, начинающиеся с заглавной буквы).
- Поиск с игнорированием регистра без преобразования строк (флаг
(?i)). - Проверка формата строки (телефон, email, дата).
Пример с игнорированием регистра через regexp:
matched, _ := regexp.MatchString(`(?i)world`, "Hello, WORLD!")
fmt.Println(matched) // true
Важно: Если вам нужна только проверка наличия фиксированной подстроки, всегда используйте strings.Contains. Регулярные выражения стоит применять только для нетривиальных паттернов, так как они работают медленнее и сложнее в отладке.