понедельник, 16 марта 2020 г.

Каналы в Golang предлагают синхронизированное общение

Канал - это механизм, позволяющий goroutines синхронизировать выполнение и обмениваться данными посредством передачи значений.

Новое значение канала можно задать с помощью встроенной функции make.

// небуферизованный канал целых чисел
ic := make(chan int)

// буферизованный канал с местом для 10 строк
sc := make(chan string, 10)

Чтобы отправить значение в канал, используйте <- в качестве бинарного оператора. Чтобы получить значение из канала, используйте <- его как унарный оператор.

ic <- 3   // Отправляем 3 по каналу
n := <-sc // Получаем string из канала

Оператор <- указывает направление канала, отправлять или получать. Если направление не указано, канал является двунаправленным.

chan Sushi    // может использоваться для отправки 
              // и получения значений типа Sushi

chan<- string // может использоваться только 
              // для отправки строк

<-chan int    // может использоваться только 
              // для получения целых чисел

Буферизованные и небуферизованные каналы

Если пропускная способность канала равна нулю или отсутствует, канал не буферизуется, и отправитель блокируется, пока получатель не получит значение.

Если у канала есть буфер, отправитель блокируется только до тех пор, пока значение не будет скопировано в буфер; если буфер заполнен, это означает ожидание, пока какой-либо получатель не получит значение.

Приемники всегда блокируются, пока нет данных для приема.

Отправка или получение из нулевого канала блокирует навсегда.

Закрытие канала

Функция close записывает, что больше значений не будет отправлено по каналу. Обратите внимание, что необходимо только закрыть канал, если получатель ищет закрытие.

  • После вызова close и после получения ранее отправленных значений операции приема вернут нулевое значение без блокировки.
  • Многозначная операция приема дополнительно возвращает указание о том, закрыт ли канал.
  • Отправка по закрытому каналу или закрытие закрытого канала вызывает панику во время выполнения. Закрытие нулевого канала также вызывает панику во время выполнения.

ch := make(chan string)
go func() {
    ch <- "Hello!"
    close(ch)
}()

fmt.Println(<-ch) // Печатает "Hello!".
fmt.Println(<-ch) // Печатает нулевое значение строки - "" 
                  // без блокировки.
fmt.Println(<-ch) // Еще раз печатает "".
v, ok := <-ch     // v равно "", ok равно false.

// Получаем значения от ch до закрытия.
for v := range ch {
    fmt.Println(v) // Не будет выполнено.
}

Пример

В следующем примере мы позволяем функции Publish возвращать канал, который используется для трансляции сообщения, когда текст опубликован.

// Publish печатает текст на стандартный вывод 
// по истечении заданного времени.
// Он закрывает канал wait после публикации текста.
func Publish(text string, delay time.Duration) (wait <-chan struct{}) {
    ch := make(chan struct{})
    go func() {
        time.Sleep(delay)
        fmt.Println(text)
        close(ch)
    }()
    return ch
}

Обратите внимание, что мы используем канал с пустыми структурами, чтобы указать, что канал будет использоваться только для сигнализации, а не для передачи данных. Вот как вы можете использовать эту функцию.

wait := Publish("important news", 2 * time.Minute)
// Выполняем еще немного работы.
<-wait // Блокирует, пока текст не будет опубликован.


Читайте также:


Купить gopher

воскресенье, 15 марта 2020 г.

Goroutines - легкие потоки

Оператор go запускает функцию в отдельном потоке выполнения.

Вы можете начать новый поток выполнения, goroutine, с помощью оператора go. Он запускает функцию в другой, недавно созданной goroutine. Все goroutines в одной программе имеют одинаковое адресное пространство.

go list.Sort() // Запустить list.Sort параллельно; не ждите этого.

Следующая программа напечатает "Привет из главной goroutine". Также может быть напечатано "Привет из другой goroutine", в зависимости от того, какая из двух goroutine завершится первой.

func main() {
    go fmt.Println("Привет из другой goroutine")
    fmt.Println("Привет из главной goroutine")

    // На этом этапе выполнение программы останавливается
    // и все активные goroutines убиты.
}

Следующая программа, скорее всего, напечатает "Привет из главной goroutine" и "Привет из другой goroutine". Они могут быть напечатаны в любом порядке. Еще одна возможность заключается в том, что вторая goroutine чрезвычайно медленная и не печатает свое сообщение до завершения программы.

func main() {
    go fmt.Println("Привет из другой goroutine")
    fmt.Println("Привет из главной goroutine")

    // даем время другой goroutine завершиться
    time.Sleep(time.Second) 
}

Вот несколько более реалистичный пример, где мы определяем функцию, которая использует конкурентность для отсрочки события.

// Publish выводит текст на стандартный вывод 
// по истечении заданного времени.
// Она не блокируется, но сразу возвращается.
func Publish(text string, delay time.Duration) {
    go func() {
        time.Sleep(delay)
        fmt.Println("BREAKING NEWS:", text)
    }() // Обратите внимание на круглые скобки. 
        // Мы должны вызвать анонимную функцию.
}

Вот как вы можете использовать функцию Publish.

func main() {
    Publish("goroutine запускается в новом потоке", 5*time.Second)
    fmt.Println("Будем надеяться, что новости будут опубликованы до того как я выйду")

    // Дождаться публикации новостей.
    time.Sleep(10 * time.Second)

    fmt.Println("Десять секунд спустя: я выхожу сейчас")
}

Программа, скорее всего, напечатает эти три строки в указанном порядке и с пятисекундным перерывом между каждой строкой.

$ go run publish1.go
Будем надеяться, что новости будут опубликованы до того как я выйду
BREAKING NEWS: goroutine запускается в новом потоке
Десять секунд спустя: я выхожу сейчас

В общем случае невозможно организовать, чтобы потоки ждали друг друга за счет Sleep. Основным методом синхронизации в Go является использование каналов.

Реализация

Goroutines легки, стоят немного больше, чем выделение стекового пространства. Стеки начинаются с малого и растут, выделяя и освобождая хранилище кучи по мере необходимости.

Внутренние goroutines действуют как сопрограммы (coroutines), которые мультиплексируются между несколькими потоками операционной системы. Если одна goroutine блокирует поток ОС, например, ожидая ввода, другие goroutines в этом потоке будут мигрировать, чтобы продолжить работу.


Читайте также:


Купить gopher

суббота, 14 марта 2020 г.

Использование fmt.Printf в Golang

С пакетом fmt в Go вы можете форматировать числа и строки, дополненные пробелами или нулями, в разных основах и с дополнительными кавычками.

Вы отправляете строку шаблона, которая содержит текст, который вы хотите отформатировать, плюс несколько глаголов аннотации, которые сообщают функциям fmt, как форматировать конечные аргументы.

Printf

В этом примере fmt.Printf форматирует и записывает в стандартный вывод:

fmt.Printf("Binary: %b\\%b", 4, 5) 
// Печатает `Binary: 100\101`

  • строка шаблона имеет вид "Binary: %b\\%b"
  • глагол аннотации %b форматирует число в двоичном формате
  • специальное значение \\ является обратной косой чертой.

В особом случае глагол %%, который не использует аргументов, производит знак процента:

fmt.Printf("%d %%", 50) 
// Печатает `50 %`

Sprintf (форматирование без печати)

Используйте fmt.Sprintf для форматирования строки без ее печати:

s := fmt.Sprintf("Binary: %b\\%b", 4, 5) 
// s == `Binary: 100\101`

Нахождение ошибок fmt с помощью vet

Если вы попытаетесь скомпилировать и запустить эту некорректную строку кода

fmt.Printf("Binary: %b\\%b", 4) 
// Отсуствует аргумент для Printf

вы обнаружите, что программа скомпилируется, а затем напечатает

Binary: 100\%!b(MISSING)

Для раннего обнаружения ошибок такого типа вы можете использовать команду vet - она ​​может найти вызовы, аргументы которых не совпадают со строкой формата.

$ go vet example.go
example.go:8: missing argument for Printf("%b"): format reads arg 2, have only 1 args

Варианты использования fmt.Printf


Стандартные форматы и тип

Значение: []int64{0, 1}

Формат Глагол Описание
[0 1] %v Формат по умолчанию
[]int64{0, 1} %#v Формат синтаксиса Go
[]int64 %T Тип значения

Целое число (отступ, основание, знак)

Значение: 15

Формат
Глагол
Описание
15 %d Основание 10
+15 %+d Всегда показывать знак
␣␣15
%4d Отступ с пробелами (ширина 4, выравнивание по правому краю)
15␣␣
%-4d Отступ с пробелами (ширина 4, выравнивание по левому краю)
0015 %04d Отступ с нулями (ширина 4)
1111 %b Основание 2
17 %o Основание 8
f %x Основание 16, нижний регистр
F %X Основание 16, верхний регистр
0xf %#x Основание 16, с ведущим 0x

Символ (цитата, Unicode)

Значение: 65 (Unicode буква A)

Формат Глагол Описание
A %c Символ
'A' %q Цитируемый символ
U+0041 %U Unicode
U+0041 'A' %#U Unicode с символом

Логическое (true/false)

Используйте %t, чтобы отформатировать логическое значение как true или false.

Указатель (шестнадцатеричный)

Используйте %p для форматирования указателя с основанием 16 с начальным 0x.

Float (отступ, точность, научная запись)

Значение: 123.456

Формат Глагол Описание
1.234560e+02
%e Научная запись
123.456000 %f Десятичная точка, без экспоненты
123.46 %.2f Ширина по умолчанию, точность 2
␣␣123.46
%8.2f
Ширина 8, точность 2
123.456 %g Экспонент по мере необходимости, только необходимые цифры

Срез строк или байтов (кавычка, отступ, шестнадцатеричный)

Значение: "café"

Формат Глагол Описание
café %s Обычная строка
␣␣café %6s Ширина 6, выравнивание по правому краю
café␣␣ %-6s Ширина 6, выравнивание по левому краю
"café" %q Цитируемая строка
636166c3a9 %x шестнадцатеричный дамп байтовых значений
63 61 66 c3 a9 % x шестнадцатеричный дамп с пробелами

Специальные значения

Значение Описание
\a U+0007 оповещение или звонок
\b U+0008 backspace
\\ U+005c обратный слэш
\t U+0009 горизонтальный таб
\n U+000A перевод строки (line feed) или новая строка (newline)
\f U+000C form feed
\r U+000D возврат каретки
\v U+000b вертикальный таб

Произвольные значения могут быть закодированы с помощью обратной косой черты и могут использоваться в любом "" строковом литерале.

Существует четыре разных формата:

  • \x, за которыми следуют ровно две шестнадцатеричные цифры
  • \ за которыми следуют ровно три восьмеричные цифры
  • \u за которыми следуют ровно четыре шестнадцатеричные цифры
  • \U за которыми следуют ровно восемь шестнадцатеричных цифр

Экранирование \u и \U представляет кодовые точки Unicode.

fmt.Println("\\caf\u00e9") // Печатает \café


Читайте также:


Купить gopher

четверг, 12 марта 2020 г.

Руны и кодировка символов в Golang

Символы, ASCII и Unicode

Тип rune является псевдонимом для int32 и используется, чтобы подчеркнуть, что целое число представляет кодовую точку.

ASCII определяет 128 символов, обозначенных кодовыми точками 0–127. Он охватывает английские буквы, латинские цифры и несколько других символов.

Unicode, который является надмножеством ASCII, определяет кодовое пространство из 1114112 кодовых точек. Unicode версия 10.0 охватывает 139 современных и исторических скриптов (включая рунический алфавит, но не клингон), а также множество наборов символов.

Строки и кодировка UTF-8

Строка - это последовательность байтов, а не рун.

Однако строки часто содержат текст Unicode, закодированный в UTF-8, который кодирует все кодовые точки Unicode, используя от одного до четырех байтов. (Символы ASCII кодируются одним байтом, в то время как другие кодовые точки используют больше.)

Поскольку сам исходный код Go кодируется как UTF-8, строковые литералы автоматически получат эту кодировку.

Например, в строке "café" символ é (кодовая точка 233) кодируется с использованием двух байтов, тогда как символы ASCII c, a и f (кодовые точки 99, 97 и 102) используют только один:

fmt.Println([]byte("café")) // [99 97 102 195 169]
fmt.Println([]rune("café")) // [99 97 102 233]


Читайте также:


Купить gopher

вторник, 10 марта 2020 г.

Обзор обработки строк в Golang

Строковые литералы (экранированные символы)

Выражение Результат Описание
"" Нулевое значение по умолчанию для типа string
"Japan 日本"
Japan 日本
Код Go это Unicode текст, кодированный в UTF‑8
"\xe6\x97\xa5" \xNN определяет byte
"\u65E5" \uNNNN определяет Unicode значение
"\\" \ Обратный слэш
"\"" " Двойная кавычка
"\n" Новая строка
"\t" Символ табуляции
`\xe6` \xe6 Необработанный строковый литерал
html.EscapeString("<>")
&lt;&gt; HTML экранирование для <, >, &, ' и "
url.PathEscape("A B")
A%20B URL %-кодирование net/url

В необработанных строковых литералах (заключены в обратные кавычки ``) текст интерпретируется буквально и обратные слэши не имеют специального значения.

Конкатенация

Выражение Результат Описание
"Ja" + "pan" Japan Конкатенация

Эквивалетность и сравнение (игнорируя регистр)

Выражение
Результат
Описание
"Japan" == "Japan" true Эквивалетность
strings.EqualFold("Japan", "JAPAN") true Сравнение Unicode с оберткой регистра
"Japan" < "japan" true Сравнение в лексикографическом порядке

Длина в байтах или рунах

Выражение
Результат
Описание
len("日") 3 Длина в байтах
utf8.RuneCountInString("日")
1 Длина в рунах unicode/utf8
utf8.ValidString("日") true Проверка UTF-8 ли переданная строка (unicode/utf8)

Индексирование, создание подстроки, итерация

Выражение Результат Описание
"Japan"[2] 'p' Байт в позиции 2
"Japan"[1:3] ap Индексирование байтов
"Japan"[:2] Ja
"Japan"[2:] pan

Цикл range в Go производит итерацию по UTF-8-кодированным символам (руны):

for i, ch := range "Japan 日本" {
    fmt.Printf("%d:%q ", i, ch)
}
// Вывод: 0:'J' 1:'a' 2:'p' 3:'a' 4:'n' 5:' ' 6:'日' 9:'本'

Итерация по байтам производит бессмысленные символы для не-ASCII текста:

s := "Japan 日本"
for i := 0; i < len(s); i++ {
    fmt.Printf("%q ", s[i])
}
// Вывод: 'J' 'a' 'p' 'a' 'n' ' ' 'æ' '\u0097' '¥' 'æ' '\u009c' '¬'

Поиск (contains, prefix/suffix, index)

Выражение
Результат
Описание
strings.Contains("Japan", "abc") false abc в Japan?
strings.ContainsAny("Japan", "abc") true a, b или c в Japan?
strings.Count("Banana", "ana") 1 не перекрывающиеся экземпляры ana
strings.HasPrefix("Japan", "Ja") true Japan начинается с Ja?
strings.HasSuffix("Japan", "pan") true Japan заканчивается на pan?
strings.Index("Japan", "abc") -1 Индекс первого abc
strings.IndexAny("Japan", "abc") 1 Индекс первого a, b или c
strings.LastIndex("Japan", "abc") -1 Индекс последнего abc
strings.LastIndexAny("Japan", "abc") 3 Индекс последнего a, b или c

Замена (uppercase/lowercase, trim)

Выражение
Результат
Описание
strings.Replace("foo", "o", ".", 2) f.. Замена первых двух “o” на “.”. Используйте -1, чтобы заменить все подходящие символы.

f := func(r rune) rune {
    return r + 1
}
strings.Map(f, "ab")

bc Применяет функцию к каждому символу
strings.ToUpper("Japan") JAPAN Приведение к верхнему регистру
strings.ToLower("Japan") japan Приведение к нижнему регистру
strings.Title("ja pan")
Ja Pan
Приведение к верхнему регистру первых букв
strings.TrimSpace(" foo\n") foo Удаление начального и завершающего пробела
strings.Trim("foo", "fo") Удаление начальных и завершающих f и s
strings.TrimLeft("foo", "f") oo Удаление начальных f
strings.TrimRight("foo", "o") f Удаление завершающих f
strings.TrimPrefix("foo", "fo") o Удаление префикса
strings.TrimSuffix("foo", "o") fo Удаление суффикса

Разделение по пробелам или запятым

Выражение Результат Описание
strings.Fields(" a\t b\n") ["a" "b"] Удаление пробелов
strings.Split("a,b", ",") ["a" "b"] Удаление разделителя
strings.SplitAfter("a,b", ",") ["a," "b"] Сохранение разделителя

Объединение строки с разделителем

Выражение Результат Описание
strings.Join([]string{"a", "b"}, ":") a:b Добавление разделителя
strings.Repeat("da", 2) dada 2 копии “da”

Форматирование и конвертирование

Выражение
Результат
Описание
strconv.Itoa(-42) "-42" Int к string
strconv.FormatInt(255, 16) "ff" Конвертирование к шестнадцетиричной основе

Sprintf

Функция fmt.Sprintf часто лучший выбор для форматирования данных:

s := fmt.Sprintf("%.4f", math.Pi) // s == "3.1416"


Читайте также:


Купить gopher

пятница, 6 марта 2020 г.

Эффективная конкатенация строк в Golang

Простое создание строк

Для простых случаев, когда производительность не является проблемой, fmt.Sprintf - ваш друг. Это чисто, просто и довольно эффективно.

s := fmt.Sprintf("Size: %d MB.", 85) // s == "Size: 85 MB."

Высокопроизводительная конкатенация строк с версии Go 1.10

strings.Builder используется для эффективного добавления строк с использованием методов записи.

  • Он предлагает подмножество методов bytes.Buffer, что позволяет безопасно избежать дополнительного копирования при преобразовании Builder в строку.
  • Вы можете использовать пакет fmt для форматирования, поскольку Builder реализует интерфейс io.Writer.
  • Метод Grow может использоваться для предварительного выделения памяти, когда известен максимальный размер строки.

var b strings.Builder
b.Grow(32)
for i, p := range []int{2, 3, 5, 7, 11, 13} {
    fmt.Fprintf(&b, "%d:%d, ", i+1, p)
}
s := b.String()   // нет копирования

s = s[:b.Len()-2] // нет копирования 
                  // (удаляет завершающий ", ")
fmt.Println(s)

Вывод:

1:2, 2:3, 3:5, 4:7, 5:11, 6:13

Создание строк до версии Go 1.10

Используйте fmt.Fprintf для печати в bytes.Buffer.

var buf bytes.Buffer
for i, p := range []int{2, 3, 5, 7, 11, 13} {
    fmt.Fprintf(&buf, "%d:%d, ", i+1, p)
}
buf.Truncate(buf.Len() - 2) // Удаляет завершающий ", "
s := buf.String()           // Копирует в новую строку
fmt.Println(s)

Вывод:

1:2, 2:3, 3:5, 4:7, 5:11, 6:13

Это решение довольно эффективно, но может привести к появлению лишнего мусора. Для более высокой производительности вы можете попробовать использовать функции добавления в пакете strconv.

buf := []byte("Size: ")
buf = strconv.AppendInt(buf, 85, 10)
buf = append(buf, " MB."...)
s := string(buf)

Если ожидаемая максимальная длина строки известна, вы можете предварительно выделить срез.

buf := make([]byte, 0, 16)
buf = append(buf, "Size: "...)
buf = strconv.AppendInt(buf, 85, 10)
buf = append(buf, " MB."...)
s := string(buf)


Читайте также:


Купить gopher

среда, 4 марта 2020 г.

Regexp (регулярные выражения) в Golang

Регулярное выражение - это последовательность символов, которые определяют шаблон поиска.

Регулярное выражение a.b соответствует любой строке, которая начинается с a, заканчивается на b и содержит один символ между ними (точка соответствует любому символу).

Чтобы проверить, существует ли подстрока, соответствующая a.b, используйте функцию regexp.MatchString.

matched, err := regexp.MatchString(`a.b`, "aaxbb")
fmt.Println(matched) // true
fmt.Println(err)     // nil (regexp валидно)

Чтобы проверить, соответствует ли полная строка a.b, закрепите начало и конец регулярного выражения:

  • символ каретки ^ соответствует началу текста или строки,
  • символ доллара $ соответствует концу текста.

matched, _ := regexp.MatchString(`^a.b$`, "aaxbb")
fmt.Println(matched) // false

Точно так же мы можем проверить, начинается ли строка с или заканчивается шаблоном, используя только начальную или конечную привязку.

Compile

Для более сложных запросов вы должны скомпилировать регулярное выражение для создания объекта Regexp. Есть два варианта:

re1, err := regexp.Compile(`regexp`) // error если regexp невалидно
re2 := regexp.MustCompile(`regexp`)  // panic если regexp невалидно

Необработанные строки (Raw strings)

При написании регулярных выражений удобно использовать `raw strings`, поскольку как обычные строковые литералы, так и регулярные выражения используют обратные слэши для специальных символов.

Необработанная строка, разделенная обратными кавычками, интерпретируется буквально, а обратная косая черта (обратный слэш) не имеет особого значения.

Регулярные выражения


Выбор и группировка


Regexp Значение
xy х с последующим у
x|y х или у, предпочитает х
xy|z такой же, как (xy)|z
xy* такой же как х(у*)

Повторение (жадное (greedy) и не жадное (non-greedy))


Regexp Значение
x* ноль или более х, предпочитает больше
x*? ноль или более х, предпочитает меньше (не жадное)
x+ один или несколько х, предпочитает больше
x+? один или несколько х, предпочитает меньше (не жадное)
x? ноль или один х, предпочитает один
x?? ноль или один х, предпочитает ноль
x{n} x точно n раз

Классы символов


Regexp Значение
. (точка) любой символ
[ab] символ a или b
[^ab] любой символ исключая a или b
[a-z] любой символ от a до z
[a-z0-9] любой символ от a до z или от 0 до 9
\d цифра: [0-9]
\D не цифра: [^0-9]
\s пробельный символ: [\t\n\f\r ]
\S не пробельный символ: [^\t\n\f\r ]
\w символ слова: [0-9A-Za-z_]
\W несловесный символ: [^0-9A-Za-z_]
\p{Greek} класс символов Unicode (RE2: имена классов символов Unicode)
\pN однобуквенное имя
\P{Greek} исключая класс символов Unicode (RE2: имена классов символов Unicode)
\PN исключая класс символов Unicode - однобуквенное имя

Специальные символы

Чтобы сопоставить специальный символ \^$.|?*+-[]{}() буквально, экранируйте (escape) его обратной косой чертой. Например, \{ соответствует открывающей фигурной скобке.

Другие escape-последовательности:


Символ Значение
\t символ горизонтальной табуляции (horizontal tab) = \011
\n символ новой строки (newline) = \012
\f form feed = \014
\r символ возврата каретки = \015
\v символ вертикальной табуляции (vertical tab) = \013
\123 восьмеричный код символа (до трех цифр)
\x7F шестнадцатеричный код (ровно две цифры)

Якори границ текста


Символ Значение
\A в начале текста
^ в начале текста или строки
$
\z
в конце текста
\b на границе ASCII слова
\B не на границе ASCII слова

Регистрозависимые и многострочные совпадения

Чтобы изменить поведение сопоставления по умолчанию, вы можете добавить набор флагов в начало регулярного выражения.

Например, префикс "(?is)" делает сопоставление без учета регистра и позволяет . (точке) совпадать \n. (Соответствие по умолчанию чувствительно к регистру и . (точка) не соответствует \n.)

Флаг Значение
i не чувствительны к регистру
m позволяет ^ и $ соотвествовать началу/концу строки в дополнение к началу/концу текста (многострочный режим)
s позволяет . (точка) соотвествовать \n (однострочный режим)

Примеры кода


Первое совпадение

Используйте метод FindString, чтобы найти текст первого совпадения. Если совпадений нет, возвращаемое значение - пустая строка.

re := regexp.MustCompile(`foo.?`)
fmt.Printf("%q\n", re.FindString("seafood fool")) // "food"
fmt.Printf("%q\n", re.FindString("meat"))         // ""

Место расположения

Используйте метод FindStringIndex, чтобы найти loc, местоположение первого совпадения, в строке s. Совпадение в s[loc[0]:loc[1]]. Возвращаемое значение nil указывает на отсутствие совпадения.

re := regexp.MustCompile(`ab?`)
fmt.Println(re.FindStringIndex("tablett"))    // [1 3]
fmt.Println(re.FindStringIndex("foo") == nil) // true

Все совпадения

Используйте метод FindAllString, чтобы найти текст всех совпадений. Возвращаемое значение nil указывает на отсутствие совпадения.

Метод принимает целочисленный аргумент n; если n >= 0, функция возвращает не более n совпадений.

re := regexp.MustCompile(`a.`)
fmt.Printf("%q\n", re.FindAllString("paranormal", -1)) // ["ar" "an" "al"]
fmt.Printf("%q\n", re.FindAllString("paranormal", 2))  // ["ar" "an"]
fmt.Printf("%q\n", re.FindAllString("graal", -1))      // ["aa"]
fmt.Printf("%q\n", re.FindAllString("none", -1))       // [] (nil slice)

Замещение (Replace)

Используйте метод ReplaceAllString для замены текста всех совпадений. Он возвращает копию, заменяя все совпадения регулярного выражения строкой замены.

re := regexp.MustCompile(`ab*`)
fmt.Printf("%q\n", re.ReplaceAllString("-a-abb-", "T")) // "-T-T-"

Метод Split

Используйте метод Split, чтобы разрезать строку на подстроки, разделенные регулярным выражением. Он возвращает часть подстрок между этими совпадениями выражений. Возвращаемое значение nil указывает на отсутствие совпадения.

Метод принимает целочисленный аргумент n; если n >= 0, функция возвращает не более n совпадений.

a := regexp.MustCompile(`a`)
fmt.Printf("%q\n", a.Split("banana", -1)) // ["b" "n" "n" ""]
fmt.Printf("%q\n", a.Split("banana", 0))  // [] (nil slice)
fmt.Printf("%q\n", a.Split("banana", 1))  // ["banana"]
fmt.Printf("%q\n", a.Split("banana", 2))  // ["b" "nana"]

zp := regexp.MustCompile(`z+`)
fmt.Printf("%q\n", zp.Split("pizza", -1)) // ["pi" "a"]
fmt.Printf("%q\n", zp.Split("pizza", 0))  // [] (nil slice)
fmt.Printf("%q\n", zp.Split("pizza", 1))  // ["pizza"]
fmt.Printf("%q\n", zp.Split("pizza", 2))  // ["pi" "a"]

Больше функций

Есть 16 функций, следующих шаблону именования

Find(All)?(String)?(Submatch)?(Index)?

Например: Find, FindAllString, FindStringIndex, ...

  • Если присутствует All, функция сопоставляет последовательные непересекающиеся совпадения.
  • String указывает, что аргумент является строкой; в противном случае это срез байтов.
  • Если Submatch присутствует, возвращаемое значение представляет собой срез последовательных подсовпадений. Подсовпадения - это совпадения заключенных в скобки подвыражений в регулярном выражении.
  • Если Index присутствует, совпадения и субсовпадения идентифицируются парами байтовых индексов.

Реализация

  • Пакет regexp реализует регулярные выражения с синтаксисом RE2.
  • Он поддерживает строки в кодировке UTF-8 и классы символов Unicode.
  • Реализация очень эффективна: время выполнения линейно по размеру ввода.
  • Обратные ссылки не поддерживаются, поскольку они не могут быть эффективно реализованы.

Читайте также:


Купить gopher