Regular Expressions — ნულიდან თავდაჯერებულ ავტორამდე

ეს არის პრაქტიკული სახელმძღვანელო რეგულარული გამოსახულებების (RegExp / regex) შესასწავლად — ნაბიჯ-ნაბიჯ, მარტივი ენით, რეალური მაგალითებით. ისწავლი არა მხოლოდ როგორ იწერება შაბლონები, არამედ როდის ღირს მათი გამოყენება და როდის — არა.

ყველა ცნება ახსნილია ფორმულით: თეორია → გამოსახულება → დამთხვევები → არა-დამთხვევები → ახსნა. მაგალითები PHP-ს preg_* ფუნქციებზეა, მაგრამ შაბლონების ლოგიკა ერთნაირია ყველა ენაში (JavaScript, Python, Java, .NET, MySQL...).

10 თავი 72 თემა 40+ პრაქტიკული მაგალითი

1 📖 შესავალი

რა არის რეგულარული გამოსახულებები, საიდან წარმოიშვა, რა პრობლემებს წყვეტს და რატომ იყენებენ მათ ათწლეულების მერეც.

რა არის RegExp

რა არის Regular Expression

რეგულარული გამოსახულება (Regular Expression, შემოკლებით RegExp ან regex) არის პატარა „ენა", რომლითაც ტექსტში შაბლონს (pattern) აღვწერთ. შაბლონის დახმარებით შეგვიძლია ტექსტში ვიპოვოთ, გადავამოწმოთ, ამოვიღოთ ან ჩავანაცვლოთ ის ნაწილები, რომლებიც გარკვეულ წესს ემორჩილებიან.

მაგალითად, ნაცვლად იმისა, რომ ხელით ვწეროთ „იპოვე ყველა სიტყვა, რომელიც იწყება a-ით, შემდეგ მოდის ციფრები..." — regex-ით ამას ერთ მოკლე სტრიქონად ვწერთ: /a\d+/.

დაიმახსოვრე მთავარი იდეა: regex აღწერს არა კონკრეტულ ტექსტს, არამედ ტექსტის ფორმას.

სინტაქსი

Syntax
/pattern/flags

  /        — შაბლონის დასაწყისი (delimiter)
  pattern  — თვითონ წესი (literals + სპეცსიმბოლოები)
  /        — შაბლონის დასასრული
  flags    — დამატებითი პარამეტრები: i (register), u (unicode), m, s ...

მაგალითები

პირველი შაბლონი

ვიპოვოთ სიტყვა „cat" ტექსტში — რეგისტრის გაუთვალისწინებლად (i flag).

PHP
$text = "The Cat sat on the mat";
preg_match("/cat/i", $text, $m);
// $m[0] === "Cat"  (იპოვა, რადგან i flag-მა რეგისტრი იგნორირა)
💡 რჩევა: regex ენებს შორის თითქმის ერთნაირია. რასაც აქ ისწავლი PHP-ზე, იგივე იმუშავებს JavaScript-ში, Python-ში, Java-ში, MySQL-ში.

why-created

რატომ შეიქმნა — მოკლე ისტორია

regex მათემატიკიდან მოვიდა. 1950-იან წლებში ლოგიკოსმა Stephen Kleene-მ აღწერა „რეგულარული სიმრავლეები" — ფორმალური ენების მათემატიკური აპარატი. აქედანაა ცნობილი „ვარსკვლავი" — Kleene star (*).

1968 წელს Ken Thompson-მა ეს თეორია პრაქტიკაში გადაიტანა Unix-ის ტექსტურ რედაქტორებსა და მოგვიანებით ცნობილ grep პროგრამაში. შემდეგ regex-ი გავრცელდა sed, awk და, რაც მთავარია, Perl-ში, რომელმაც თანამედროვე, მძლავრი სინტაქსი ჩამოაყალიბა (PCRE — Perl Compatible Regular Expressions).

დღეს თითქმის ყველა ენა PCRE-ს თავსებად regex-ს იყენებს — PHP-ს preg_* ფუნქციებიც სწორედ ამ „P"-ს (Perl) ნიშნავს.

მნიშვნელობები

მნიშვნელობააღწერა
1951 Kleene — რეგულარული სიმრავლეების მათემატიკური თეორია.
1968 Ken Thompson — regex Unix-ში, მოგვიანებით grep.
1986 POSIX სტანდარტი regex-ისთვის.
1987 Perl — მძლავრი თანამედროვე სინტაქსი.
1997+ PCRE ბიბლიოთეკა — დღეს PHP, R, Nginx და სხვები იყენებენ.

problems-solved

რა პრობლემებს წყვეტს

regex-მდე ტექსტში „ფორმის" ძებნა ნიშნავდა ათობით ხაზიან კოდს: ციკლები, სიმბოლო-სიმბოლო შემოწმება, მდგომარეობების თვალყურის დევნება. regex-ი ამ ყველაფერს ერთ დეკლარაციულ სტრიქონად აქცევს — შენ აღწერ რას ეძებ, და არა როგორ ეძებ.

მაგალითები

იგივე ამოცანა regex-ით და უ regex-ოდ

შევამოწმოთ, სტრიქონი მთლიანად ციფრებისგან შედგება თუ არა.

PHP
// ❌ regex-ის გარეშე — ხელით:
function isAllDigits($s) {
    if ($s === "") return false;
    for ($i = 0; $i < strlen($s); $i++) {
        if ($s[$i] < "0" || $s[$i] > "9") return false;
    }
    return true;
}

// ✅ regex-ით — ერთი ხაზი:
function isAllDigits($s) {
    return preg_match("/^\d+$/", $s) === 1;
}
💡 რჩევა: regex-ის ძალა ლაკონურობაშია: რაც ხელით 10–20 ხაზია, ხშირად ერთ შაბლონად იწერება.

why-still-used

რატომ იყენებენ ათწლეულების მერეც

ბევრი ტექნოლოგია ქრება, regex კი 50+ წელია ცოცხალია. რატომ?

  • უნივერსალურია — ერთხელ ისწავლი და ყველგან მუშაობს (კოდი, ბაზა, ტერმინალი, ტექსტური რედაქტორი, CI/CD).
  • ლაკონურია — რთული ტექსტური ლოგიკა ერთ ხაზში.
  • სწრაფია — engine-ები კომპილებად, ოპტიმიზებულ ავტომატებად მუშაობენ.
  • ჩაშენებულია — სტანდარტული ნაწილია თითქმის ყველა ენისა და ხელსაწყოსი.
  • დეკლარაციულია — აღწერ შედეგს, და არა ალგორითმს.

🌍 რეალური გამოყენება

დღესაც regex-ს იყენებენ: ფორმების ვალიდაცია, ლოგების ანალიზი (Grafana, Splunk), მონაცემთა გაწმენდა (ETL), ძებნა/ჩანაცვლება IDE-ში (VS Code), URL routing (Laravel, Express), firewall-ისა და WAF-ის წესები.

how-engine-works

როგორ მუშაობს engine (გონებრივი მოდელი)

regex engine ტექსტს კითხულობს მარცხნიდან მარჯვნივ და ცდილობს შაბლონს „მიადო" ყოველ პოზიციაზე. თუ ერთ პოზიციაზე არ გამოვიდა, ერთით წინ ინაცვლებს და თავიდან ცდის. ამ პროცესს ხშირად backtracking-იც ახლავს — როცა engine უკან ბრუნდება ალტერნატივების გადასაამოწმებლად.

ამ მოდელის გაგება მთავარია: სწორედ აქედან მოდის ორი ცნება, რომელსაც ხშირად შეხვდები — greedy/lazy კვანტიფიკატორები და catastrophic backtracking (ნელი შაბლონები).

მაგალითები

engine ნაბიჯ-ნაბიჯ

შაბლონი /ab/ ტექსტზე "xaby":

ნაბიჯები
პოზ. 0: "x" ≠ "a"  → წარუმატებელი, ინაცვლებს
პოზ. 1: "a"="a", "b"="b" → ✅ დამთხვევა "ab" (ინდექსი 1–2)
💡 რჩევა: როცა შაბლონი „ნელია" ან უცნაურ შედეგს იძლევა, წარმოიდგინე engine როგორ დადის ტექსტში პოზიცია-პოზიცია — ხშირად პასუხი მაშინვე ჩანს.

2 🎯 რატომ ვიყენებთ RegExp

პრაქტიკული სარგებელი: ვალიდაცია, მონაცემთა ამოღება და გარდაქმნა, ლოგების ანალიზი, ძებნა, ETL, CRM/ERP და API ინტეგრაციები.

benefit-validation

შეტანილი მონაცემის ვალიდაცია

ყველაზე გავრცელებული გამოყენება — შევამოწმოთ, მომხმარებლის შეტანილი მონაცემი სწორ ფორმატშია თუ არა: ელფოსტა, ტელეფონი, პაროლი, საიდენტიფიკაციო ნომერი. regex ერთ ხაზში პასუხობს კითხვას „ეს ტექსტი ჩემს წესს ემორჩილება?".

მაგალითები

მარტივი ვალიდაცია
PHP
// მხოლოდ ციფრები, 4 ცალი (მაგ. SMS კოდი):
preg_match("/^\d{4}$/", $code);

// მხოლოდ ლათინური ასოები და ციფრები (username):
preg_match("/^[A-Za-z0-9]+$/", $username);

benefit-extraction

მონაცემთა ამოღება (extraction)

ტექსტიდან გვინდა ამოვიღოთ კონკრეტული ნაწილები: ფასები, თარიღები, ჰეშთეგები, URL-ები, ID-ები. დაჯგუფებით ((...)) regex-ი არა მხოლოდ პოულობს, არამედ ცალკე გვიბრუნებს საჭირო ნაწილებს.

მაგალითები

ჰეშთეგების და ფასების ამოღება
PHP
$text = "ფასი 19.99 ლარი, ფასდაკლება #sale #ახალი";

preg_match_all("/#(\w+)/u", $text, $tags);
// $tags[1] === ["sale", "ახალი"]

preg_match("/(\d+\.\d{2})/", $text, $price);
// $price[1] === "19.99"

benefit-transformation

მონაცემთა გარდაქმნა (transformation)

ჩანაცვლება (replace) საშუალებას გვაძლევს ტექსტი ერთი ფორმატიდან მეორეში გადავიყვანოთ: თარიღის ფორმატი, ნომრის ნორმალიზაცია, ტექსტის გასუფთავება ზედმეტი ჰარეებისგან. backreference-ით ($1, $2) დაჯგუფებულ ნაწილებს ადგილებს ვუცვლით.

მაგალითები

თარიღის ფორმატის შეცვლა
PHP
// YYYY-MM-DD  →  DD.MM.YYYY
$out = preg_replace(
    "/(\d{4})-(\d{2})-(\d{2})/",
    "$3.$2.$1",
    "2026-06-10"
);
// $out === "10.06.2026"

benefit-logs

ლოგების ანალიზი

სერვერის, აპლიკაციის ან firewall-ის ლოგები — ეს უზარმაზარი ტექსტური ფაილებია. regex-ით ვფილტრავთ მხოლოდ შეცდომებს, ვითვლით სტატუს-კოდებს, ვამოიღებთ IP-ებსა და დროის ნიშნულებს. grep, awk, Splunk, Grafana Loki — ყველა regex-ს ეყრდნობა.

მაგალითები

შეცდომების და IP-ების ამოღება ლოგიდან
PHP
$line = '192.168.1.10 - - [10/Jun/2026] "GET /api" 500';

// IP მისამართი:
preg_match("/^(\d{1,3}(?:\.\d{1,3}){3})/", $line, $m);
// $m[1] === "192.168.1.10"

// მხოლოდ 5xx შეცდომები:
preg_match("/\" (5\d{2})$/", $line, $code);

benefit-filtering

ძებნა და ფილტრაცია

დიდ სიაში ან მასივში regex-ით ვტოვებთ მხოლოდ იმ ელემენტებს, რომლებიც შაბლონს ერგებიან. PHP-ში ამისთვის არსებობს preg_grep() — მთელ მასივს ერთ ხაზში ფილტრავს.

მაგალითები

მასივის ფილტრი
PHP
$files = ["report.pdf", "photo.jpg", "data.csv", "notes.txt"];

// მხოლოდ pdf და csv:
$docs = preg_grep("/\.(pdf|csv)$/i", $files);
// ["report.pdf", "data.csv"]

benefit-textprocessing

ტექსტის დამუშავება და გასუფთავება

ზედმეტი ჰარეები, ცარიელი ხაზები, HTML ტეგები, არასასურველი სიმბოლოები — regex-ით ტექსტს ვასუფთავებთ და ვანორმალებთ. ეს ETL-ისა და მონაცემთა მიგრაციის ყოველდღიური ამოცანაა.

მაგალითები

მრავალი ჰარის ერთ ჰარედ გადაქცევა
PHP
$dirty = "ერთი    ორი\tსამი\n\nოთხი";
$clean = preg_replace("/\s+/u", " ", trim($dirty));
// "ერთი ორი სამი ოთხი"

benefit-integrations

Config, ETL, CRM/ERP და API ინტეგრაციები

regex „წებოა" სისტემებს შორის:

  • კონფიგურაციის სისტემები.env, .ini, routing-ის წესების დაშლა.
  • ETL პროცესები — წყაროდან წამოღებული „ჭუჭყიანი" მონაცემის ნორმალიზაცია ბაზაში ჩაწერამდე.
  • CRM/ERP ინტეგრაციები — სხვადასხვა სისტემიდან მოსული ტელეფონების, საიდენტიფიკაციო კოდების, ინვოისის ნომრების ერთ ფორმატში მოყვანა.
  • API ინტეგრაციები — პასუხებიდან ID-ების, token-ების, error-კოდების ამოღება; endpoint-ების ვალიდაცია.

🌍 რეალური გამოყენება

მაგალითად, ERP-ში ორი სხვადასხვა მომწოდებლის ფაილში ტელეფონი ჩაწერილია როგორც +995 555 12 34 56 და 995555123456. regex-ით ორივეს ვაქცევთ ერთ ფორმატად, რომ ბაზაში დუბლები არ გაჩნდეს.

3 ✅ როდის გამოვიყენოთ

კონკრეტული, ხშირი სცენარები მზა შაბლონებით: ელფოსტა, ტელეფონი, პაროლი, URL, საფოსტო ინდექსი, ბარათის ფორმატი, ლოგები, საკვანძო სიტყვები, მონაცემთა გაწმენდა.

when-email

ელფოსტის ვალიდაცია

ელფოსტის შესამოწმებლად პრაქტიკული (და არა „იდეალურად სრული") შაბლონი საკმარისია. სრულყოფილი RFC-შაბლონი ასობით სიმბოლოიანია და კითხვადობას კლავს.

სინტაქსი

Syntax
/^[\w.+-]+@[\w-]+\.[\w.-]+$/

მაგალითები

ემთხვევა / არ ემთხვევა
ტესტები
✅ "ana@example.com"     — სტანდარტული
✅ "j.doe+news@mail.co"  — წერტილი/პლუსი დასაშვებია
❌ "ana@@example.com"    — ორი @
❌ "ana@example"         — დომენს წერტილი აკლია
❌ "@example.com"        — local ნაწილი ცარიელია
PHP-ში გამოყენება
PHP
if (preg_match("/^[\w.+-]+@[\w-]+\.[\w.-]+$/", $email)) {
    // ფორმატი სწორია
}

// 💡 production-ში სჯობს ჩაშენებული ფილტრი:
filter_var($email, FILTER_VALIDATE_EMAIL);
💡 რჩევა: ელფოსტისთვის რეალურ პროექტში გამოიყენე filter_var(..., FILTER_VALIDATE_EMAIL) — regex დაიტოვე იქ, სადაც ჩაშენებული ფილტრი არ არსებობს.

✗ ხშირი შეცდომები

  • Anchor-ების (^ და $) გამოტოვება — მაშინ "ana@x.com#hack" გაივლის ვალიდაციას.

when-phone

ტელეფონის ნომრის ვალიდაცია

ქართული მობილური ნომერი 9 ციფრია და იწყება 5-ით; შესაძლოა წინ ჰქონდეს საერთაშორისო პრეფიქსი +995. ვალიდაციამდე ხშირად ჯობია ნომრის ნორმალიზაცია — ჰარეების და ტირეების მოშორება.

სინტაქსი

Syntax
/^(\+995)?5\d{8}$/

მაგალითები

ემთხვევა / არ ემთხვევა
ტესტები
✅ "555123456"      — 9 ციფრი, იწყება 5-ით
✅ "+995555123456"  — +995 პრეფიქსით
❌ "555123"         — მოკლეა
❌ "777123456"      — არ იწყება 5-ით
❌ "555 12 34 56"   — ჰარეები (ჯერ ნორმალიზაცია სჭირდება)
ჯერ ნორმალიზაცია, მერე შემოწმება
PHP
$raw   = "+995 555 12 34 56";
$clean = preg_replace("/[\s\-()]/", "", $raw);  // "+995555123456"
$ok    = preg_match("/^(\+995)?5\d{8}$/", $clean);

when-password

პაროლის წესები

ძლიერი პაროლის წესი: მინიმუმ 8 სიმბოლო, სულ მცირე ერთი დიდი ასო, ერთი პატარა და ერთი ციფრი. აქ lookahead ((?=...)) გვეხმარება — თითო პირობას ცალკე ვამოწმებთ ისე, რომ engine კურსორი არ გადაიწიოს.

სინტაქსი

Syntax
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/

მაგალითები

ემთხვევა / არ ემთხვევა
ტესტები
✅ "Tbilisi2026"   — დიდი, პატარა, ციფრი, ≥8
❌ "tbilisi2026"   — დიდი ასო აკლია
❌ "Tbilisi"       — ციფრი აკლია
❌ "Tb26"          — მოკლეა (8-ზე ნაკლები)
💡 რჩევა: თითო (?=...) ცალკე პირობაა — ამიტომ მათი თანმიმდევრობა მნიშვნელობას არ ცვლის და ადვილად დაამატებ მეოთხეს (მაგ. სპეცსიმბოლო).

when-url

URL-ის ვალიდაცია

URL-ის შესამოწმებლად ვადასტურებთ სქემას (http/https), დომენსა და არასავალდებულო ბილიკს. https?s არასავალდებულოა.

სინტაქსი

Syntax
#^https?://[\w.-]+(\.[a-z]{2,})(/\S*)?$#i

მაგალითები

ემთხვევა / არ ემთხვევა
ტესტები
✅ "https://edu.mfes.ge"
✅ "http://site.com/page?x=1"
❌ "ftp://site.com"     — სქემა http(s) არაა
❌ "site.com"           — სქემა აკლია
სხვა delimiter — #

URL-ში ბევრი / არის; თუ delimiter-ად # ავიღებთ, /-ის escape აღარ გვჭირდება.

PHP
preg_match("#^https?://[\w.-]+\.[a-z]{2,}#i", $url);

when-postal

საფოსტო ინდექსი

საფოსტო ინდექსის ფორმატი ქვეყნის მიხედვით განსხვავდება — სწორედ ამიტომ regex იდეალურია: თითო ქვეყნისთვის ცალკე მოკლე შაბლონი.

მაგალითები

სხვადასხვა ქვეყნის ფორმატი
შაბლონები
// საქართველო — 4 ციფრი:
/^\d{4}$/         // "0102", "6000"

// აშშ — 5 ციფრი (+ არასავალდებულო -4):
/^\d{5}(-\d{4})?$/   // "10001", "10001-1234"

// დიდი ბრიტანეთი (გამარტივებული):
/^[A-Z]{1,2}\d[A-Z\d]? ?\d[A-Z]{2}$/i   // "SW1A 1AA"

when-card

საბანკო ბარათის ფორმატის შემოწმება

regex ამოწმებს მხოლოდ ფორმატს — 16 ციფრი, შესაძლოა ჰარეებით/ტირეებით დაყოფილი. ნამდვილ ვალიდურობას (Luhn-ის ალგორითმი) regex ვერ ამოწმებს — ეს უკვე ბიზნეს-ლოგიკაა.

სინტაქსი

Syntax
/^\d{4}[ -]?\d{4}[ -]?\d{4}[ -]?\d{4}$/

მაგალითები

ემთხვევა / არ ემთხვევა
ტესტები
✅ "4111111111111111"
✅ "4111 1111 1111 1111"
✅ "4111-1111-1111-1111"
❌ "4111 1111 1111"        — 12 ციფრი
❌ "4111abcd11111111"      — ასოები
💡 რჩევა: ფორმატი ≠ ვალიდურობა. ნამდვილ ბარათს ამოწმებს Luhn-ის ალგორითმი — ეს regex-ის საქმე არაა.

when-logs

აპლიკაციის ლოგების დამუშავება

ლოგის თითო ხაზი სტრუქტურირებული ტექსტია: დრო, დონე (INFO/ERROR), შეტყობინება. named groups-ით ცალკე ამოვიღებთ თითო ველს — შედეგი იკითხება როგორც ასოციაციური მასივი.

მაგალითები

ლოგის ხაზის დაშლა named groups-ით
PHP
$line = "[2026-06-10 14:42:01] ERROR: DB timeout";

preg_match(
    "/^\[(?<date>[\d\- :]+)\] (?<level>\w+): (?<msg>.+)$/",
    $line, $m
);
// $m["date"]  === "2026-06-10 14:42:01"
// $m["level"] === "ERROR"
// $m["msg"]   === "DB timeout"

when-keywords

საკვანძო სიტყვების ამოცნობა

ტექსტში გვინდა ვიპოვოთ რამდენიმე საკვანძო სიტყვა ერთდროულად — alternation (|) და word boundary (\b) ამისთვისაა. \b უზრუნველყოფს, რომ „cat" არ დაემთხვეს სიტყვაში „category".

მაგალითები

სიტყვა მთლიანად, არა ნაწილი
PHP
$text = "urgent ticket about category";

// ❌ ცუდი — დაემთხვევა "category"-შიც:
preg_match_all("/cat|urgent/i", $text, $m);

// ✅ კარგი — მხოლოდ ცალკე სიტყვები:
preg_match_all("/\b(cat|urgent)\b/i", $text, $m);
// $m[0] === ["urgent"]

when-clean-import

იმპორტირებული მონაცემის გაწმენდა

Excel/CSV-დან მოსული მონაცემი ხშირად „ჭუჭყიანია": წინ/უკან ჰარეები, ფარული სიმბოლოები, არათანმიმდევრული გამყოფები. regex-ით ვასუფთავებთ ბაზაში ჩაწერამდე.

მაგალითები

ფასის სვეტის ნორმალიზაცია
PHP
$cells = ["1 200,50 GEL", "  890.00", "1 500"];

foreach ($cells as $c) {
    // ვტოვებთ მხოლოდ ციფრებსა და წერტილს:
    $n = preg_replace("/[^\d.]/u", "", str_replace(",", ".", $c));
}

4 ⛔ როდის არ გამოვიყენოთ

regex ყველაფრის წამალი არ არის. აქ — სიტუაციები, სადაც regex ცუდი არჩევანია და უკეთესი ალტერნატივა არსებობს.

when-not-overcomplex

ზედმეტად რთული გამოსახულებები

თუ შაბლონი ისეთი გრძელი და გადახლართულია, რომ თვითონ ვერ კითხულობ — ეს უკვე საფრთხის ნიშანია. „write-only" regex (დაწერე და ვერავინ წაიკითხავს) მომავალში შეცდომების წყაროა.

მაგალითები

ცუდი vs კარგი მიდგომა
PHP
// ❌ ერთი გიგანტური „ყველაფრის" შაბლონი:
/^(?=.{8,72}$)(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*]).*$/

// ✅ რამდენიმე მცირე, გასაგები შემოწმება კოდში:
$okLen   = strlen($p) >= 8;
$okUpper = preg_match("/[A-Z]/", $p);
$okDigit = preg_match("/\d/", $p);
// უფრო ადვილი წასაკითხი და სატესტო
💡 რჩევა: თუ შაბლონს კომენტარის გარეშე ვერ ხსნი — დაშალე პატარა ნაწილებად ან გამოიყენე x (extended) flag კომენტარებით.

when-not-business

ბიზნეს-ლოგიკა regex-ით

regex ამოწმებს ფორმას, და არა მნიშვნელობას. „თარიღი არსებობს თუ არა" (29 თებერვალი არა-ნაკიან წელს), „ბარათი ვალიდურია თუ არა" (Luhn), „ასაკი 18-ზე მეტია თუ არა" — ეს ლოგიკაა, regex-ის საქმე არაა.

მაგალითები

regex ვერ ხედავს მნიშვნელობას
PHP
// regex იტყვის: "2026-02-31" ფორმატით სწორია ✅
preg_match("/^\d{4}-\d{2}-\d{2}$/", "2026-02-31"); // 1

// მაგრამ 31 თებერვალი არ არსებობს — ამას მხოლოდ
// ლოგიკა იჭერს:
$d = DateTime::createFromFormat("Y-m-d", "2026-02-31");
$valid = $d && $d->format("Y-m-d") === "2026-02-31"; // false
💡 რჩევა: წესი: regex-ით — ფორმატის გადამოწმება; კოდით/ბიბლიოთეკით — მნიშვნელობის ვალიდაცია.

when-not-parser

HTML / JSON / XML — გამოიყენე parser

კლასიკური შეცდომა — HTML-ის ან JSON-ის regex-ით „დაშლა". ეს ფორმატები იერარქიულია (ჩადგმული ელემენტები), regex კი იერარქიას ვერ აღწერს. ასეთ მონაცემზე გამოიყენე სპეციალური parser.

მაგალითები

სწორი ხელსაწყო ფორმატისთვის
PHP
// ❌ HTML-ის regex-ით დაშლა — მყიფე და არასწორი:
preg_match("/<a href=\"(.*?)\">/", $html);

// ✅ DOM parser:
$dom = new DOMDocument();
@$dom->loadHTML($html);
foreach ($dom->getElementsByTagName("a") as $a) {
    $href = $a->getAttribute("href");
}

// ✅ JSON:  json_decode($str, true);
💡 რჩევა: HTML → DOMDocument; JSON → json_decode; CSV → fgetcsv; XML → SimpleXML. regex დაიტოვე მცირე, ბრტყელ ფრაგმენტებზე.

when-not-readability

კითხვადობა და მხარდაჭერა

კოდს ერთხელ წერ, მაგრამ მრავალჯერ კითხულობ. თუ მარტივი str_contains(), str_starts_with() ან explode() საკმარისია — regex ზედმეტი სირთულეა. გამოიყენე regex მაშინ, როცა ის ამარტივებს, და არა ართულებს.

მაგალითები

მარტივი ამოცანა — მარტივი ხელსაწყო
PHP
// ❌ regex ზედმეტია:
preg_match("/^https:/", $url);
preg_match("/\.pdf$/", $name);
preg_split("/,/", $csv);

// ✅ უფრო ნათელი და სწრაფი:
str_starts_with($url, "https:");
str_ends_with($name, ".pdf");
explode(",", $csv);

5 🧩 ბირთვული ცნებები

regex-ის სამშენებლო ბლოკები. თითო ცნება ახსნილია სქემით: თეორია → გამოსახულება → ✅ დამთხვევები → ❌ არა-დამთხვევები → ახსნა.

literals

ლიტერალები (literals)

ლიტერალი არის ჩვეულებრივი სიმბოლო, რომელიც თავის თავს ეძებს. შაბლონი cat ეძებს ზუსტად ასოების მიმდევრობას c-a-t. ეს regex-ის ყველაზე მარტივი ფორმაა — ჩვეულებრივი ტექსტური ძებნა.

სიმბოლოდ ითვლება ყველაფერი, გარდა სპეციალური („ფუნქციონალური") სიმბოლოებისა: . ^ $ * + ? ( ) [ ] { } | \ /.

სინტაქსი

Syntax
/cat/

მაგალითები

ემთხვევა / არ ემთხვევა
ტესტები
შაბლონი: /cat/

✅ "cat"          — ზუსტი დამთხვევა
✅ "concatenate"  — შეიცავs "cat"-ს (ნაწილში)
❌ "Cat"          — დიდი C (i flag-ის გარეშე)
❌ "dog"          — საერთო არაფერი
💡 რჩევა: ლიტერალი ტექსტში ნებისმიერ ადგილას იძებნება. თუ გინდა მხოლოდ ცალკე სიტყვა — გამოიყენე \b (word boundary).

character-classes

სიმბოლოთა კლასები [...]

კვადრატული ფრჩხილები [...] ნიშნავს „ერთი სიმბოლო ამ ჩამონათვალიდან". [aeiou] ემთხვევა ერთ ხმოვანს. შიგნით - ქმნის დიაპაზონს ([a-z]), ხოლო თავში ^ ნიშნავს უარყოფას — „ყველაფერი, გარდა".

სინტაქსი

Syntax
[abc]    — a ან b ან c
[a-z]    — ნებისმიერი პატარა ლათინური ასო
[0-9]    — ნებისმიერი ციფრი
[^0-9]   — ნებისმიერი არა-ციფრი
[A-Za-z] — ნებისმიერი ლათინური ასო

მაგალითები

ემთხვევა / არ ემთხვევა
ტესტები
შაბლონი: /^[A-Za-z0-9_]+$/  (username)

✅ "ana_2026"   — ასოები, ციფრები, ქვედა ტირე
✅ "User1"
❌ "ana-2026"   — ტირე კლასში არ შედის
❌ "ანა"        — ქართული ასოები კლასში არაა
უარყოფითი კლასი
მაგალითი
შაბლონი: /[^aeiou]/  — ნებისმიერი არა-ხმოვანი

"sky" → დაემთხვევა "s", "k", "y" (ყველა თანხმოვანი)
💡 რჩევა: კლასის შიგნით უმეტესი სპეცსიმბოლო კარგავს ძალას — [.] ნიშნავს ლიტერალ წერტილს, escape არ სჭირდება.

predefined-classes

მზა კლასები \d \w \s

ხშირად საჭირო კლასებს მოკლე ჩანაწერი აქვთ. დიდი ასო ყოველთვის უარყოფაა პატარასი (\d — ციფრი, \D — არა-ციფრი).

მნიშვნელობები

მნიშვნელობააღწერა
. ნებისმიერი სიმბოლო (ახალი ხაზის გარდა).
\d ციფრი — იგივეა, რაც [0-9].
\D არა-ციფრი — [^0-9].
\w სიტყვის სიმბოლო — [A-Za-z0-9_].
\W არა-სიტყვის სიმბოლო (გამყოფი).
\s თეთრი ადგილი — ჰარე, ტაბი, ახალი ხაზი.
\S არა-თეთრი ადგილი (ხილული სიმბოლო).

მაგალითები

წყაროდან მიგრირებული მაგალითი
PHP
$content = "http://www.php.net/index.html";

// ყველა ხილული ბლოკი:
preg_match_all("/\S+/", $content, $m);
// $m[0] === ["http://www.php.net/index.html"]

// ჰარეებით დაშლა:
preg_match_all("/\w+/", $content, $m);
// $m[0] === ["http","www","php","net","index","html"]
💡 რჩევა: ქართულ ტექსტზე \w ნაგულისხმევად მხოლოდ ლათინურს ჭრის — Unicode-ისთვის დაამატე u flag და გამოიყენე \p{L} (ნებისმიერი ასო).

quantifiers

კვანტიფიკატორები * + ? {n,m}

კვანტიფიკატორი ამბობს, რამდენჯერ უნდა გამეორდეს წინა ელემენტი. ეს regex-ის ერთ-ერთი ყველაზე მძლავრი ნაწილია.

მნიშვნელობები

მნიშვნელობააღწერა
* 0 ან მეტჯერ (შესაძლოა საერთოდ არ იყოს).
+ 1 ან მეტჯერ (მინიმუმ ერთხელ).
? 0 ან 1-ჯერ (არასავალდებულო).
{3} ზუსტად 3-ჯერ.
{2,5} 2-დან 5-მდე.
{2,} 2 ან მეტჯერ.

მაგალითები

ემთხვევა / არ ემთხვევა
ტესტები
შაბლონი: /^\d{3}-\d{2,4}$/

✅ "123-45"     — 3 ციფრი, ტირე, 2 ციფრი
✅ "123-4567"   — 4 ციფრი ბოლოს
❌ "12-3456"    — წინ 2 ციფრი (საჭიროა 3)
❌ "123-45678"  — ბოლოს 5 ციფრი (max 4)
* და + სხვაობა (მიგრირებული)
PHP
$content = "http://www.php.net";

// + : მინიმუმ ერთი — სუფთა შედეგი:
preg_match_all("/[a-z]+/", $content, $m);
// ["http","www","php","net"]

// * : 0-იც ვარგა — ცარიელ დამთხვევებსაც აბრუნებს
//     ყოველ გამყოფ სიმბოლოზე.
💡 რჩევა: + ყველაზე ხშირად გამოსადეგია. *-ს ფრთხილად მოეპყარი — ის ცარიელ დამთხვევებსაც უშვებს.

greedy-lazy

ხარბი და ზარმაცი (greedy / lazy)

ნაგულისხმევად კვანტიფიკატორები ხარბია (greedy) — იღებენ რაც შეიძლება მეტს. თუ მათ მერე დაამატებ ?-ს, ხდებიან ზარმაცი (lazy) — იღებენ რაც შეიძლება ნაკლებს. ეს განსხვავება გადამწყვეტია ტეგების/ბრჭყალების ამოღებისას.

სინტაქსი

Syntax
.*    — ხარბი (greedy): მაქსიმუმი
.*?   — ზარმაცი (lazy): მინიმუმი

მაგალითები

ერთი და იგივე ტექსტი, ორი შედეგი
PHP
$html = "<b>ერთი</b><b>ორი</b>";

// ხარბი — დაიჭერს ყველაფერს პირველ < და ბოლო > შორის:
preg_match("/<.*>/", $html, $m);
// $m[0] === "<b>ერთი</b><b>ორი</b>"

// ზარმაცი — უმოკლეს დამთხვევას იღებს:
preg_match("/<.*?>/", $html, $m);
// $m[0] === "<b>"
💡 რჩევა: როცა „ერთ ცალს" ეძებ ბრჭყალებში/ტეგებში, თითქმის ყოველთვის გინდა ზარმაცი .*?.

anchors

წამმაგრებლები ^ $ \b

Anchor-ი არ ემთხვევა სიმბოლოს — ის ემთხვევა პოზიციას. ^ — სტრიქონის დასაწყისი, $ — დასასრული, \b — სიტყვის საზღვარი. anchor-ები ვალიდაციის გული-გულია: ისინი უზრუნველყოფენ, რომ შაბლონი მთელ ტექსტს მოერგოს, და არა მის ნაწილს.

სინტაქსი

Syntax
^    — სტრიქონის დასაწყისი
$    — სტრიქონის დასასრული
\b   — სიტყვის საზღვარი (word/non-word გადასვლა)
\B   — არა-საზღვარი

მაგალითები

^ და $ — სრული დამთხვევა
ტესტები
შაბლონი: /^\d{4}$/  (ზუსტად 4 ციფრი)

✅ "1234"     — მთელი სტრიქონი 4 ციფრია
❌ "12345"    — 5 ციფრი ($-მა დაიჭირა)
❌ "x1234"    — წინ ასო (^-მა დაიჭირა)
❌ "1234 ok"  — ტექსტი ბოლოს
\b — ცალკე სიტყვა
PHP
$text = "category cat scatter";

preg_match_all("/\bcat\b/", $text, $m);
// $m[0] === ["cat"]  — მხოლოდ ცალკე "cat",
// "category"-სა და "scatter"-ში არ დაიჭირა
💡 რჩევა: ვალიდაციისას თითქმის ყოველთვის გჭირდება ^...$. მათ გარეშე regex „ნაწილობრივ" დამთხვევასაც წარმატებად ჩათვლის.

groups

დაჯგუფება (...)

მრგვალი ფრჩხილები (...) აჯგუფებენ რამდენიმე ელემენტს ერთ ერთეულად, რომ კვანტიფიკატორი ან | მთელ ჯგუფზე იმოქმედოს. (ab)+ ნიშნავს „ab"-ის გამეორებას, და არა მხოლოდ „b"-ის.

სინტაქსი

Syntax
/(ab)+/    — "ab", "abab", "ababab" ...
/(\d{1,3}\.){3}\d{1,3}/   — IP-ის სტრუქტურა

მაგალითები

დაჯგუფება vs მისი გარეშე
PHP
// ჯგუფის გარეშე — + მხოლოდ "b"-ზე მოქმედებს:
preg_match("/ab+/", "ababab", $m);  // $m[0] === "ab"

// ჯგუფით — + მთელ "ab"-ზე:
preg_match("/(ab)+/", "ababab", $m); // $m[0] === "ababab"

capturing-groups

დამჭერი ჯგუფები (capturing)

ყოველი (...) არა მხოლოდ აჯგუფებს, არამედ იმახსოვრებს დაჭერილ ტექსტს — შედეგში ცალკე ინდექსად აბრუნებს ($matches[1], $matches[2] ...). ეს extraction-ის ძირითადი ხელსაწყოა.

მაგალითები

თარიღის ნაწილების ამოღება
PHP
$date = "2026-06-10";
preg_match("/(\d{4})-(\d{2})-(\d{2})/", $date, $m);

// $m[0] === "2026-06-10"  (სრული დამთხვევა)
// $m[1] === "2026"        (პირველი ჯგუფი)
// $m[2] === "06"          (მეორე ჯგუფი)
// $m[3] === "10"          (მესამე ჯგუფი)
💡 რჩევა: $matches[0] ყოველთვის სრული დამთხვევაა; ჯგუფები 1-დან იწყება, მარცხნივ მდგომი ფრჩხილის მიხედვით.

non-capturing-groups

არა-დამჭერი ჯგუფები (?:...)

ზოგჯერ დაჯგუფება გვჭირდება, მაგრამ ჩაჭერა — არა. (?:...) აჯგუფებს ისე, რომ ინდექსს არ ხარჯავს. ეს აუმჯობესებს წაკითხვადობას და ოდნავ — წარმადობას.

მაგალითები

ინდექსების სუფთად შენახვა
PHP
$url = "https://site.com";

// (?:...) — სქემა გვჭირდება, მაგრამ ცალკე ამოღება — არა:
preg_match("#^(?:https?)://([\w.-]+)#", $url, $m);
// $m[1] === "site.com"  (დომენი — პირველივე ჯგუფია,
//                        სქემამ ინდექსი არ წაართვა)
💡 რჩევა: წესი: თუ ჯგუფის შიგთავსი არ გჭირდება შედეგში — დაამატე ?:. შედეგი უფრო სუფთა და ცხადი ხდება.

named-groups

სახელდებული ჯგუფები (?<name>...)

ნომრებით ($m[1], $m[2]) წვდომა ადვილად აირევა, განსაკუთრებით როცა ჯგუფებს ამატებ/აშორებ. სახელდებული ჯგუფი საშუალებას იძლევა, ცალკეულ ნაწილს გასაგები სახელით მიმართო.

სინტაქსი

Syntax
(?<name>...)  ან  (?P<name>...)
წვდომა:  $matches["name"]

მაგალითები

მიგრირებული და გაუმჯობესებული HTML ტეგის მაგალითი
PHP
$buf = "<div>Hello</div>";

preg_match(
    "/<(?<tag>[a-z][a-z0-9]*)\b[^>]*>(?<body>.*?)<\/(?P=tag)>/i",
    $buf, $m
);
// $m["tag"]  === "div"
// $m["body"] === "Hello"
// (?P=tag) — იგივე ტეგი უნდა დაიხუროს (backreference)
💡 რჩევა: named groups-ით კოდი თვით-დოკუმენტირებული ხდება — $m["date"] გაცილებით ცხადია, ვიდრე $m[1].

alternation

ალტერნაცია (ან) |

ვერტიკალური ხაზი | ნიშნავს „ან": cat|dog ემთხვევა „cat"-ს ან „dog"-ს. ხშირად ფრჩხილებში ვათავსებთ მოქმედების ფარგლის შესაზღუდად: (jpg|png|gif).

მაგალითები

ფაილის გაფართოების შემოწმება
ტესტები
შაბლონი: /\.(jpg|jpeg|png|gif)$/i

✅ "photo.JPG"   — i flag რეგისტრს არ ითვალისწინებს
✅ "logo.png"
❌ "doc.pdf"     — ჩამონათვალში არაა
❌ "image.jpg.exe" — ბოლო გაფართოება .exe-ა
მიგრირებული მაგალითი
PHP
$content = "http://www.php.net";
preg_match_all("/www|net|php/i", $content, $m);
// $m[0] === ["www", "php", "net"]
💡 რჩევა: ფრჩხილების გარეშე | ვრცელდება მთელ მხარეებზე: ^cat|dog$ ნიშნავს „იწყება cat-ით" ან „მთავრდება dog-ით" — ალბათ არა ის, რაც გინდოდა.

escaping

Escape — სპეცსიმბოლოს „განეიტრალება" \

თუ გინდა ლიტერალი წერტილი, ფრჩხილი ან ? ეძებო — და არა მათი სპეციალური მნიშვნელობა — წინ უნდა დაუსვა \ (backslash). \. ნიშნავს ნამდვილ წერტილს, ხოლო უბრალო . — „ნებისმიერ სიმბოლოს".

მნიშვნელობები

მნიშვნელობააღწერა
\. ლიტერალი წერტილი (და არა „ნებისმიერი სიმბოლო").
\? ლიტერალი კითხვის ნიშანი.
\/ ლიტერალი slash (როცა delimiter-იც / არის).
\( ლიტერალი ფრჩხილი.
\\ ლიტერალი backslash (ორი — \\).

მაგალითები

წერტილის ნამდვილი მნიშვნელობა
PHP
// . = ნებისმიერი სიმბოლო:
preg_match("/3.14/", "3X14");   // ✅ დაემთხვევა! (. = X)

// \. = ნამდვილი წერტილი:
preg_match("/3\.14/", "3X14");  // ❌ არ დაემთხვევა
preg_match("/3\.14/", "3.14");  // ✅ დაემთხვევა
💡 რჩევა: PHP-ში მზა, ცვლადიდან მომავალი ტექსტის უსაფრთხოდ ჩასასმელად გამოიყენე preg_quote($str, "/") — ის ავტომატურად დააescape-ებს ყველა სპეცსიმბოლოს.

lookahead

Lookahead (?=...) (?!...)

Lookahead ამოწმებს, რა მოდის წინ, მაგრამ ამ ნაწილს დამთხვევაში არ ითვლის (zero-width). (?=...) — დადებითი („უნდა მოჰყვებოდეს"), (?!...) — უარყოფითი („არ უნდა მოჰყვებოდეს").

სინტაქსი

Syntax
(?=...)   — დადებითი lookahead
(?!...)   — უარყოფითი lookahead

მაგალითები

დადებითი — პაროლის წესი
PHP
// "უნდა შეიცავდეს ციფრს" — კურსორის გადაწევის გარეშე:
preg_match("/^(?=.*\d).{6,}$/", "abcdef"); // ❌ ციფრი არაა
preg_match("/^(?=.*\d).{6,}$/", "abc123"); // ✅
უარყოფითი — „გარდა"
PHP
// ფაილი, რომელიც .bak-ით არ მთავრდება:
/^.+(?<!\.bak)$/   // (აქ lookbehind-ია, იხ. შემდეგი თემა)

// სიტყვა "foo", რომელსაც არ მოჰყვება "bar":
preg_match("/foo(?!bar)/", "foobaz"); // ✅
preg_match("/foo(?!bar)/", "foobar"); // ❌
💡 რჩევა: lookahead „zero-width"-ია: ის ამოწმებს პირობას, მაგრამ სიმბოლოებს არ „ჭამს" — ამიტომ რამდენიმე lookahead ერთ ადგილას ერთდროულად მუშაობს (იხ. პაროლის წესი).

lookbehind

Lookbehind (?<=...) (?<!...)

Lookbehind ამოწმებს, რა იყო უკან (მარცხნივ), დამთხვევაში მისი ჩათვლის გარეშე. (?<=...) — დადებითი, (? — უარყოფითი. PCRE-ში lookbehind ფიქსირებული სიგრძის უნდა იყოს.

სინტაქსი

Syntax
(?<=...)   — დადებითი lookbehind
(?<!...)   — უარყოფითი lookbehind

მაგალითები

ფასის ამოღება ნიშნის გარეშე
PHP
$text = "ფასი: $250 და $1000";

// მხოლოდ ციფრები, რომლებსაც $ უსწრებს
// (თვითონ $ შედეგში არ შედის):
preg_match_all("/(?<=\\$)\d+/", $text, $m);
// $m[0] === ["250", "1000"]
💡 რჩევა: lookbehind იდეალურია, როცა „კონტექსტი" გჭირდება, მაგრამ თვითონ კონტექსტი შედეგში არ გინდა (ვალუტის ნიშანი, პრეფიქსი, ტეგი).

backreferences

უკუმიმართვები (backreferences) \1

Backreference საშუალებას იძლევა, შაბლონის შიგნით მიმართო უკვე დაჭერილ ჯგუფს: \1 (ან named — \k<name>). გამოსადეგია გამეორებების და დაბალანსებული ბრჭყალების/ტეგების დასაჭერად.

მაგალითები

გამეორებული სიტყვის პოვნა
PHP
$text = "ეს არის is is შეცდომა the the";

// (\w+) დაიჭერს სიტყვას, \1 ითხოვს იმავეს გამეორებას:
preg_match_all("/\b(\w+)\s+\1\b/", $text, $m);
// $m[1] === ["is", "the"]  — გაორმაგებული სიტყვები
დაბალანსებული ბრჭყალები
PHP
// ერთნაირი გამხსნელი/დამხურავი ბრჭყალი:
preg_match("/([\'\"]).*?\1/", $s, $m);
// დაიჭერს '...' ან "..." (მაგრამ არა "..')
💡 რჩევა: ჩანაცვლებაში ჯგუფს მიმართავ $1-ით, თვითონ შაბლონში კი — \1-ით.

delimiters-modifiers

დელიმიტერები და flags (i, u, m, s, x)

PHP-ში შაბლონი იწერება დელიმიტერებს შორის — ჩვეულებრივ /.../, მაგრამ შეიძლება #...# ან ~...~-იც. დახურვის მერე მოდის flags, რომლებიც ცვლიან ქცევას.

მნიშვნელობები

მნიშვნელობააღწერა
i რეგისტრის იგნორი (A = a).
u UTF-8 / Unicode რეჟიმი — ქართულისთვის აუცილებელია.
m multiline — ^/$ თითო ხაზზე მუშაობს.
s dotall — . ახალ ხაზსაც იჭერს.
x extended — ჰარეები/კომენტარები იგნორირდება (კითხვადობა).

მაგალითები

flags მოქმედებაში
PHP
// u — ქართული ასოები სწორად:
preg_match_all("/\w+/u", "გამარჯობა მსოფლიო", $m);

// x — კომენტირებადი, წაკითხვადი შაბლონი:
$re = "/
    \d{4}   # წელი
    -\d{2}  # თვე
    -\d{2}  # დღე
/x";
💡 რჩევა: ქართულ ტექსტთან ყოველთვის დაამატე u flag — სხვანაირად Unicode სიმბოლოები არასწორად დაიჭრება.

6 🐘 PHP ფუნქციები (preg_*)

PHP-ს PCRE ფუნქციები: ძებნა, ყველა დამთხვევა, ჩანაცვლება (callback-ითაც), დაშლა, მასივის ფილტრი და უსაფრთხო escape. გადამუშავებულია legacy regexp_files.php-დან.

preg-match

preg_match() — პირველი დამთხვევა

ეძებს შაბლონის პირველ დამთხვევას. აბრუნებს 1 (იპოვა), 0 (ვერ იპოვა) ან false (შეცდომა). დაჭერილი ნაწილები მესამე არგუმენტში — $matches მასივში თავსდება.

სინტაქსი

Syntax
int preg_match(string $pattern, string $subject, array &$matches = null)

მაგალითები

ჰოსტის ამოღება URL-დან (მიგრირებული)
PHP
$content = "http://www.php.net/index.html";
preg_match("#^(https?://)?([^/]+)#i", $content, $m);
echo $m[2];   // "www.php.net"
💡 რჩევა: preg_match ჩერდება პირველ დამთხვევაზე — სწრაფია ვალიდაციისთვის („არსებობს თუ არა").

preg-match-all

preg_match_all() — ყველა დამთხვევა

პოულობს ყველა დამთხვევას და მათ მასივში აგროვებს. extraction-ის მთავარი ფუნქცია — ფასების, ტეგების, ID-ების ჩამონათვალის ამოსაღებად.

სინტაქსი

Syntax
int preg_match_all(string $pattern, string $subject, array &$matches, int $flags = PREG_PATTERN_ORDER)

მაგალითები

ტეგებს შორის ტექსტის ამოღება (მიგრირებული)
PHP
$html = "<b>example: </b><div>this is a test</div>";
preg_match_all("|<[^>]+>(.*?)</[^>]+>|", $html, $out);

// $out[0] — სრული დამთხვევები (ტეგებითურთ)
// $out[1] — მხოლოდ შიგთავსი: ["example: ", "this is a test"]
💡 რჩევა: ორიგინალში გამოყენებული იყო U flag (ხარბის შებრუნება). თანამედროვე, ცხადი მიდგომაა .*? (ზარმაცი) — შედეგი იგივეა, კოდი — გასაგები.

preg-replace

preg_replace() — ჩანაცვლება

ცვლის ყველა დამთხვევას ახალი ტექსტით. ჩანაცვლების ტექსტში დაჭერილ ჯგუფებს მიმართავ $1, $2 ... (ან ${1}, როცა წინ ციფრია).

სინტაქსი

Syntax
mixed preg_replace(mixed $pattern, mixed $replacement, mixed $subject, int $limit = -1)

მაგალითები

თარიღის გადაწყობა (მიგრირებული, გაუმჯობესებული)
PHP
$string  = "April 15, 2003";
$pattern = "/(\w+) (\d+), (\d+)/";
echo preg_replace($pattern, "$3-$1-$2", $string);
// "2003-April-15"

✗ ხშირი შეცდომები

  • $10 შეიძლება ჯგუფ 10-ად აღიქვას; თუ მე-10 ჯგუფი არ გაქვს და გინდა „ჯგუფი 1 + ტექსტი 0", დაწერე ${1}0.

preg-replace-callback

preg_replace_callback() — დინამიური ჩანაცვლება

როცა ჩანაცვლება გამოთვლას საჭიროებს (და არა მხოლოდ გადაწყობას), თითო დამთხვევაზე გამოიძახება ფუნქცია, რომელიც აბრუნებს ახალ ტექსტს. თანამედროვე PHP-ში მოსახერხებელია closure.

სინტაქსი

Syntax
mixed preg_replace_callback(mixed $pattern, callable $callback, mixed $subject, int $limit = -1)

მაგალითები

წლის გაზრდა +1-ით (მიგრირებული → closure)
PHP
$text = "fools day 04/01/2002, christmas 12/24/2001";

echo preg_replace_callback(
    "#(\d{2}/\d{2}/)(\d{4})#",
    function ($m) {
        return $m[1] . ($m[2] + 1);   // წელს +1
    },
    $text
);
// "fools day 04/01/2003, christmas 12/24/2002"
💡 რჩევა: callback იქ გამოიყენე, სადაც ჩანაცვლების შინაარსი დამთხვევის მნიშვნელობაზეა დამოკიდებული (გამოთვლა, ძებნა ცხრილში, ფორმატირება).

preg-split

preg_split() — დაშლა შაბლონით

ანაწევრებს სტრიქონს იქ, სადაც შაბლონი ემთხვევა. explode()-ისგან განსხვავებით, გამყოფი შეიძლება ცვალებადი იყოს — მაგ. ჰარეები ან მძიმეები ერთდროულად.

სინტაქსი

Syntax
array preg_split(string $pattern, string $subject, int $limit = -1, int $flags = 0)

მაგალითები

ცვალებად გამყოფზე დაშლა (მიგრირებული)
PHP
$keywords = preg_split("/[\s,]+/", "hypertext language, programming");
// ["hypertext", "language", "programming"]

// PREG_SPLIT_NO_EMPTY — ცარიელ ნაწილებს გამოტოვებს:
$parts = preg_split("/;/", "a;;b;", -1, PREG_SPLIT_NO_EMPTY);
// ["a", "b"]
💡 რჩევა: მარტივ, ფიქსირებულ გამყოფზე (ერთი მძიმე) explode() სწრაფია; preg_split() მაშინ, როცა გამყოფი ცვალებადია.

preg-grep

preg_grep() — მასივის ფილტრი

აბრუნებს მასივის მხოლოდ იმ ელემენტებს, რომლებიც შაბლონს ემთხვევიან. ფლაგით PREG_GREP_INVERT — პირიქით, შეუსაბამოებს.

სინტაქსი

Syntax
array preg_grep(string $pattern, array $input, int $flags = 0)

მაგალითები

რიცხვების გაფილტვრა (მიგრირებული)
PHP
$array = ["23.32", "22", "12", "23.43.43"];

// მხოლოდ წერტილის შემცველი:
print_r(preg_grep("/\./", $array));
// [0 => "23.32", 3 => "23.43.43"]

// invert — წერტილის გარეშე:
preg_grep("/\./", $array, PREG_GREP_INVERT);
// [1 => "22", 2 => "12"]
💡 რჩევა: preg_grep ინარჩუნებს ორიგინალ გასაღებებს — საჭიროებისას გამოიყენე array_values() გადასანომრად.

preg-quote

preg_quote() — უსაფრთხო escape

როცა შაბლონში ცვლადიდან მომავალ ტექსტს ჩასვამ (მაგ. მომხმარებლის ძებნის სიტყვა), მასში შესაძლოა სპეცსიმბოლოები იყოს. preg_quote() ყველა მათგანს დააescape-ებს — ეს ასევე უსაფრთხოების საკითხია (regex injection-ის თავიდან აცილება).

სინტაქსი

Syntax
string preg_quote(string $str, ?string $delimiter = null)

მაგალითები

მომხმარებლის შეტანის უსაფრთხო ძებნა
PHP
$search = "3.14 (pi)?";   // შეიცავს . ( ) ?
$safe   = preg_quote($search, "/");
// "3\.14 \(pi\)\?"

preg_match("/$safe/", $text);  // ეძებს ლიტერალ ტექსტს
💡 რჩევა: ყოველთვის გაატარე preg_quote-ში გარეთა (მომხმარებლის) ტექსტი, სანამ შაბლონში ჩასვამ.

7 🌍 რეალური მაგალითები

ცხოვრებისეული სცენარები: ფორმები, CRM, ERP, იმპორტი/ექსპორტი, მარკეტინგის ავტომატიზაცია, მონაცემთა გაწმენდა, უსაფრთხოება და რეგისტრაცია.

real-forms

ფორმების ვალიდაცია

ვებ-ფორმა მონაცემთა შესვლის მთავარი წერტილია. სანამ ბაზაში ჩაიწერება, თითო ველი ფორმატზე უნდა გადამოწმდეს — სერვერის მხარეს, აუცილებლად.

მაგალითები

სარეგისტრაციო ფორმის წესების ნაკრები
PHP
$rules = [
    "username" => "/^[a-z0-9_]{3,20}$/i",
    "email"    => "/^[\w.+-]+@[\w-]+\.[\w.-]+$/",
    "phone"    => "/^(\+995)?5\d{8}$/",
    "zip"      => "/^\d{4}$/",
];

foreach ($rules as $field => $re) {
    if (!preg_match($re, trim($_POST[$field] ?? ""))) {
        $errors[$field] = "არასწორი ფორმატი";
    }
}
💡 რჩევა: კლიენტის მხარეს ვალიდაცია მოხერხებულობისთვისაა; სერვერზე ვალიდაცია — უსაფრთხოებისთვის. ორივე გჭირდება.

real-crm

CRM — კონტაქტების ნორმალიზაცია

CRM-ში კონტაქტები სხვადასხვა წყაროდან მოდის და ფორმატები ერევა. დუბლების თავიდან ასაცილებლად ტელეფონებსა და სახელებს ერთ კანონიკურ ფორმაში ვაქცევთ.

მაგალითები

ტელეფონის კანონიკურ ფორმაში მოყვანა
PHP
function normalizePhone($raw) {
    $d = preg_replace("/\D+/", "", $raw);      // მხოლოდ ციფრები
    $d = preg_replace("/^995/", "", $d);        // ქვეყნის კოდი მოვაშოროთ
    return preg_match("/^5\d{8}$/", $d) ? "+995" . $d : null;
}

normalizePhone("+995 555 12-34-56"); // "+995555123456"
normalizePhone("(555) 123 456");      // "+995555123456"
💡 რჩევა: ჯერ ნორმალიზაცია, მერე შედარება/ვალიდაცია — ასე დუბლები აღარ გაჩნდება ბაზაში.

real-erp

ERP — დოკუმენტის ნომრების დამუშავება

ERP სისტემებში ინვოისებსა და დოკუმენტებს სტრუქტურირებული კოდები აქვს, მაგ. INV-2026-000123. regex-ით ვამოწმებთ ფორმატს და ცალკე ვამოიღებთ პრეფიქსს, წელსა და თანმიმდევრულ ნომერს.

მაგალითები

ინვოისის კოდის დაშლა
PHP
$code = "INV-2026-000123";
preg_match("/^(?<type>[A-Z]{2,4})-(?<year>\d{4})-(?<seq>\d{6})$/", $code, $m);

// $m["type"] === "INV"
// $m["year"] === "2026"
// $m["seq"]  === "000123"

real-import-export

იმპორტი/ექსპორტი — CSV ველების გაწმენდა

CSV-ის იმპორტისას ცალკეული ველი ხშირად საჭიროებს გასუფთავებას — ფასები, რაოდენობები, თარიღები. regex ამ ნორმალიზაციის გული-გულია.

მაგალითები

ფასისა და რაოდენობის ნორმალიზაცია
PHP
function toNumber($cell) {
    $s = str_replace(",", ".", trim($cell));
    $s = preg_replace("/[^\d.]/", "", $s);   // ვალუტა, ჰარეები წავშალოთ
    return $s === "" ? null : (float) $s;
}

toNumber("1 200,50 GEL"); // 1200.5
toNumber("  890.00 ");    // 890.0
💡 რჩევა: CSV-ის სტრუქტურა (ველებად დაშლა) fgetcsv()-ით აიღე; regex მხოლოდ ცალკეული ველის შიგთავსის გასაწმენდად.

real-marketing

მარკეტინგის ავტომატიზაცია

კამპანიების ანალიტიკაში regex ამოიცნობს UTM-პარამეტრებს, ჰეშთეგებსა და სეგმენტაციის საკვანძო სიტყვებს — შემოსულ ტექსტებსა და ბმულებში.

მაგალითები

UTM-წყაროს ამოღება ბმულიდან
PHP
$url = "https://shop.ge/p?utm_source=facebook&utm_campaign=summer";

preg_match("/[?&]utm_source=([^&]+)/", $url, $m);
// $m[1] === "facebook"

// ჰეშთეგების შეგროვება პოსტებიდან:
preg_match_all("/#(\w+)/u", $post, $tags);

real-data-cleansing

მონაცემთა გაწმენდა (data cleansing)

„ჭუჭყიანი" ტექსტი — ფარული სიმბოლოები, ორმაგი ჰარეები, HTML ნარჩენები — ანალიზამდე უნდა გაიწმინდოს. ეს ETL-ის სავალდებულო ეტაპია.

მაგალითები

ტექსტის სრული ნორმალიზაცია
PHP
function cleanText($s) {
    $s = preg_replace("/<[^>]+>/", " ", $s);  // HTML ტეგები
    $s = preg_replace("/\s+/u", " ", $s);      // ზედმეტი ჰარეები
    return trim($s);
}

cleanText("<p>გამარჯობა   მსოფლიო</p>"); // "გამარჯობა მსოფლიო"
💡 რჩევა: ტეგების მოსაცილებლად მცირე ფრაგმენტებზე regex მუშაობს; სრული HTML დოკუმენტისთვის — DOMDocument.

real-security

უსაფრთხოების ვალიდაცია

regex სასარგებლოა შემოსული მონაცემის გასაფილტრად, მაგრამ ფრთხილად: blacklist-ით (აკრძალულის ძებნა) თავდასხმის გვერდის ავლა ადვილია. გამოიყენე whitelist — დაუშვი მხოლოდ ცნობილი, უსაფრთხო ფორმატი.

მაგალითები

Whitelist მიდგომა (slug)
PHP
// ✅ whitelist — მხოლოდ ნებადართული სიმბოლოები:
if (!preg_match("/^[a-z0-9\-]+$/", $slug)) {
    die("დაუშვებელი slug");
}

// ⚠ უსაფრთხოდ ჩასმისთვის ცვლადი ჯერ preg_quote-ში:
$needle = preg_quote($userInput, "/");
💡 რჩევა: regex-ით ნებადართულის დადასტურება (whitelist) უფრო უსაფრთხოა, ვიდრე აკრძალულის ძებნა (blacklist).

✗ ხშირი შეცდომები

  • SQL injection-სა და XSS-ს regex-ით ნუ დაიცავ — გამოიყენე prepared statements და სათანადო escaping/encoding.

real-registration

მომხმარებლის რეგისტრაცია

რეგისტრაცია აერთიანებს ბევრ წესს ერთად: username, email, ძლიერი პაროლი. ქვემოთ — მთლიანი, კითხვადი ნაკრები.

მაგალითები

რეგისტრაციის სრული შემოწმება
PHP
$checks = [
    "username" => "/^[a-zA-Z0-9_]{3,20}$/",
    "password" => "/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/",
    "email"    => "/^[\w.+-]+@[\w-]+\.[\w.-]+$/",
];

$ok = true;
foreach ($checks as $field => $re) {
    if (!preg_match($re, $_POST[$field] ?? "")) $ok = false;
}

8 ⭐ საუკეთესო პრაქტიკა

როგორ დავწეროთ შაბლონები, რომლებიც იკითხება, ადვილად ნარჩუნდება, სწრაფად მუშაობს და ადვილად იტესტება.

bp-readability

კითხვადობა — x flag და კომენტარები

გრძელი შაბლონი ერთ ხაზად — მომავალი შეცდომების წყაროა. x (extended) flag საშუალებას იძლევა, შაბლონი რამდენიმე ხაზად დაშალო, დაამატო ჰარეები და კომენტარები.

მაგალითები

ერთი ხაზი vs კომენტირებული
PHP
// ❌ რთულად წასაკითხი:
$re = "/^(\+995)?5\d{8}$/";

// ✅ x flag — თვით-ახსნადი:
$re = "/
    ^(\+995)?   # არასავალდებულო ქვეყნის კოდი
    5           # ქართული მობილური იწყება 5-ით
    \d{8}$      # კიდევ 8 ციფრი
/x";
💡 რჩევა: x რეჟიმში ნამდვილი ჰარე უნდა დაწერო \ -ით ან [ ]-ით, თორემ იგნორირდება.

bp-naming-groups

ჯგუფებს დაარქვი სახელი

ნომრიანი ჯგუფები ($m[1], $m[2]) ადვილად აირევა, როცა შაბლონი იცვლება. სახელდებული ჯგუფები კოდს თვით-დოკუმენტირებულს ხდის.

მაგალითები

ნომრები vs სახელები
PHP
// ❌ რა არის $m[2]? უნდა დაითვალო ფრჩხილები:
preg_match("/(\d{4})-(\d{2})-(\d{2})/", $d, $m);
$month = $m[2];

// ✅ ცხადია:
preg_match("/(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})/", $d, $m);
$month = $m["m"];

bp-maintainability

მხარდაჭერა — ანთება, ხელახალი გამოყენება

შაბლონები ცალკე, დასახელებულ კონსტანტებში გაიტანე და დააკომენტარე რას აკეთებს. ერთი და იგივე regex არ გაიმეორო კოდის სხვადასხვა ადგილას.

მაგალითები

ცენტრალიზებული შაბლონები
PHP
final class Patterns {
    // ქართული მობილური (ნორმალიზებული)
    const PHONE = "/^(\+995)?5\d{8}$/";
    // პრაქტიკული ელფოსტა
    const EMAIL = "/^[\w.+-]+@[\w-]+\.[\w.-]+$/";
}

preg_match(Patterns::PHONE, $input);
💡 რჩევა: ერთ ადგილას შენახული შაბლონი — ერთ ადგილას იცვლება. დუბლირებული regex კი ერთ დღეს აუცილებლად აცდება ერთმანეთს.

bp-performance

წარმადობა

regex სწრაფია, თუ მას არ აიძულებ ზედმეტ backtracking-ს. რამდენიმე მარტივი წესი დიდ სხვაობას იძლევა.

✓ საუკეთესო პრაქტიკა

  • გამოიყენე anchor-ები (^) — engine ადრევე წყვეტს უიმედო ცდას.
  • უპირატესობა მიეცი კონკრეტულ კლასებს ([^"]) ბუნდოვან .*-ს ნაცვლად.
  • ჩადგმული კვანტიფიკატორები ((a+)+) თავიდან აიცილე — catastrophic backtracking-ის რისკი.
  • არა-დამჭერი ჯგუფი (?:...), როცა ჩაჭერა არ გჭირდება.
  • შესაძლებლობისას გამოიყენე ენის ჩაშენებული ფუნქცია (str_contains, filter_var).

bp-documenting

რთული შაბლონების დოკუმენტირება

ყოველ არა-ტრივიალურ შაბლონს თან უნდა ახლდეს: 1) მოკლე ახსნა რას ამოწმებს, 2) ერთი-ორი ✅ და ❌ მაგალითი კომენტარში. ეს მომავალ შენ (ან კოლეგას) ბევრ დროს უზოგავს.

მაგალითები

კარგი კომენტარის ნიმუში
PHP
// ამოწმებს ქართულ მობილურს, არასავალდებულო +995-ით.
// ✅ "555123456", "+995555123456"
// ❌ "777123456" (არ იწყება 5-ით), "55512" (მოკლე)
$re = "/^(\+995)?5\d{8}$/";

bp-testing

შაბლონების ტესტირება

regex ადვილად „თითქმის სწორია". დაფარე ის ერთეულ ტესტებით — დადებითი (უნდა დაემთხვეს) და უარყოფითი (არ უნდა დაემთხვეს) შემთხვევებით, საზღვრულ მაგალითებთან ერთად.

მაგალითები

ცხრილით მართული ტესტი
PHP
$re = "/^(\+995)?5\d{8}$/";

$cases = [
    ["555123456",     true],
    ["+995555123456", true],
    ["777123456",     false],
    ["55512",         false],
];
foreach ($cases as [$in, $want]) {
    assert((bool) preg_match($re, $in) === $want);
}
💡 რჩევა: ონლაინ ხელსაწყოები (regex101.com) რეალურ დროში ხსნიან, შაბლონის თითო ნაწილი რას აკეთებს — ჩინებულია სწავლისა და გამართვისთვის.

9 🐞 ხშირი შეცდომები

ხაფანგები, რომლებშიც დამწყებიც და გამოცდილიც ხვდება — და როგორ ავიცილოთ თავიდან.

mistake-missing-anchors

დავიწყებული anchor-ები (^ $)

ვალიდაციისას ^ და $-ის გამოტოვება ნიშნავს, რომ regex ნაწილობრივ დამთხვევასაც წარმატებად ჩათვლის — და დაუშვებს არასწორ ან საშიშ შეტანას.

მაგალითები

უსაფრთხოების ხვრელი
PHP
// ❌ anchor-ების გარეშე — ნაწილსაც პოულობს:
preg_match("/\d{4}/", "kod: 1234; rm -rf /");  // 1 (გაატარა!)

// ✅ anchor-ებით — მთელი სტრიქონი უნდა იყოს ციფრი:
preg_match("/^\d{4}$/", "kod: 1234; rm -rf /"); // 0
preg_match("/^\d{4}$/", "1234");                // 1

mistake-greedy

ხარბი დამთხვევის სიურპრიზი

ნაგულისხმევი .* ხარბია და ხშირად „ზედმეტს ჭამს" — განსაკუთრებით ტეგებსა და ბრჭყალებში. შედეგი — ერთის ნაცვლად მთელი ბლოკი.

მაგალითები

სწორება ზარმაცით
PHP
$s = '<a>1</a><a>2</a>';

// ❌ ხარბი — დაიჭერს ყველაფერს:
preg_match("/<a>(.*)<\/a>/", $s, $m);   // $m[1] = "1</a><a>2"

// ✅ ზარმაცი — მხოლოდ პირველი:
preg_match("/<a>(.*?)<\/a>/", $s, $m);  // $m[1] = "1"

mistake-escaping

არასწორი escaping

ყველაზე ხშირი — დაუescape-ებელი წერტილი. . regex-ში „ნებისმიერი სიმბოლოა", ამიტომ დაუescape-ებელი წერტილი ბევრ არასასურველ შემთხვევას უშვებს.

მაგალითები

წერტილი = ნებისმიერი სიმბოლო
PHP
// ❌ . აქ ნებისმიერ სიმბოლოს ნიშნავს:
preg_match("/^file.txt$/", "fileXtxt"); // 1 (არასწორად!)

// ✅ \. — ნამდვილი წერტილი:
preg_match("/^file\.txt$/", "fileXtxt"); // 0
preg_match("/^file\.txt$/", "file.txt"); // 1
💡 რჩევა: ცვლადიდან მომავალ ტექსტს ყოველთვის გაატარე preg_quote()-ში.

mistake-catastrophic

Catastrophic backtracking

ჩადგმული კვანტიფიკატორები, როგორიც (a+)+ ან (.*)*, engine-ს აიძულებს ექსპონენციალურად ბევრი ვარიანტი გადაამოწმოს. შედეგად მცირე შეტანაც კი წამებით „ჰკიდებს" პროგრამას — ეს ReDoS შეტევის საფუძველია.

მაგალითები

საშიში vs უსაფრთხო
PHP
// ❌ ჩადგმული კვანტიფიკატორი — ექსპონენციალური:
preg_match("/^(a+)+$/", "aaaaaaaaaaaaaaaaaaaa!");
//   "!"-ის გამო engine ათასობით კომბინაციას ცდის

// ✅ გადააწერე ჩადგმვის გარეშე:
preg_match("/^a+$/", $s);
💡 რჩევა: მოერიდე ერთმანეთში ჩადგმულ კვანტიფიკატორებსა და გადამფარავ ალტერნატივებს. ეჭვის შემთხვევაში დაატესტე გრძელ, „ცუდ" შეტანაზე.

mistake-complexity

ზედმეტი სირთულე

ცდუნება — ერთ შაბლონში ყველაფრის ჩატევა. ხშირად კოდის ნაწილად დაშლა უფრო გასაგები, სატესტო და სწრაფია. regex ინსტრუმენტია, და არა თვითმიზანი.

მაგალითები

დაშალე ნაბიჯებად
PHP
// ❌ ერთი მონსტრი-შაბლონი თარიღის სრული ვალიდაციით
//    (ნაკიანი წლები, თვის დღეები...) — წაუკითხავი.

// ✅ ფორმატი regex-ით, მნიშვნელობა კოდით:
if (preg_match("/^\d{4}-\d{2}-\d{2}$/", $s)) {
    $d = DateTime::createFromFormat("Y-m-d", $s);
    $valid = $d && $d->format("Y-m-d") === $s;
}

10 🏋️ სავარჯიშოები

თითო დონეზე: მარტივი → საშუალო → პრაქტიკული. ჯერ თავად სცადე, მერე გახსენი გადაწყვეტა და ახსნა.

ex-basics

სავარჯიშო 1 — ლიტერალები და კლასები

🟢 მარტივი: დაწერე შაბლონი, რომელიც პოულობს სიტყვა „php"-ს რეგისტრის გაუთვალისწინებლად.
🟡 საშუალო: შაბლონი, რომელიც ემთხვევა ზუსტად 3 ციფრიან რიცხვს.
🔵 პრაქტიკული: ამოიღე ტექსტიდან ყველა სიტყვა, რომელიც მხოლოდ ლათინური ასოებისგან შედგება.

მაგალითები

✅ გადაწყვეტა და ახსნა
გადაწყვეტა
// 🟢 i flag რეგისტრს უგულებელყოფს:
preg_match("/php/i", $text);

// 🟡 ^...$ — ზუსტად 3 ციფრი (არც მეტი, არც ნაკლები):
preg_match("/^\d{3}$/", $code);

// 🔵 + = ერთი ან მეტი ასო, \b ცალკე სიტყვისთვის:
preg_match_all("/\b[a-z]+\b/i", $text, $m);

// ახსნა: [a-z] — დიაპაზონი; i — რეგისტრი; \b — საზღვარი.

ex-quantifiers

სავარჯიშო 2 — კვანტიფიკატორები და anchor-ები

🟢 მარტივი: შაბლონი არასავალდებულო „s"-ით — დაემთხვეს „color"-სა და „colour"-საც.
🟡 საშუალო: შეამოწმე, სტრიქონი ზუსტად 4–6 ციფრიანი PIN-ია თუ არა.
🔵 პრაქტიკული: დაიჭირე ფაილის სახელი, რომელიც .log-ით მთავრდება.

მაგალითები

✅ გადაწყვეტა და ახსნა
გადაწყვეტა
// 🟢 u? — "u" არასავალდებულო (0 ან 1):
preg_match("/colou?r/", $text);

// 🟡 {4,6} + anchor-ები — მთელი სტრიქონი 4–6 ციფრი:
preg_match("/^\d{4,6}$/", $pin);

// 🔵 \. ლიტერალი წერტილი, $ — ბოლო:
preg_match("/\.log$/i", $filename);

// ახსნა: anchor-ების გარეშე "12345678" PIN-ად ჩაითვლებოდა.

ex-groups

სავარჯიშო 3 — ჯგუფები და ამოღება

🟢 მარტივი: ამოიღე წელი თარიღიდან 2026-06-10.
🟡 საშუალო: სახელდებული ჯგუფებით ამოიღე დომენი ელფოსტიდან.
🔵 პრაქტიკული: ფორმატი YYYY-MM-DD გადააქციე DD/MM/YYYY-ად.

მაგალითები

✅ გადაწყვეტა და ახსნა
გადაწყვეტა
// 🟢 პირველი ჯგუფი = წელი:
preg_match("/^(\d{4})/", "2026-06-10", $m); // $m[1] = "2026"

// 🟡 სახელდებული ჯგუფი დომენისთვის:
preg_match("/@(?<domain>[\w.-]+)$/", $email, $m);
// $m["domain"]

// 🔵 ჯგუფების გადაწყობა ჩანაცვლებაში:
preg_replace("/(\d{4})-(\d{2})-(\d{2})/", "$3/$2/$1", $date);

// ახსნა: შაბლონში ჯგუფი — \1; ჩანაცვლებაში — $1.

ex-lookaround

სავარჯიშო 4 — lookahead / lookbehind

🟢 მარტივი: შაბლონი პაროლისთვის, რომელიც სულ მცირე ერთ ციფრს შეიცავს.
🟡 საშუალო: ამოიღე რიცხვი, რომელსაც $ უსწრებს (ფასი).
🔵 პრაქტიკული: იპოვე სიტყვა „test", რომელსაც არ მოჰყვება „ing".

მაგალითები

✅ გადაწყვეტა და ახსნა
გადაწყვეტა
// 🟢 დადებითი lookahead — „სადღაც არის ციფრი":
preg_match("/^(?=.*\d).+$/", $pass);

// 🟡 lookbehind — $-ის შემდეგ ციფრები ($ შედეგში არაა):
preg_match_all("/(?<=\\$)\d+/", $text, $m);

// 🔵 უარყოფითი lookahead — "test", მაგრამ არა "testing":
preg_match_all("/test(?!ing)/", $text, $m);

// ახსნა: lookaround zero-width-ია — პირობას ამოწმებს,
// მაგრამ სიმბოლოებს არ „ჭამს".

ex-real

სავარჯიშო 5 — რეალური ამოცანა

🔵 პრაქტიკული (კომპლექსური): ლოგის ფაილიდან ამოიღე მხოლოდ ERROR-ხაზების დროის ნიშნული და შეტყობინება, named groups-ით. შემდეგ ნორმალიზე ტელეფონები სხვადასხვა ფორმატიდან ერთ სტანდარტში.

მაგალითები

✅ გადაწყვეტა და ახსნა
გადაწყვეტა
$log = "[2026-06-10 14:42:01] ERROR: DB timeout";

if (preg_match(
    "/^\[(?<time>[\d\- :]+)\] ERROR: (?<msg>.+)$/",
    $log, $m
)) {
    // $m["time"], $m["msg"]
}

// ტელეფონის ნორმალიზაცია:
$phone = preg_replace("/\D+/", "", "+995 (555) 12-34-56");
// "995555123456"

// ახსნა: \D+ ყველა არა-ციფრს შლის; named groups ხდის
// კოდს თვით-დოკუმენტირებულს.
💡 რჩევა: რეალურ ამოცანას დაშალე პატარა ნაბიჯებად: ჯერ დაიჭირე, მერე ამოიღე, ბოლოს ნორმალიზე. თითო ნაბიჯი ცალკე დაატესტე.