عبارتهای باقاعده روشی بسیار همهکاره برای تطبیق الگو در رشتهها هستند و از یک زبان دامنهویژه (DSL) استفاده میکنند که دقیقاً برای همین منظور طراحی شده است.
جولیا هم مانند چند زبان برنامهنویسی دیگر سعی نمیکند کتابخانهی Regex مخصوص خودش را پیادهسازی کند. در عوض، کتابخانهی پرآوازهی PCRE2 را پوشش میدهد و به این ترتیب نحوهی نگارش Regex یکسانی با (برای مثال) Gleam و بسیار شبیه به JavaScript فراهم میکند.
این سرفصل جولیا فرض میکند که شما از قبل با نحوهی نگارش پایهی Regex آشنا هستید. ما فقط روی ویژگیهای مخصوص جولیا تمرکز میکنیم.
چند منبع برای تازه کردن دانش عبارت باقاعدهی شما در ادامه آمده است.
رابط جولیا با عبارتهای باقاعده در راهنما توضیح داده شده است.
یک عبارت باقاعده در جولیا به سادگی رشتهای است که پیش از " آغازین آن، یک 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
معمولاً میخواهیم بدانیم چه چیزی تطبیق میخورد. برای این کار، «گروههای گیرانداز» را داخل پرانتز در Regex قرار میدهیم و سپس از تابع 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")
در جولیا، 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"
تطبیقهای همپوشان بهطور پیشفرض مجاز نیستند.
برای لغو این رفتار، overlap = true را بهعنوان یک «آرگومان کلیدواژهای» اضافه کنید.
julia> eachmatch(r"aba", "abababa") |> collect # matches at positions 1, 5
2-element Vector{RegexMatch}:
RegexMatch("aba")
RegexMatch("aba")
julia> eachmatch(r"aba", "abababa"; overlap = true) |> collect # also matches at position 3
3-element Vector{RegexMatch}:
RegexMatch("aba")
RegexMatch("aba")
RegexMatch("aba")
یکی از دلایل رایج استفاده از 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" "، به کار برد.
برای جزئیات بیشتر راهنما را ببینید: این موضوعی است که مدام بیشتر برنامهنویسان را وادار میکند به مستندات برگردند!