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\\\\ba\\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)^aaaa aaa
$Конец текста (или строки при модификаторе ?m)a$aaa aaa
\bГраница словаa\baaa aaa
\baaaa aaa
\BНе граница слова\Ba\Baaa aaa
\GПредыдущий успешный поиск\Gaaaa aaa (поиск остановился на 4-й позиции — там, где не нашлось a)
ПредставлениеЧисло повторенийЭквивалентПримерСоответствие
?Ноль или одно{0,1}colou?rcolorcolour
*Ноль или более{0,}colou*rcolorcolourcolouur и т. д.
+Одно или более{1,}colou+rcolourcolouur и т. д. (но не color)
ПредставлениеЧисло повторенийПримерСоответствие
{n}Ровно n разcolou{3}rcolouuur
{m,n}От m до n включительноcolou{2,4}rcolouurcolouuurcolouuuur
{m,}Не менее mcolou{2,}rcolouurcolouuurcolouuuur и т. д.
{,n}Не более ncolou{,3}rcolorcolourcolouurcolouuur

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.

+1
0
+1
0
+1
0
+1
0
+1
0

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *