Go. Гайд по регулярным выражениям.
Учебник по регулярным выражениям в Go показывает, как разобрать текст в Go с помощью регулярных выражений.
$ go version
go version go1.18.1 linux/amd64
Мы используем Go версии 1.18.
В Go есть встроенный API для работы с регулярными выражениями; он находится в пакете regexp.
Регуля́рные выраже́ния — формальный язык, используемый в компьютерных программах, работающих с текстом, для поиска и осуществления манипуляций с подстроками в тексте, основанный на использовании метасимволов (символов-джокеров, англ. wildcard characters). Для поиска используется строка-образец (англ. pattern, по-русски её часто называют «шаблоном», «маской»), состоящая из символов и метасимволов и задающая правило поиска. Для манипуляций с текстом дополнительно задаётся строка замены, которая также может содержать в себе специальные символы.
Регулярное выражение задает шаблон поиска для строк. Синтаксис регулярных выражений, принятый в Go, совпадает с общим синтаксисом, используемым в Perl, Python и других языках.
Большая часть символов в регулярном выражении представляет само себя. кроме специальных символов [
]
\
/
^
$
.
|
?
*
+
(
)
{
}
(в разных типах регулярных выражений этот набор различается, см. Разновидности регулярных выражений), которые могут быть экранированы символом \
(обратная косая черта) для представления самих себя в качестве символов текста. Можно экранировать целую последовательность символов, заключив её между \Q
и \E
.
В моем телеграм вы найдете множество проектов с уроками, гайдами и кодом для Golang разработчиков
Еще я собрал полезную папку для Golang разработчиков, там находится все, что нужно Go программисту.
Пример | Соответствие |
---|---|
a\.? | a. или a |
a\\\\b | a\\b |
a\[F\] | a[F] |
\Q+-*/\E | +-*/ |
Примеры Regex
Символ | Возможный эквивалент | Соответствие |
---|---|---|
\d | [0-9] | Цифровой символ |
\D | [^0-9] | Нецифровой символ |
\s | [ \f\n\r\t\v] | Пробельный символ |
\S | [^ \f\n\r\t\v] | Непробельный символ Пример: Выражение вида ^\S.* или ^[^ \f\n\r\t\v].* будет находить строки, начинающиеся с непробельного символа |
\w | [A-Za-z0-9_] | Буквенный или цифровой символ или знак подчёркивания; буквы ограничены латиницей Пример: Выражение вида \w+ будет находить и выделять отдельные слова |
\W | [^A-Za-z0-9_] | Любой символ, кроме буквенного или цифрового символа или знака подчёркивания |
Представление | Позиция | Пример | Соответствие |
---|---|---|---|
^ | Начало текста (или строки при модификаторе ?m) | ^a | aaa aaa |
$ | Конец текста (или строки при модификаторе ?m) | a$ | aaa aaa |
\b | Граница слова | a\b | aaa aaa |
\ba | aaa aaa | ||
\B | Не граница слова | \Ba\B | aaa aaa |
\G | Предыдущий успешный поиск | \Ga | aaa aaa (поиск остановился на 4-й позиции — там, где не нашлось a ) |
Представление | Число повторений | Эквивалент | Пример | Соответствие |
---|---|---|---|---|
? | Ноль или одно | {0,1} | colou?r | color , colour |
* | Ноль или более | {0,} | colou*r | color , colour , colouur и т. д. |
+ | Одно или более | {1,} | colou+r | colour , colouur и т. д. (но не color ) |
Представление | Число повторений | Пример | Соответствие |
---|---|---|---|
{n} | Ровно n раз | colou{3}r | colouuur |
{m,n} | От m до n включительно | colou{2,4}r | colouur , colouuur , colouuuur |
{m,} | Не менее m | colou{2,}r | colouur , colouuur , colouuuur и т. д. |
{,n} | Не более n | colou{,3}r | color , colour , colouur , colouuur |
Go regex MatchString
Функция MatchString сообщает, содержит ли строка какое-либо совпадение с шаблоном регулярного выражения
package main
import (
"fmt"
"log"
"regexp"
)
func main() {
words := [...]string{"Seven", "even", "Maven", "Amen", "eleven"}
for _, word := range words {
found, err := regexp.MatchString(".even", word)
if err != nil {
log.Fatal(err)
}
if found {
fmt.Printf("%s matches\n", word)
} else {
fmt.Printf("%s does not match\n", word)
}
}
}
В примере кода у нас есть пять слов в массиве. Мы проверяем, какие слова соответствуют регулярному выражению .even.
words := [...]string{"Seven", "even", "Maven", "Amen", "eleven"}
У нас есть массив слов.
for _, word := range words {
Мы проходим через массив слов.
found, err := regexp.MatchString(".even", word)
Мы проверяем, соответствует ли текущее слово регулярному выражению с помощью MatchString. У нас есть регулярное выражение .even. Метасимвол точка (.) обозначает любой отдельный символ в тексте.
if found {
fmt.Printf("%s matches\n", word)
} else {
fmt.Printf("%s does not match\n", word)
}
Мы выводим, соответствует ли слово регулярному выражению или нет.
$ go run matchstring.go
Seven matches
even does not match
Maven does not match
Amen does not match
eleven matches
Два слова в массиве соответствуют нашему регулярному выражению.
Скомпилированное регулярное выражение
Функция Compile разбирает регулярное выражение и в случае успеха возвращает объект Regexp, который можно использовать для сопоставления с текстом. Скомпилированные регулярные выражения работают быстрее.
Функция MustCompile – это удобная функция, которая компилирует регулярное выражение и паникует, если выражение не может быть разобрано.
package main
import (
"fmt"
"log"
"regexp"
)
func main() {
words := [...]string{"Seven", "even", "Maven", "Amen", "eleven"}
re, err := regexp.Compile(".even")
if err != nil {
log.Fatal(err)
}
for _, word := range words {
found := re.MatchString(word)
if found {
fmt.Printf("%s matches\n", word)
} else {
fmt.Printf("%s does not match\n", word)
}
}
}
В примере с кодом мы использовали скомпилированное регулярное выражение.
re, err := regexp.Compile(".even")
Мы компилируем регулярное выражение с помощью Compile.
found := re.MatchString(word)
Функция MatchString вызывается для возвращаемого объекта regex.
package main
import (
"fmt"
"regexp"
)
func main() {
words := [...]string{"Seven", "even", "Maven", "Amen", "eleven"}
re := regexp.MustCompile(".even")
for _, word := range words {
found := re.MatchString(word)
if found {
fmt.Printf("%s matches\n", word)
} else {
fmt.Printf("%s does not match\n", word)
}
}
}
Пример упрощен с помощью MustCompile.
Go regex FindAllString
Функция FindAllString возвращает фрагмент всех последовательных совпадений регулярного выражения.
package main
import (
"fmt"
"os"
"regexp"
)
func main() {
var content = `Foxes are omnivorous mammals belonging to several genera
of the family Canidae. Foxes have a flattened skull, upright triangular ears,
a pointed, slightly upturned snout, and a long bushy tail. Foxes live on every
continent except Antarctica. By far the most common and widespread species of
fox is the red fox.`
re := regexp.MustCompile("(?i)fox(es)?")
found := re.FindAllString(content, -1)
fmt.Printf("%q\n", found)
if found == nil {
fmt.Printf("no match found\n")
os.Exit(1)
}
for _, word := range found {
fmt.Printf("%s\n", word)
}
}
В примере кода мы находим все вхождения слова fox, включая его форму множественного числа.
re := regexp.MustCompile("(?i)fox(es)?")
При использовании синтаксиса (?i) регулярное выражение не зависит от регистра. Символ (es)? указывает, что символы “es” могут быть включены как ноль раз, так и один раз.
found := re.FindAllString(content, -1)
С помощью FindAllString мы ищем все вхождения заданного регулярного выражения. Второй параметр – максимальное количество совпадений; -1 означает поиск всех возможных совпадений.
$ go run findall.go
["Foxes" "Foxes" "Foxes" "fox" "fox"]
Foxes
Foxes
Foxes
fox
fox
Мы нашли пять совпадений.
Go regex FindAllStringIndex
FindAllStringIndex возвращает фрагмент всех последовательных индексов совпадений с выражением.
package main
import (
"fmt"
"regexp"
)
func main() {
var content = `Foxes are omnivorous mammals belonging to several genera
of the family Canidae. Foxes have a flattened skull, upright triangular ears,
a pointed, slightly upturned snout, and a long bushy tail. Foxes live on every
continent except Antarctica. By far the most common and widespread species of
fox is the red fox.`
re := regexp.MustCompile("(?i)fox(es)?")
idx := re.FindAllStringIndex(content, -1)
for _, j := range idx {
match := content[j[0]:j[1]]
fmt.Printf("%s at %d:%d\n", match, j[0], j[1])
}
}
В примере с кодом мы находим все вхождения слова fox и их индексы в тексте.
$ go run allindex.go
Foxes at 0:5
Foxes at 81:86
Foxes at 196:201
fox at 296:299
fox at 311:314
Go regex Split
Функция Split разрезает строку на подстроки, разделенные заданным регулярным выражением. Она возвращает фрагмент подстроки между совпадениями этих выражений.
package main
import (
"fmt"
"log"
"regexp"
"strconv"
)
func main() {
var data = `22, 1, 3, 4, 5, 17, 4, 3, 21, 4, 5, 1, 48, 9, 42`
sum := 0
re := regexp.MustCompile(",\\s*")
vals := re.Split(data, -1)
for _, val := range vals {
n, err := strconv.Atoi(val)
sum += n
if err != nil {
log.Fatal(err)
}
}
fmt.Println(sum)
}
В примере кода у нас есть список значений, разделенных запятыми. Мы вырезаем значения из строки и вычисляем их сумму.
re := regexp.MustCompile(",\\s*")
Регулярное выражение включает символ запятой и любое количество смежных пробелов.
vals := re.Split(data, -1)
Мы получаем срез ценностей.
for _, val := range vals {
n, err := strconv.Atoi(val)
sum += n
if err != nil {
log.Fatal(err)
}
}
Мы проходим по срезу и вычисляем сумму. Слайс содержит строки, поэтому мы преобразуем каждую строку в целое число с помощью функции strconv.Atoi.
$ go run splittext.go
189
Сумма значений равна 189.
Go regex capturing groups
Круглые скобки () используются для создания групп захвата. Это позволяет применить квантификатор ко всей группе или ограничить чередование частью регулярного выражения.
Чтобы найти группы захвата (в Go используется термин “подвыражения”), мы используем функцию FindStringSubmatch.
package main
import (
"fmt"
"regexp"
)
func main() {
websites := [...]string{"webcode.me", "zetcode.com", "freebsd.org", "netbsd.org"}
re := regexp.MustCompile("(\\w+)\\.(\\w+)")
for _, website := range websites {
parts := re.FindStringSubmatch(website)
for i, _ := range parts {
fmt.Println(parts[i])
}
fmt.Println("---------------------")
}
}
В примере кода мы разделили доменные имена на две части с помощью групп.
re := regexp.MustCompile("(\\w+)\\.(\\w+)")
В скобках мы обозначили две группы.
parts := re.FindStringSubmatch(website)
FindStringSubmatch возвращает фрагмент строк, содержащих совпадения, включая совпадения из групп захвата.
$ go run capturegroups.go
webcode.me
webcode
me
---------------------
zetcode.com
zetcode
com
---------------------
freebsd.org
freebsd
org
---------------------
netbsd.org
netbsd
org
---------------------
Go regex replacing strings
С помощью ReplaceAllString можно заменять строки. Метод возвращает измененную строку.
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"regexp"
"strings"
)
func main() {
resp, err := http.Get("http://webcode.me")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
content := string(body)
re := regexp.MustCompile("<[^>]*>")
replaced := re.ReplaceAllString(content, "")
fmt.Println(strings.TrimSpace(replaced))
}
Пример считывает HTML-данные веб-страницы и удаляет ее HTML-теги с помощью регулярного выражения.
resp, err := http.Get("http://webcode.me")
Мы создаем GET-запрос с помощью функции Get из пакета http.
body, err := ioutil.ReadAll(resp.Body)
Мы читаем тело объекта ответа.
re := regexp.MustCompile("<[^>]*>")
Этот шаблон задает регулярное выражение, которое соответствует HTML-тегам.
replaced := re.ReplaceAllString(content, "")
Мы удаляем все теги с помощью метода ReplaceAllString.
Go regex ReplaceAllStringFunc
Функция ReplaceAllStringFunc возвращает копию строки, в которой все совпадения регулярного выражения были заменены возвращаемым значением указанной функции.
package main
import (
"fmt"
"regexp"
"strings"
)
func main() {
content := "an old eagle"
re := regexp.MustCompile(`[^aeiou]`)
fmt.Println(re.ReplaceAllStringFunc(content, strings.ToUpper))
}
В примере кода мы применяем функцию strings.ToUpper ко всем виткам строки.
$ go run replaceallfunc.go
aN oLD eaGLe
В этой статье мы работали с регулярными выражениями в Go.