Треки
/
Julia
Julia
/
Вправи
/
Регулярний чатбот
Регулярний чатбот

Регулярний чатбот

Навчальна вправа

Вступ

Регулярні вирази дають надзвичайно універсальний спосіб знаходити збіги за зразком у рядках тексту (англ. string) за допомогою предметно-орієнтованої мови (DSL), створеної саме для цього.

Як і чимало інших мов програмування, Julia не намагається реалізувати власну бібліотеку регулярних виразів. Натомість вона обгортає популярну бібліотеку PCRE2, тож синтаксис регулярних виразів у ній ідентичний до (наприклад) Gleam і дуже схожий на JavaScript.

Note

Цей силабус 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" ".

Докладніше дивімося в посібнику: це тема, яка постійно повертає більшість програмістів до документації!

Вказівки

Нас найняли на посаду спеціаліста з регулярних виразів у компанію, яка розробляє чатбота.

Вона перебуває на дуже ранній стадії розробки, тож наше завдання - використовувати регулярні вирази, щоб поліпшити здатність чатбота розуміти й генерувати природну мову.

Note

З навчальною метою виконуйте ці завдання за допомогою регулярних виразів.

Ми знаємо, що іноді можливі альтернативи (і навіть продуктивніші!)

1. Перевірте дійсну команду

Окрім того, що чатбот кмітливий, він ще й відданий помічник.

Щоб щось запитати в чатбота, користувач має сказати слово «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

2. Видаліть зашифровані емодзі

Чатботу непросто зрозуміти, як люди використовують емодзі, щоб виражати свої емоції.

Коли чатбот отримує повідомлення від користувача, кожен емодзі представлено як «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"

3. Перевірте дійсний номер телефону

Зважаючи на те, що можливості чатбота завантажуються в мобільному застосунку, користувач має написати номер телефону під час розмови.

Проблема в тому, що чатбот уміє прочитати й перевірити лише номер певного формату.

Якщо номер дійсний (збігається з послідовністю символів, заданою регулярним виразом), чатбот відповідає повідомленням, у якому дякує користувачу й підтверджує номер. Якщо номер недійсний, функція повідомляє користувача, що номер телефону недійсний.

Очікуваний формат: (+##) ###-###-###

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"

4. Отримайте посилання на вебсайт

Чатбот - дуже допитлива програма. Хоча він уміє шукати в інтернеті інформацію на певну тему, йому подобається розпитувати користувачів про цікаві вебсайти чи URL-адреси, щоб знайти потрібну інформацію.

Приклад розмови:

  • Чатбот: Привіт, username, я хочу навчитися програмувати на JavaScript, чи є якийсь класний вебсайт, де можна цього навчитися?
  • Користувач: Я багато дізнався з exercism.org

Реалізуйте функцію getURL(), яка повертає масив лише з посиланням на кожен вебсайт.

julia> getURL("I learned a lot from exercism.org")
["exercism.org"]

5. Привітайте користувача

Щоб зберігати дані про всіх, хто спілкувався з ним, чатбот може взяти повне імʼя з профілю користувача в такому форматі: «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"
Редагувати через GitHub Посилання відкривається в новому вікні або вкладці
Julia Exercism

Час розпочати Регулярний чатбот?

Зареєструйтеся на Exercism, щоб вивчати й опановувати Julia, а також 35 концепцій128 вправ та справжнє наставництво від людей, і все це безкоштовно.