مسیرها
/
Julia
Julia
/
تمرین‌ها
/
چت‌بات باقاعده
چت‌بات باقاعده

چت‌بات باقاعده

تمرین یادگیری

مقدمه

«عبارات باقاعده» روشی بسیار انعطاف‌پذیر برای تطبیق الگو روی رشته‌ها هستند که از یک زبان دامنه‌ویژه (DSL) طراحي‌شده برای همین منظور استفاده می‌کنند.

Julia هم مانند چندین زبان برنامه‌نویسی دیگر تلاشی نمی‌کند که کتابخانه‌ی Regex خودش را پیاده‌سازی کند. در عوض، کتابخانه‌ی پرکاربرد PCRE2 را در بر می‌گیرد و بدین ترتیب نحوه‌ی نگارش Regex یکسانی با (برای مثال) Gleam و بسیار شبیه به Javascript ارائه می‌دهد.

Note

این برنامه‌ی درسی Julia فرض می‌کند که شما از قبل با نحوه‌ی نگارش پایه‌ی Regex آشنا هستید. ما فقط روی ویژگی‌های مخصوص Julia تمرکز خواهیم کرد.

چند منبع برای تازه‌کردن دانش عبارات باقاعده‌ی شما در ادامه فهرست شده است.

رابط Julia با عبارات باقاعده در راهنما توضیح داده شده است.

یک عبارت باقاعده در Julia به سادگی رشته‌ای است که پیش از " آغازین، یک r دارد. همه‌ی قابلیت‌های پایه بخشی از کتابخانه‌ی استاندارد هستند.

در واقع، بسیاری از توابعی که پیش‌تر در مفهوم Strings بررسی کردیم، به‌طور پیش‌فرض برای جست‌وجوهای Regex طراحی شده‌اند، مانند 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"

جایگزینی

یکی از دلایل رایج استفاده از Regex، جایگزین کردن تطبیق با رشته‌ای دیگر است.

تابع replace() در مفهوم Strings بررسی شد، آن‌جا که از رشته‌های متنی برای جست‌وجو استفاده می‌کردیم. همین تابع می‌تواند از تمام توان تطبیق Regex بهره ببرد.

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() را پیاده‌سازی کنید تا یک رشته بگیرد و همه‌ی رمزنگاری ایموجی‌ها را در سراسر پیام حذف کند.

خط‌هایی که متن ایموجی ندارند باید بدون تغییر برگردانده شوند.

فقط رشته‌ی ایموجی را حذف کنید. سعی نکنید فاصله‌ها را تنظیم کنید.

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‌ها بپرسد تا اطلاعات مرتبط را پیدا کند.

نمونه‌ای از گفت‌وگو:

  • چت‌بات: سلام کاربر، می‌خواهم یاد بگیرم چطور با 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 تمرین و مربی‌گری انسانی واقعی یاد بگیرید و در آن استاد شوید، همه‌ی این‌ها رایگان.