среда, 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

Комментариев нет:

Отправить комментарий