Регулярні вирази дають надзвичайно універсальний спосіб знаходити збіги за зразком у рядках тексту (англ. string) за допомогою предметно-орієнтованої мови (DSL), створеної саме для цього.
Як і чимало інших мов програмування, Julia не намагається реалізувати власну бібліотеку регулярних виразів. Натомість вона обгортає популярну бібліотеку PCRE2, тож синтаксис регулярних виразів у ній ідентичний до (наприклад) Gleam і дуже схожий на JavaScript.
Цей силабус Julia припускає, що ми вже знайомі з базовим синтаксисом регулярних виразів. Ми зосередимося виключно на особливостях, властивих Julia.
Нижче наведено кілька ресурсів, щоб освіжити знання регулярних виразів.
Інтерфейс Julia для роботи з регулярними виразами описано в посібнику.
У Julia регулярний вираз — це просто рядок тексту, перед яким стоїть r, а вже потім відкривальна ".
Уся базова функціональність входить до стандартної бібліотеки.
Насправді багато функцій, які вже розглядалися в концепції Strings, стандартно призначені для пошуку за регулярними виразами, як-от occursin().
julia> re = r"test$"
r"test$"
julia> typeof(re)
Regex
# Does a string end with "test"?
julia> occursin(re, "this is a test")
true
julia> occursin(re, "these are tests")
false
Після закривальної лапки можуть стояти символи-модифікатори, як-от i для пошуку без урахування регістру.
julia> occursin(r"test", "Testing")
false
julia> occursin(r"test"i, "Testing")
true
Часто нам хочеться знати, що саме збіглося. Для цього в регулярний вираз додають групи захоплення в дужках, а потім використовують функцію match().
julia> m = match(r"(\d+g) .* (\d+ml)", "dissolve 25g sugar in 200ml water")
RegexMatch("25g sugar in 200ml", 1="25g", 2="200ml")
julia> m.captures
2-element Vector{Union{Nothing, SubString{String}}}:
"25g"
"200ml"
# how many matches?
julia> length(m.captures)
2
# what matched?
julia> m[1], m[2]
("25g", "200ml")
# Starting positions of the matches (character index)
julia> m.offsets
2-element Vector{Int64}:
10
23
Звісно, збіг може й не знайтися.
Тоді результатом замість RegexMatch буде особливе значення Nothing, тож варто бути готовими це перевірити.
# failed match
m = match(r"(not here)", "dissolve 25g sugar in 200ml water")
julia> typeof(m)
Nothing
julia> isnothing(m)
true
Хоча match типово починає пошук від початку рядка тексту, ми можемо вказати зсув n, щоб проігнорувати перші n символів.
# capture first match
julia> m = match(r"(\wat)", "cat, sat, mat")
RegexMatch("cat", 1="cat")
# ignore first 5 characters, then match
julia> m = match(r"(\wat)", "cat, sat, mat", 5)
RegexMatch("sat", 1="sat")
У Julia match() знаходить лише перший збіг у цільовому рядку тексту: глобального модифікатора, як у деяких інших мовах, тут немає.
Натомість є eachmatch(), яка повертає ітератор збігів.
Він обчислюється ліниво, тож, імовірно, його доведеться перетворити на потрібний формат.
julia> matches = eachmatch(r"(\wat)", "cat, sat, mat")
Base.RegexMatchIterator{String}(r"(\wat)", "cat, sat, mat", false)
# convert to vector
julia> collect(matches)
3-element Vector{RegexMatch}:
RegexMatch("cat", 1="cat")
RegexMatch("sat", 1="sat")
RegexMatch("mat", 1="mat")
# convert with comprehension
julia> [m.match for m in matches]
3-element Vector{SubString{String}}:
"cat"
"sat"
"mat"
# broadcast an anonymous function
julia> (m -> m.match).(matches)
3-element Vector{SubString{String}}:
"cat"
"sat"
"mat"
Одна з поширених причин скористатися регулярними виразами - замінити знайдений збіг іншим рядком тексту.
Функцію replace() ми вже розглядали в концепції Strings, коли шукали за рядковими літералами.
Та сама функція може задіяти всю потугу зіставлення з регулярними виразами.
julia> replace("some string", r"[aeiou]" => "*")
"s*m* str*ng"
julia> replace("first second", r"(\w+) (?<agroup>\w+)" => s"\g<agroup> \1")
"second first"
Другий приклад вище показує, як і нумеровані, і іменовані групи захоплення можна використати в заміні, всередині рядка s" ".
Докладніше дивімося в посібнику: це тема, яка постійно повертає більшість програмістів до документації!
Нас найняли на посаду спеціаліста з регулярних виразів у компанію, яка розробляє чатбота.
Вона перебуває на дуже ранній стадії розробки, тож наше завдання - використовувати регулярні вирази, щоб поліпшити здатність чатбота розуміти й генерувати природну мову.
З навчальною метою виконуйте ці завдання за допомогою регулярних виразів.
Ми знаємо, що іноді можливі альтернативи (і навіть продуктивніші!)
Окрім того, що чатбот кмітливий, він ще й відданий помічник.
Щоб щось запитати в чатбота, користувач має сказати слово «Chatbot» на першій позиції команди.
Не має значення, написане ключове слово великими чи малими літерами. Важлива тут саме позиція слова.
Реалізуйте функцію is_valid_command(), яка допомагає чатботу розпізнати, коли користувач дає команду.
julia> is_valid_command("Chatbot, play a song from the 80's.")
True
julia> is_valid_command("Hey Chatbot, where is the closest pharmacy?")
False
julia> is_valid_command("CHATBOT, do you have a solution for this challenge?")
True
Чатботу непросто зрозуміти, як люди використовують емодзі, щоб виражати свої емоції.
Коли чатбот отримує повідомлення від користувача, кожен емодзі представлено як «emoji», за яким іде його id-номер.
Реалізуйте метод remove_emoji(), який приймає рядок тексту (англ. string) і прибирає все шифрування емодзі з повідомлення.
Рядки, які не містять тексту емодзі, мають повертатися без змін.
Просто видаліть текст емодзі. Не намагайтеся коригувати пробіли.
julia> remove_emoji("I love playing videogames emoji3465 it's one of my hobbies")
"I love playing videogames it's one of my hobbies"
Зважаючи на те, що можливості чатбота завантажуються в мобільному застосунку, користувач має написати номер телефону під час розмови.
Проблема в тому, що чатбот уміє прочитати й перевірити лише номер певного формату.
Якщо номер дійсний (збігається з послідовністю символів, заданою регулярним виразом), чатбот відповідає повідомленням, у якому дякує користувачу й підтверджує номер. Якщо номер недійсний, функція повідомляє користувача, що номер телефону недійсний.
Очікуваний формат: (+##) ###-###-###
julia> check_phone_number("(+34) 659-771-594")
"Thanks! You can now download me to your phone."
julia> check_phone_number("659-771-594")
"Oops, it seems like I can't reach out to 659-771-594"
Чатбот - дуже допитлива програма. Хоча він уміє шукати в інтернеті інформацію на певну тему, йому подобається розпитувати користувачів про цікаві вебсайти чи URL-адреси, щоб знайти потрібну інформацію.
Приклад розмови:
Реалізуйте функцію getURL(), яка повертає масив лише з посиланням на кожен вебсайт.
julia> getURL("I learned a lot from exercism.org")
["exercism.org"]
Щоб зберігати дані про всіх, хто спілкувався з ним, чатбот може взяти повне імʼя з профілю користувача в такому форматі: «smith, john».
Так ми хочемо, щоб наш чатбот був дуже ввічливим і справляв гарне враження.
Напишіть функцію nice_to_meet_you(), яка приймає рядок тексту з повним імʼям користувача й повертає рядок «Nice to meet you, John Smith»
julia> str = "Smith, John"
julia> nice_to_meet_you(str)
"Nice to meet you, John Smith"
Зареєструйтеся на Exercism, щоб вивчати й опановувати Julia, а також 35 концепцій128 вправ та справжнє наставництво від людей, і все це безкоштовно.