التعبيرات القياسية (Regular Expressions)، هي أنماط (patterns) تُستخدم لمطابقة مجموعة من الأحرف في السلاسل النصية. التعبيرات القياسية في جافاسكربت كائنات أيضا. تُستخدم هذه الأنماط مع الوظائف exec
وtest
للكائن RegExp
، ومع الوظائف match
، و replace
، وsearch
و split
للكائن String
. يتناول هذا الفصل تعبيرات جافاسكربت القياسية.
انشاء تعبير قياسي او ريجكس
يمكنك انشاء ريجكس من خلال احدى الطرق التالية:
الطريقة الاولى، باستخدام التعبير القياسى الحرفي regular expression literal، ويتضمن الباترن pattern بين سلاشين، كما يلي:
var re = /ab+c/;
يقوم ال Regular expression literals بتجهيز التعبير القياسي عند تحميل السكريبت. شرط ان يظل التعبير القياسي ثابتا، في هذه الحالة، استخدام هذا الشكل المختصر يمكن أن يحسن من الأداء.
الطريقة الثانية، من خلال استدعاء constructor
الكائن RegExp
، كما يلي:
var re = new RegExp('ab+c');
استخدام ال constructor، يقلل من وقت تشغيل الريجكس. إسْتخدِم ال constructor عندما تريد ان يكون الريجكس قابلا للتغيير، او في حالة عدم علمك بالريجكس الذي ستحصل عليه من طرف اخر. كحقل المدخلات مثلا.
انشاء باترن الريجكس
يتكون الباترن البسيط اما من رموز عادية، مثل /abc/
، او خليط من الرموز العادية والرموز الخاصة، مثل /ab*c/
او /Chapter (\d+)\.\d*/
. يحتوي هذا الباترن على اقواس هلالية، هذه الاقواس ستقوم بدور ذاكرة الجهاز، بحيث ستقوم بتخزين قيمة المطابقة الناتجة عن هذا الجزء من الباترن وفهرستها ليتم استدعاؤها لاحقا. للمزيد من التفاصيل حول مطابقة السلسلة النصية الجزئية بين قوسين.
استخدام الباتر البسيط
تتكون الباترنز البسيطة، من رموز صريحة ومباشرة، تصف فيها ما تريد مقارنته مباشرة. مثلا، الباترن /abc/
سيطابق مجموعة من الرموز في سلسلة نصية، شرط تواجد هذه الرموز جنبا الى جنب بشكل مرتب. لذالك، ستنجح المطابقة في هذه السلسلة النصية "Hi, do you know your abc's?"
وكذالك في السلسلة النصية التالية "The latest airplane designs evolved from slabcraft."
، نجحت المطابقة في كلتا الحالتين لان السلسلة الفرعية 'abc'
هي المطلوبة. وهذا لايتطابق مع هذه السلسلة النصية 'Grab crab'
لانها تحتوي على سلسلة نصية غير تلك المطلوبة 'ab c'
.
استخدام الرموز الخاصة
عندما يتطلب الامر عملية بحث، أكثر من مطابقة صريحة ومباشرة، مثل البحث عن واحد او اكثر من ال 'b'
، او البحث عن مسافة فارغة، عندها سيتوجب على الباترن ان يحتوي على الرموز الخاصة. مثلا، الباترن /ab*c/
سيطابق مجموعة من الرموز، حيث ستكون 'a'
متبوعة بصفر او اكثر من ال 'b'
، الرمز الخاص نجمة *
يرصد وجود العنصر المطلوب صفر او اكثر من المرات، متبوعا مباشرة ب 'c'
. بعد فحص السلسلة النصية "cbbabbbbcdebc,"
قام الباترن بمطابقة السلسلة الجزئية 'abbbbc'
.
يحتوي الجدول التالي على قائمة مكتملة من رموز الريجكس الخاصة وشرحها.
الرمز | شرح الاستخدام |
---|---|
\ |
مطابقات وفقا للقواعد التالية:
|
^ |
مطابقة بداية المدخلات. ادا كان البند
|
$ |
مطابقة نهاية المدخلات. ادا كان البند |
* |
مطابقة التعبير الذي سيسبق الرمز مثلا،
|
+ |
مطابقة التعبير الذي سيسبق الرمز مثلا،
|
? |
مطابقة التعبير الذي سيسبق الرمز
|
. |
النقطة الكسرية تطابق اي شئ، ما عدا السطر الجديد مثلا،
|
(x) |
مطابقة
|
(x:?) |
مطابقة ال انشاء جزئية مفهرسة وعدم استخدامها، يبطئ من سرعة محرك الريجكس، لانه يتسبب له في عمل زائد، يمكنك جعل محرك الريجكس اسرع قليلا باستخدام علامة الاستفهام والنقطتين بعد قوس الافتتاح هما من الرموز الخاصة، استخدامهما جنبا الى جنب يخبر محرك الريجكس بان هذه المجموعة لا ينبغي ان تعامل كجزئية مفهرسة. وبالتالي لا يمكن، استدعاء المطابقة من خلال الفهرسة الرقمية
|
=? |
مطابقة ال مثلا،
|
!? |
مطابقة ال مثلا،
|
x|y |
مطابقة مثلا،
|
{n} |
مطابقة n تحديدا، بناءا على التعبير الذي سيسبقه. n يجب ان يكون عددا صحيحا.
|
{n,} |
مطابقة n او اكثر، بناءا على التعبير الذي سيسبقه. n يجب ان يكون عددا صحيحا. مثلا،
|
{n,m} |
حيث ان مثلا،
|
[xyz] |
المجموعة، او مجموعة الرموز، هذا النوع من الباترن يطابق اي رموز داخل الاقواس المعقوفة، بما فيها المهربات المتتالية escape sequences. الرموز الخاصة مثل النقطة (
|
[xyz^] |
منع مجموعة من الرموز او رموز معينة. سيتم مطابقة اي شئ ما عد ما ورد داخل الاقواس المعقوفة، يمكنك تحديد منظم الرموز وفصله بشرطة، جميع ما يمكن استخدامه في المجموعة او مجموعة الرموز العادية يمكن استخدامه هنا. مثلا، الباترن
|
[b\] |
سيطابق backspace (U+0008). اذا كنت ترغب بمطابقة الرمز النصي: رجوع الى الخلف literal backspace character. فمن الضروري استخدام الاقواس المعقوفة، حتى لا تتعارض مع
|
b\ |
مطابقة حدود الكلمة
امثلة مختلفة: ملاحظة: محرك الريجكس في الجافاسكريبت حدد بالتدقيق مجموعة الرموز على ان تكون
|
B\ |
ال مثلا،
|
cX\ |
حيث ان X هو منظم الرموز من A الى Z. يطابق رمز عنصر التحكم في سلسلة نصية. مثلا، مثلا،
|
d\ |
مطابقة الاعداد. ويكافئ الباترن مثلا،
|
D\ |
مطابقة كل شئ ما عدا الاعداد. ويكافئ الباترن مثلا،
|
f\ |
سيطابق نموذج التلقيم form feed (U+000C). |
n\ |
سيطابق سطر التلقيم line feed (U+000A). |
r\ |
سيطابق carriage return (U+000D). |
s\ |
مطابقة رمز المسافة الفارغة، بما في ذالك المسافة، التاب، نمودج التلقيم، سطر التلقيم، ويكافئ مثلا،
|
S\ |
مطابقة اي شئ ما عدا رمز المسافة الفارغة، ويكافئ مثلا،
|
t\ |
سيطابق tab (U+0009). |
v\ |
سيطابق vertical tab (U+000B). |
w\ |
مطابقة الحروف الابجدية بما في ذالك ال underscore. ويكافي مثلا، |
W\ |
مطابقة اي شئ غير الحروف الابجدية والاندرسكور، ويكافئ مثلا،
|
n\ |
حيث ان n عدد صحيح موجب، سيشير الى المجموعة المفهرسة capturing parentheses . مثلا،
|
0\ |
مطابقة الرمز NULL (U+0000). لا تتبع هذا برقم آخر، بسبب ان
|
xhh\ |
مطابقة الرمز مع الكود hh (two hexadecimal digits). |
uhhhh\ |
مطابقة الرمز مع الكود hhhh (four hexadecimal digits). |
u{hhhh } |
( فقط عندما يستخدم u flag ) سيطابق الرمز مع ال Unicode بالقيمة hhhh (hexadecimal digits). |
لتهريب تعابير الريجكس في المدخلات النصية، يمكنك استخدام دالة الاستبدال التالية:
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}
يستخدم البند g
بعد الباترن، لاجراء بحث عام، ينظر في كل السلسلة النصية ويعود بكل المطابقات. تم شرحه بالتفصيل ادناه. البحث المتقدم باستخدام البنود.
استخدام الاقواس
الاقواس المحيطة باي جزء من الباترن، تجعل هذا الجزء قابل للتخزين والفهرسة. بمجرد ما يتم تخزينه وفهرسته، يصبح قابلا لاعادة الاستخدام من اطراف اخرى، كما تم شرحه في استخدام مطابقة الاقواس الجزئية.
مثلا، الباترن /Chapter (\d+)\.\d*/
يطابق بدقة، الرموز 'Chapter '
متبوعة بواحد او اكثر من الارقام (\d
تشير الى اي رقم و +
تشير الى واحد او اكثر من المرات، بالاضافة الى الاقواس المستخدمة خصيصا لتخزين وفهرسة ما سينتج عنه )، متبوعا بنقطة او فاصلة عشرية التي هي نفسها من الرموز الخاصة، يسبقها الباكسلاش \ الذي بدوه يخبر الباترن بان يعاملها كنقطة عادية، متبوعا باي رقم يكرر صفر او اكثر من المرات (\d
تشير الى اي رقم والنجمة *
تشير الى صفر او اكثر من المرات).
هذا الباترن سيطابق "Chapter 4.3"
في "Open Chapter 4.3, paragraph 6"
، وايضا سيقوم بتخزين وفهرسة الجزئية '4'
. بينما الباترن لا يطابق شئ في "Chapter 3 and 4"
بسبب ان السلسلة الحرفية لاتحتوي على النقطة بعد الرقم '3'
.
لمطابقة سلسلة فرعية من دون التسبب في فهرسة الجزء المتطابق (راجع non-capturing)، ضمن الاقواس ابدا الباترن ب ?:
. مثلا (?:\d+)
ستطابق واحد او اكثر من الارقام من دون ان تفهرس الرموز المتطابقة.
العمل مع الريجكس
تستخدم التعابير القياسية مع اثنين من الاوبجكت. الاوبجكت الاول هو RegExp
ويحتوي على الوظيفتين test
و exec
والاوبجكت الثاني وهو String
ويحتوي على الوظائف التالية: match
، replace
، search
، و split
. تم شرح هذه الوظائف بالتفصيل في JavaScript reference.
الوظيفة | وصفها |
---|---|
exec |
تقوم هذه الوظيفة بتنفيذ بحث لمطابقة سلسلة نصية. وتعود بمصفوفة تحتوي على نتيجة البحث، او تعود ب null في حالة عدم المطابقة. |
test |
تقوم هذه الوظيفة بعمل فحص لمطابقة سلسلة نصية. وتعود اما ب true او false. |
match |
تقوم هذه الوظيفة بتنفيذ بحث لمطابقة سلسلة نصية. وتعود بمصفوفة تحتوي على نتيجة البحث، او تعود ب null في حالة عدم المطابقة. (نفس ما تقوم به الوظيفة exec). |
search |
تقوم هذه الوظيفة بعمل فحص لمطابقة سلسلة نصية. وتعود برقم المكان الذي يتواجد فيه ما تمت مطابقته. او ب -1 في حالة لم يتم العثور على المطلوب. |
replace |
تقوم هذه الوظيفة بتنفيذ بحث لمطابقة سلسلة نصية. ويحل محل السلسلة الجزئية المتطابقة، السلسلة الجزئية البديلة. |
split |
هذه الوظيفة تستخدم الريجكس او سلسلة نصية ثابتة لتقسيم السلسلة الى مصفوفة من السلاسل الجزئية. |
عندما تريد معرفة ما اذا كان الباترن موجود في سلسلة نصية ام لا، استخدم اما الوظيفة test
او الوظيفة search
، اما لمعرفة المزيد من المعلومات (ولكن أبطأ قليلا في التنفيذ)، استخدم اما الوظيفة exec
او الوظيفة match
اذا استخدمت exec
او match
ونجحت المطابقة، فان هاتان الوظيفتان ستعود بمصفوفة، وفي نفس الوقت ستقوم بتحديث خصائص الريجكس المرتبطة به وكذلك خصائص الريجكس RegExp
. اذا فشلت المطابقة, ستعود الوظيفة exec
ب null
( التي تفرض : false
).
في المثال التالي، السكريبت يستخدم الوظيفة exec
للبحث عن مطابقة في السلسلة النصية:
var myRe = /d(b+)d/g;
var myArray = myRe.exec('cdbbdbsbz');
إذا كنت لا تحتاج إلى الوصول إلى خصائص الريجكس، هناك طريقة بديلة لإنشاء myArray
، كالتلي:
var myArray = /d(b+)d/g.exec('cdbbdbsbz'); // similar to "cdbbdbsbz".match(/d(b+)d/g); however,
// the latter outputs Array [ "dbbd" ], while
// /d(b+)d/g.exec('cdbbdbsbz') outputs Array [ "dbbd", "bb" ].
// See below for further info (CTRL+F "The behavior associated with the".)
إذا كنت ترغب في بناء ريجكس من سلسلة نصية، هناك بديل آخر، كالتالي:
var myRe = new RegExp('d(b+)d', 'g');
var myArray = myRe.exec('cdbbdbsbz');
مع هذا السكريبت، تنجح المطابقة، ويتم ارجاع مصفوفة وتحديث الخصائص معروض في الجدول التالي.
الكائن | الخاصية او الفهرس | الوصف | في هذا المثال |
---|---|---|---|
myArray |
السلسلة النصية التي جرى مطابقتها وجميع السلاسل النصية الجزئية المفهرسة. | ['dbbd', 'bb', index: 1, input: 'cdbbdbsbz'] |
|
index |
فهرس بداية المُطابَقة في السلسلة النصية، والفهرسة تبتدئ من 0. | 1 |
|
input |
السلسلة النصية الأصلية. | "cdbbdbsbz" |
|
[0] |
الرموز الاخيرة التي جرى مطابقتها | "dbbd" |
|
myRe |
lastIndex |
الفهرس الذي ستبدأ عنده عملية البحث عن المطابقة التالية. وإذا لم يتم ضبط البند "g " فستبقى قيمته مساويةً للصفر. للمزيد حول البحث المتقدم باستخدام البنود. |
5 |
source |
نص الباترن. تم تحديثه في الوقت الذي تم فيه إنشاء الريجكس، وليس وقت تنفيذه. | "d(b+)d" |
كما شاهدنا في المثال الثاني، تستطيع استخدام ريجكس منشا من خلال معد الاوبجكت "object initializer"
، من دون اسناده الى متغير. اذا قمت بعمل ذالك، كل ما سيحدث هو ظهور ريجكس جديد. لهذا السبب، لا يمكن الوصول الى خصائص الريجكس. يوضح المثال التالي كيفية الوصول الى خصائص الكائن بالطريقة الصحيحة:
var myRe = /d(b+)d/g;
var myArray = myRe.exec('cdbbdbsbz');
console.log('The value of lastIndex is ' + myRe.lastIndex);
// "The value of lastIndex is 5"
بينما يوضح المثال التالي كيفية الوصول الى خصائص الكائن بالطريقة الخاطئة:
var myArray = /d(b+)d/g.exec('cdbbdbsbz');
console.log('The value of lastIndex is ' + /d(b+)d/g.lastIndex);
// "The value of lastIndex is 0"
حاصل الباترن /d(b+)d/g
في كلتا التعليمات البرمجية، عبارة عن كائنان مختلفان، لذالك هما مختلفان في قيمة الخاصية lastIndex
اذا كنت ترغب في الوصول الى خصائص الريجكس المنشا من طرف معد او مهيئ الاوبجكت، يلزمك اولا اسناده لمتغير.
Using parenthesized substring matches
بمجرد تضمين جزء من الباترن داخل الاقواس الهلالية، سيصبح جزءا مفهرسا قابل لاعادة الاستخدام، مثلا، الباترن /a(b)c/
سيطابق 'abc'
في "abcd"
ويفهرس المطابقة الجزئية (b)
برقم 1
، ناتج المطابقة الجزئية (b)
هو السلسلة الحرفية الجزئية 'b'
. لاستدعاء هذا الجزء المفهرس خارج الباترن، استخدم عناصر المصفوفة [1]...
. ولاعادة استخدامها داخل الباترن استخدم الفهرسة الرقمية \1 ...
.
- كيفية استدعائها خارج الباترن:
var myRe = /a(b)c/;
var myArray = myRe.exec('abcb');
console.log('The result of submatch N1: ' + myArray[1] );
// log: The result of submatch N1: b
يمكنك استخدام عدد لا متناهي من هذه الاجزاء المفهرسة، تبتدئ الفهرسة من واحد، عائد المصفوفة سيتضمن جميع الاجزاء المفهرسة في الباترن.
كيفية اعادة استخدامها داخل الباترن:
var myRe = /a(b)c\s\1/g;
var myArray = myRe.exec('abc b');
console.log('The result of submatch N1: ' + myArray[1] );
// log: The result of submatch N1: b
يستخدم السكريبت التالي الوظيفة ()replace
لعكس الكلمتين John و Smith في السلسلة النصية 'John Smith'
. ويستخدم في نص الاستبدال، المتغيرات السحرية $1
و $2
لاستدعاء المطابقة الجزئية المفهرسة الاولى والثانية. مثال:
var re = /(\w+)\s(\w+)/;
var str = 'John Smith';
var newstr = str.replace(re, '$2, $1');
console.log(newstr);
// "Smith, John"
ملاحظة: يسمح باستخدام المتغيرات السحرية، 9 مرات فقط، في العملية الواحدة.
البحث المتقدم باستخدام البنود
التعبيرات القياسية في الجافاسكريبت لها خمسة بنود ، وجودها اختياريا، تسمح لنا بعمل بحثا عاما او بحثا دون مراعات لحالة الاحرف. يمكن استخدامها اما منفردة او مجتمعة وكذالك في اي ترتيب، حسب الطلب، وهي جزء من الريجكس.
Flag | Description |
---|---|
g |
بحث عام، عدم وجوده = النتيجة الاولى فقط. |
i |
عدم مراعاة حالة الاحرف، سواء كانت صغيرة او كبيرة. |
m |
البحث في السطور المتعدد = كامل النص. |
u |
سلسلة يونيكود، أي معاملة الباترن على أنه سلسلة من رموز يونيكود (Unicode code points). |
y |
المطابقة ستبدأ من الفهرس المُشار إليه بالخاصية lastIndex لكائن التعابير النمطية في السلسلة الهدف، ولن تتم محاولة مطابقة ما قبل هذا الفهرس. للمزيد من المعلومات sticky |
لتضمين بند مع الريجكس استخدم التعبير التالي:
var re = /pattern/flags;
او
var re = new RegExp('pattern', 'flags');
البنود، جزء لا يتجزأ من الريجكس. لا يمكن إزالتها أو إضافتها لاحقا.
مثلا، re = /\w+\s/g
يقوم بانشاء ريجكس يبحث على واحد او اكثر من الرموز متبوعة بمسافة واحدة، يقوم بتنفيذ هذا الاجراء على السلسلة الحرفية (كاملة = g
):
var re = /\w+\s/g;
var str = 'fee fi fo fum';
var myArray = str.match(re);
console.log(myArray);
// ["fee ", "fi ", "fo "]
يمكنك استبدال هذا السطر:
var re = /\w+\s/g;
ب:
var re = new RegExp('\\w+\\s', 'g');
وستحصل على نفس النتيجة.
يستخدم البند m
لاخبار محرك الريجكس، بان المدخلات النصية، المتعددة السطور، يجب ان تعامل كسطور متعددة. اذا تم استخدام البند m
فسيتطابق الرمزان الخاصان ^
و $
، مع بداية أو نهاية كل سطر من المدخلات، بدلا من المدخل بالكامل. مثال:
var re = /^Multi\s*line$/gm;
var str = 'Multi line\n or \nMultiline';
var myArray = str.match( re );
console.log( myArray );
// log: [ "Multi line", "Multiline" ]
امثلة
تبين الامثلة التالية بعض استخدامات الريجكس
اعادة صياغة المدخلات النصية.
يوضح المثال التالي كيف يمكن للريجكس ان يتلاعب في بنية السلسلة النصية، وايضا كيفية استخدام ()string.split
و ()string.replace
. سيقوم السكريبت التالي بتنظيف واعادة صياغة السلسلة النصية، التي تحتوي على اسماء مفصولة بمسافات فارغة، تابات، وبالظبط فاصلة منقوطة واحدة. واخيرا سيقوم بعكس هذه الاسماء وترتيبها من a الى z.
// The name string contains multiple spaces and tabs,
// and may have multiple spaces between first and last names.
var names = 'Orange Trump ;Fred Barney; Helen Rigby ; Bill Abel ; Chris Hand ';
var output = ['---------- Original String\n', names + '\n'];
// Prepare two regular expression patterns and array storage.
// Split the string into array elements.
// pattern: possible white space then semicolon then possible white space
var pattern = /\s*;\s*/;
// Break the string into pieces separated by the pattern above and
// store the pieces in an array called nameList
var nameList = names.split(pattern);
// new pattern: one or more characters then spaces then characters.
// Use parentheses to "memorize" portions of the pattern.
// The memorized portions are referred to later.
pattern = /(\w+)\s+(\w+)/;
// Below is the new array for holding names being processed.
var bySurnameList = [];
// Display the name array and populate the new array
// with comma-separated names, last first.
//
// The replace method removes anything matching the pattern
// and replaces it with the memorized string—the second memorized portion
// followed by a comma, a space and the first memorized portion.
//
// The variables $1 and $2 refer to the portions
// memorized while matching the pattern.
output.push('---------- After Split by Regular Expression');
var i, len;
for (i = 0, len = nameList.length; i < len; i++) {
output.push(nameList[i]);
bySurnameList[i] = nameList[i].replace(pattern, '$2, $1');
}
// Display the new array.
output.push('---------- Names Reversed');
for (i = 0, len = bySurnameList.length; i < len; i++) {
output.push(bySurnameList[i]);
}
// Sort by last name, then display the sorted array.
bySurnameList.sort();
output.push('---------- Sorted');
for (i = 0, len = bySurnameList.length; i < len; i++) {
output.push(bySurnameList[i]);
}
output.push('---------- End');
console.log(output.join('\n'));
استخدام الرموز الخاصة للتحقق من صحة المدخلات.
في المثال التالي، يتوقع من المستخدم ادخال رقم الهاتف. عندما سينقر المستخدم على زر "الفحص" سيقوم السكريبت بفحص صحة الرقم. اذا كان الرقم صحيحا، سيقوم السكريبت باظهار رسالة تشكر المستخدم وتظهر الرقم المدخل. اذا كان الرقم غير صحيح، سيقوم السكريبت باخبار المستخدم بان الرقم المدخل غير صحيح.
بعد non-capturing parentheses (?:
سينظر الريجكس الى الثلاثة ارقام \d{3}
او |
الى القوس اليساري \(
متبوعا بثلاثة ارقام \d{3}
متبوعة بقوس الاغلاق \)
, (نهاية non-capturing parenthesis )
)، متبوعة بشرطة واحدة تليها الباكسلاش او النقطة الكسرية، اذا وجدت قم بفهرستها ([-\/\.])
، متبوعة بثلاث ارقام \d{3}
، متبوعة باستدعاء الجزء المفهرس \1
, متبوعا باربعة ارقام \d{4}
.
يتم تنشيط حدث التغيير عندما يقوم المستخدم بالضغط على إنتر وملأ القيمة RegExp.input
.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<script type="text/javascript">
var re = /(?:\d{3}|\(\d{3}\))([-\/\.])\d{3}\1\d{4}/;
function testInfo(phoneInput) {
var OK = re.exec(phoneInput.value);
if (!OK)
window.alert(phoneInput.value + ' isn\'t a phone number with area code!');
else
window.alert('Thanks, your phone number is ' + OK[0]);
}
</script>
</head>
<body>
<p>Enter your phone number (with area code) and then click "Check".
<br>The expected format is like ###-###-####.</p>
<form action="#">
<input id="phone"><button onclick="testInfo(document.getElementById('phone'));">Check</button>
</form>
</body>
</html>