30 марта 2020 г. Regular Expressions Sources
Почему регулярные выражения с точкой (".") работают по-другому в Go по сравнению с PHP и JavaScript.
Для включения подсветки синтаксиса кода на этом сайте я использую регулярные выражения. Логика проста — я помещаю исходный код в специальные HTML-теги. Когда пост загружается, я обрабатываю эти теги — ищу их с помощью регулярных выражений и заменяю исходный код на подсвеченные версии.
Я потратил много времени, пытаясь понять, почему некоторые примеры кода не совпадали с регулярными выражениями. Я использовал специальный символ точки “.” для сопоставления любого символа внутри моего тега. Посмотрите на следующий пример регулярного выражения и текста и угадайте, совпадает ли он или нет:
Регулярное выражение:
<tag>(.*?)</tag>
Текст:
<tag>1
2
3</tag>
Если у вас есть опыт работы с PHP, ваш ответ, вероятно, будет “да”.
Однако простой пример из Go Playground ясно показывает, что ответ на самом деле “нет”:
match, _ := regexp.MatchString("<tag>(.*)</tag>", "<tag>1\n2\n3</tag>")
fmt.Println(match)
// false
Затем я искал в исходниках Go, пытаясь понять, как Go работает с классами символов, и нашел следующий список флагов:
const (
FoldCase Flags = 1 << iota // case-insensitive match
Literal // treat pattern as literal string
ClassNL // allow character classes like [^a-z] and [[:space:]] to match newline
DotNL // allow . to match newline
OneLine // treat ^ and $ as only matching at beginning and end of text
NonGreedy // make repetition operators default to non-greedy
PerlX // allow Perl extensions
UnicodeGroups // allow \p{Han}, \P{Han} for Unicode group and negation
WasDollar // regexp OpEndText was $, not \z
Simple // regexp contains no counted repetition
MatchNL = ClassNL | DotNL
Perl = ClassNL | OneLine | PerlX | UnicodeGroups // as close to Perl as possible
POSIX Flags = 0 // POSIX syntax
)
Согласно исходникам, Go работает следующим образом:
syntax.Parsesyntax.Parse использует Flags для “планирования” выполнения регулярного выражения (для сопоставления символов регулярного выражения с операциями)regexp.Regexp (публичная структура) создается с использованием результатов syntax.ParseТаким образом, нам нужно скомпилировать регулярное выражение с флагом DotNL.
Когда я искал все случаи использования функции regexp.Compile, я обнаружил, что доступны только два варианта флагов регулярных выражений — POSIX и Perl. Это означает, что в Go нет возможности сопоставлять символы новой строки с точкой.
Итак, регулярное выражение, которое на самом деле работает, приведено ниже:
<tag>([[:graph:]\\s]*?)</tag>
Также существует множество предопределенных классов символов, документированных здесь. Я использовал два из них, чтобы покрыть все символы в скобках [].
Пакеты text/template и html/template являются частью стандартной библиотеки Go. Шаблоны Go используются во многих программах, написанных на Go — Docker, Kubernetes, Helm. Многие сторонние библиотеки интегрированы с шаблонами Go, например Echo. Знание синтаксиса шаблонов Go очень полезно.
Эта статья состоит из документации пакета text/template и нескольких решений автора. После описания синтаксиса шаблонов Go мы погрузимся в исходники text/template и html/template.
В блоге Go описывается, как использовать срезы. Давайте посмотрим на внутреннее устройство срезов.
Read More → Slice Allocation SourcesВ Go у нас есть функциональность горутин из коробки. Мы можем запускать код параллельно. Однако в нашем параллельно выполняющемся коде мы можем работать с общими переменными, и не совсем понятно, как именно Go обрабатывает такие ситуации.
Read More → Map SourcesПрограммный интерфейс map в Go описан в блоге Go. Нам просто нужно вспомнить, что map — это хранилище ключ-значение, и оно должно извлекать значения по ключу как можно быстрее.
Read More → Map SourcesWhy PHP- and JavaScript-like regular expressions work with dot (".") work differently in GO.
Read More → Regular Expressions Sources