რეგულარული გამოსახულებები

რეგულარული გამოსახულებები (Regular expressions) არის სიმბოლოთა თანმიმდევრობა, რომელიც ახდენს სტრიქონში ამა თუ იმ სიმბოლოს ძებნას ან ჩანაცვლებას კონკრეტული ფორმულირების მიხედვით. JavasScript-ში რეგულარული გამოსახულებები რეალიზირებულია ობიექტ RegExp.

რეგულარული გამოსახულების შექმნა

რეგულარული გამოსახულების შექმნა შესაძლებელია 2 გზით:

  • რეგულარული გამოსახულებების პატერნის ხაზებში მოთავსებით (/pattern/).
  • ობიექტ RegExp კონსტრუქტორის გამოძახებით (new RegExp("pattern", flag)).

დროშები

რეგულარულ გამოსახულებას შეიძლება გააჩნდეს დროშები (flags), რომლის გამოყენების დროსაც ვღბულობთ განსხვავებულ შედეგს:

დროშა აღწერა შესაბამისი თვისება
d აგენერირებს ინდექსებს ქვესტრიქონთან დამთხვევის დროს hasIndicies
g გლობალური ძებნა global
i Case-insensitive (დიდი და პატარა სიმბოლო განიხილება ერთნაირად) ძებნა ignoreCase
m მრავალხაზიანი ძებნა (აძლევს უფლებას ^ და $ დაემთხვეს ახალხაზზე მდგომ ჩარებს) multiline
s აძლევს უფლებას . დაემთხვეს ახალხაზზე მდგომ ჩარებს dotAll
u განიხიალვს "Unicode"-ის ჩანაწერებს (მაგ: \u{6B}) unicode
v განახლებული ვერსია u დროშის, სადაც უფრო მეტი თვისებები არის unicodeSets
y განიხილავს 'sticky' ძიებას sticky

დროშების გამოყენების სინტაქსი:

JS
const regex = /pattern/flags;
const regexWithObject = new RegExp('pattern', 'flags');

კლასები

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

ჩარაქტერები მნიშვნელობა
[xyz] [a-z] ჩარაქტერების დიაპაზონი ან კონკრეტული სიმბოლოები. კონკრეტული შემთხვევისთვის გვაქვს: [xyz], როგორც დამთხვევა: 'x', 'y', 'z', სადაც სხვა არცეთი სიმბოლო არ ემთხვევა, ხოლო [a-z] იგულისხმება დიაპაზონი, სადაც შედის ლათინური სიმბოლოები (a-დან z-მდე) თუმცა არ იგულისხმება დიდი სიმბოლოები (A-დან Z-მდე), არც რიცხვები და არც სპეციალური სიმბოლოები.
[^a-k] ჩვეულებრივი დიაპაზონების გარდა არსებობს გამონაკლისი დიაპაზონები, მაგალითად: [^a-k] იგულისხმება ყოველი ჩარაქტერი გარდა a-დან k-მდე.
. წერტილი გამოიყენება ერთი სიმბოლოს დასამთხვევად, გარდა ახალი ხაზის ჩარაქტერისა (\n). წერტილს შეუძლია ნებისმიერი სიმბოლოს წარმოდგენა (თვითონ წერტილიც იგულისხმება), შეგიძლიათ წარმოიდგინოთ, როგორც placeholder. მაგალითად: /a.b/ ემთხვევა 'aab' 'axb' 'a1b', იგივე პატერნი არ ემთხვევა: ab და a\nb (\n გამონაკლისი შემთხვევა .-ისთვის).
\d digit კლასი გამოიყენება ნებისმიერი ციფრების (არაბული რიცხვებისთვის 1,2, ...) დასამთხვევად, მისი გამოყენება იგივეა რაც [0-9] დიაპაზონი.
\D digit შებრუნებული კლასი, რაც გულისხმობს: ნებისმიერი სიმბოლო გარდა ციფრებისა, იგივეა რაც: [^0-9].
\w word კლასი გამოიყენება ნებისმიერი ლათინური ანბანის სიმბოლოსთვის დამთხვევისთვის და ქვედატირეც, არა ლათინური სიმბოლოები არ შედის ამ კლასსში. მაგალითად: \w ექვივალენტურია [a-zA-Z0-9_].
\W word შებრუნებული კლასი, რაც გულისხმობს: ნებისმიერი სიმბოლო გარდა ლათინური ანბანისა და ქვედატირისა, იგივეა რაც: [^a-zA-Z0-9_].
\s space კლასი გამოიყენება: whitespace, დაშორებებისთვის (space), ტაბის დაშორებისთვის (tab ღილაკიდან მიღებული დაშორებები) დამთხვევისთვის (მეტწილადად დაშორებებისთვის), იგივეა რაც: [\f\n\r\t\v\u0020\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff], მაგალითი: /\s/.test('Hello world'), რაც დააბრუნებს true რადგან 'Hello world' შეიცავს დაშორებას.
\S space შებრუნებული კლასი, ნებისმიერი სიმბოლო გარდა დაშორებებისა. იგივეა რაც: [^\f\n\r\t\v\u0020\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff], მაგალითად: /\S/.test('HelloWorld') დააბრუნებს true, რადგან HelloWorld არ შეიცავს დაშორებას.
\t გამოიყენება ჰორიზონტალური tab დაშორების დამთხვევისთვის, მაგალითად: /\t/.test('Hello\tWord') დააბრუნებს true, რადგან 'Hello\tWord' შეიცავს \t.
\r გამოიყენება ვაგონის (carriage) დაბრუნების დამთხვევისთვის, მაგალითად: /\r/.test('ხაზი 1\rხაზი 2') დააბრუნებს true, რადგან 'ხაზი 1\rხაზი 2' შეიცავს \r.
\n გამოიყენება linefeed დამთხვევისთვის, მაგალითად: /\n/.test('ხაზი 1\nხაზი 2') დააბრუნებს true, რადგან 'ხაზი 1\nხაზი 2' შეიცავს \n.
\v გამოიყენება ვერტიკალური tab დაშორების დამთხვევისთვის, მაგალითად: /\v/.test('Hello\vWord') დააბრუნებს true, რადგან 'Hello\vWord' შეიცავს \v.
\f გამოიყენება form-feed დამთხვევისთვის, მაგალითად: /\f/.test('Hello\fWord') დააბრუნებს true, რადგან 'Hello\fWord' შეიცავს \f.
\0 გამოიყენება NUL ჩარაქტერის დამთხვევისთვის (არ ჩათვალოთ 0, როგორც ციფრი), მაგალითად: /\0/.test('Hello\0Word') დააბრუნებს true, რადგან 'Hello\0Word' შეიცავს \0.
[\b] გამოიყენება backspace დაშორების დამთხვევისთვის, მაგალითად: Hello\bWorld დააბრუნებს true, რადგან 'Hello\bWord' შეიცავს \b.
x | y გამოიყენება x ან y დამთხვევის შემთხვევაში (x ან y შეიძლება შეიცვალოს ნებისმიერი მნიშვნელობით). მაგალითად: /კარგი|ცუდი/.test('დღეს კარგი ამინდია') დააბრუნებს true, რადგან 'დღეს კარგი ამინდია' შეიცავს სიტყვა 'კარგს'.
\ escape ჩარაქტერი, გამოიყენება იმისათვის რომ წინა მნიშვნელობა გამოტოვოს. მაგალითად გვინდა მნიშვნელობა დავიწყოთ რომელიმე ისეთი ჩარაქტერით, რომელსაც სპეციფიკური მნიშვნელობა გააჩნია პატერნში, ესეთ დროს შესაძლებელია escape ჩარაქტერით ეს მნიშვნელობა დავტოვოთ, როგორც ჩვეულებრიბ სიმბოლოდ ზედმეტი მნიშვნელობების დატანების გარეშე.

მტკიცებულებები

მტკიცებულებები (Assertions) შეიცავს საზღვრებს, რომლებიც მიუთითებს ტექსტის დასაწყისისა და დასასრულის დამთხვევას.

ჩარაქტერები მნიშვნელობა
^ პოულობს დამთხვევას პატერნის დასაწყისში. თუ მრავალხაზოვანი დღოშა (m) არის გამოყენებული მაშინ ემთხვევა ყოველი ახალი ხაზის დასაწყისში მოთავსებულ ჩარაქტერებს.
$ პოულობს დამთხვევას პატერნის ბოლოში. თუ მრავალხაზოვანი დღოშა (m) არის გამოყენებული მაშინ ემთხვევა ყოველი ახალი ხაზის ბოლოში მოთავსებულ ჩარაქტერებს.

რაოდენობები

რაოდენობები (Quantifiers) განსაზღვრავს თუ რამდენჯერ უნდა იყოს კონკრეტული ჩარაქტერი ან გამოსახულება დამთხვეული.

ჩარაქტერები მნიშვნელობა
x* განსაზღვრავს "x" დამთხვევას საერთოდ არა (0) ან მეტჯერ, მაგალითად: /კი*/ შემთხვევაში, გვაქვს შემდგომი დამთხვევები: 'კ', 'კი', 'კიი (ბევრი ი შეიძლება)'.
x+ განსაზღვრავს "x" დამთხვევას 1 ან მეტჯერ, მაგალითად: /კი+/ შემთხვევაში, გვაქვს შემდგომი დამთხვევები: 'კი', 'კიი (ბევრი ი შეიძლება)'. შესაბამისი მაგალითი შესაძლოა იყოს ასევე {1, }.
x? განსაზღვრავს "x" დამთხვევას საერთოდ არა (0) ან ერთხელ. მაგალითად: /კი?/ შემთხვევაში, გვაქვს შემდგომი დამთხვევები: 'კ', 'კი'.
x{n} განსაზღვრავს "x" დამთხვევას "n"-ჯერ. მაგალითად: /კი{2}/ შემთხვევაში, გვაქვს შემდგომი დამთხვევა 'კიი'.
x{n, } განსაზღვრავს "x" დამთხვევას მინიმუმ "n"-ჯერ. მაგალითად: /კი{2, }/ შემთხვევაში, გვაქვს შემდგომი დამთხვევები: 'კიი', 'კიიი (ბევრი ი შეიძლება)'.
x{n, m} განსაზღვრავს "x" დამთხვევას კონკრეტულ ინტერვალში "n"-დან "m"-მდე. მაგალითად: /კი{2, 3}/ შემთხვევაში, გვაქვს შემდგომი დამთხვევები: 'კიი', 'კიიი'.

მეთოდები

რეგულარული გამოსახულებებისთვის ხშირ შემთხვევაში გამოიყენება RegExp-ს მეთოდები: test() და exec(), ასევე გამოიყენება სტრინგი-ს მეთოდები: match(), matchAll(), replace(), replaceAll(), search() და split().

მეთოდი აღწერა
exec() მეთოდი ეძებს სტრინგში დამთხვევას, აბრუნებს მასივს შესაბამისი ელემენტებით თუ იპოვა დამთხვევა წინააღმდეგ შემთხვევაში აბრუნებს null-ს. მეტწილადად გამოიყენება ციკლებთან მიმართებაში.
test() მეთოდი ამოწმებს სტრინგში არის თუ არა დამთხვევა პატერნიდან გამომდინარე. თუ არის დამთხვევა აბრუნებს true წინააღმდეგ შემთხვევაში false.
match() მეთოდი აბრუნებს მასივს დამთხვეული მნიშვნელობისთვის, თუ დამთხვევა არ არის დააბრუნებს null-ს. თუ გამოვიყენებთ g დროშას, მეთოდი იმოქმედებს, როგორც matchAll.
matchAll() მეთოდი აბრუნებს იტერირებად მასივს, რომელსაც გააჩნია ყოველი დამთხვევა (for...of-სთვის იდეალურია).
search() მეთოდი ეძებს სტრინგს დამთხვევებზე. თუ იპოვა დამთხვევა დააბრუნებს მის ინდექს წინააღმდეგ შემთხვევაში -1-ს.
replace() მეთოდი დაიწყებს სტრინგში დამთხვევების მოძებნას, პოვნის შემთხვევაში დააბრუნებს შესაცვლელი სტირნგით თუ ვერ იპოვა მაშინ დააბრუნებს იგივე სტრინგს. მეთოდი შეცვლის მხოლოდ პირველ ნაპოვნ მნიშვნელობას, თუ გვსურს ყოველი დამთხვევის შეცვლა მაშინ უნდა გამოვიყენოთ replaceAll მეთოდი ან g დროშა.
replaceAll() მეთოდი დაიწყებს სტრინგში დამთხვევების მოძებნას, პოვნის შემთხვევაში შეცვლის ყოველ დამთხვევას და დააბრუნებს ახალ სტრინგს, ვერ პოვნის შემთხვევაში კი იგივე სტრინგს.
split() მეთოდი დაყოფს სტრინგს გადაცემული პატერნის მიხედვით და დააბრუნებს მასივს.

პრაქტიკა

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

შესწავლილი თეორიიდან მოდით მცირედ პრაქტიკაზე გადავიდეთ, დავწეროთ მარტივი ქართული ნომრის რეგულარული გამოსახულება. ქართული ნომრის პატერნი შემდგომია: +9955XXXXXXXX.

JS
const phoneNumberRegex = /\+9955\d{8}$/;
console.log(phoneNumberRegex.test('+995512345678')); // true
console.log(phoneNumberRegex.test('+9955123456789')); // false

არსებული რეგექსის პატერნი განვიხილოთ ნაწილებად:

  • \+9955 ქართული ნომრის პრეფიქსი (+995) და 5, რადგან მეტწილადად ნომრები 5-ით იწყება.
  • \d{8} პრეფიქსის შემდგომი 8 ცალი ციფრი გვჭირდება.

შემდგომი მაგალითისთვის შევქმნათ სახელის პატერნი, ქართულ სახელში მინიმუმ 2 სიმბოლო გვჭირდება და მაქსიმუმისთვის განვიხილოთ 25 (ბევრია თუმცა თავი დავიზღვიოთ, რაღაც მაქსიმალური მნიშვნელობით), ასევე სახელში არ უნდა იყოს რიცხვი ან სპეციალური ჩარაქტერი.

JS
const nameRegex = /^[a-zA-Z]{2,25}$/;
console.log(nameRegex.test('konstantine')); // true
console.log(nameRegex.test('pridoni')); // true
console.log(nameRegex.test('satesto1')); // false
console.log(nameRegex.test('satesto_')); // false

არსებული რეგექსის პატერნი განვიხილოთ ნაწილებად:

  • ^ მტკიცებულების ნიშანი, რომელიც გულისხმობს, რომ იწყებოდეს ...
  • [a-zA-Z] დიაპაზონი ლათინური სიმბოლოების, როგორც პატარა ასევე დიდი ასოებისთვის.
  • {2, 25} მინიმუმ 2 მაქსიმუმ 25.
  • $ მტკიცებულების ნიშანი, რომელიც გულისხმობს, რომ უნდა მთავრდებოდეს ამ მნიშვნელობით.

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

JS
const georgianNameRegex = /^[ა-ჰ]{2,25}$/;
console.log(georgianNameRegex.test('კონსტანტინე')); // true
console.log(georgianNameRegex.test('ფრიდონი')); // true
console.log(georgianNameRegex.test('ი')); // false
console.log(georgianNameRegex.test('pridoni')); // false
console.log(georgianNameRegex.test('konstantine_')); // false

არსებულ პატერნში შეიცვალა უბრალოდ დიაპაზონი, რომ სიმბოლოები იყოს მოთავსებული -დან -მდე. იგივე შედეგის მიღება შეგვეძლო უნიკოდების გამოყენებით, რომ დაიწყოს U+10D0-დან U+10FF-მდე. ტექნიკურად ქართული სიმბოლოები იწყება U+10A0 თუმცა ძველი და ამოღებული სიმბოლოებით დღესდღეისობით ვეღარ შევხვდებით სახელს ამიტომაც, უმჯობესია დავიწყოთ -დან. უნიკოდების სია შეგიძლიათ იხილოთ symbl.cc-ზე.

პაროლის ვალიდატორი

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

შეჯამება

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

იხილეთ სამაგალითო კოდები playground-ში.