نقلا عن الأخ الغملاسي : الموضوع
==========================================================
السلام عليكم
الدرس الحادي عشر والأخير : System.Text.RegularExpressions
مدة الدرس 30 دقيقة .
في الدرس الأخير يتوجب علينا توظيف القوالب والسلوكيات المتوفرة في VB.NET لتكون خاتمة لهذه السلسلة المتواضعه
فسنستهل حديثنا عن القالب Capture Class وهو يقوم بما تقوم به الأداة $ التي تم التطرق لها في الدرس الثامن
وهي عملية حفظ ما تطابق في المجموعة Group , إلا أنه يمتلك إلى خصائص وسلوكان تمكننا بسهولة التعامل مع المجموعات وقيمها.
كل خصائص هذا القالب هي من نوع Read only للقراءة فقط .
يتوجب علينا لتعريف القالب أن نقوم بتعريف مجموعة من نفس النوع وتعرف بـ CaptureCollection وهي كذلك قالب
مستقل بذاته . لنفترض أن لدينا نص بهذا الشكل
one = 1 two = 2 و نريد أن نعرف القيم التي تطابقت من خلال هذه الصيغة وهي
string RX = "(?<1>\d+)\s*;" لنكتب المثال بهذا الشكل
txt2.Text = "one = 1 two = 2";
string RX = "(?<1>\\d+)\\s*";
Regex r = new Regex(RX, RegexOptions.IgnoreCase);
Match m = r.Match(txt2.Text);
while (m.Success) {
CaptureCollection cc = m.Captures;
Capture c;
foreach (int c in cc) {
txt3.Text += c.Value();
}
m = m.NextMatch();
}سيكون الناتج هو 1 و 2 لأننا نبحث عن تطابق أرقام فقط لا كلمات .
يتبين لنا من خلال هذا المثال البسيط أن الفائدة من القالب Capture هو معرفة ما تطابق
من الصيغة وهذا مفيد و مهم جداً لفهم آلية Regex ولمعرفة التطابق بشكل أغزر و أعمق .
القالب Group وهي المجموعة و لها Collection كقالب تعرف بـ GroupCollection
نستطيع اللف فيها و إظهار قيم المجموعات , كذلك نستطيع أن نظهر قيمة مجموعة
دون إستخدام الـ GroupCollection بأن نقوم بالتعامل مع العنصر Match مباشرتاً بهذا الشكل
txt2.Text = "one=1 two=2"; string RX = "\\w+=(\\d)\\s\\w+=(\\d)"; Regex r = new Regex(RX, RegexOptions.IgnoreCase); Match m = r.Match(txt2.Text); Group g1 = m.Groups(1); Group g2 = m.Groups(2); txt3.Text = "Group 1 is: " + g1.ToString + "\r\n"; txt3.Text += "Group 2 is: " + g2.ToString;
سيكون الناتج في المجموعة الأول القيمة 1 و الثانية القيمة 2
الفائدة القصوى من هذا القالب معرفة قيمة مجموعة معينه كمثلاً المجموعة الأولى أو الثانية
ولهذا يتبين أن الفارق بينه وبين القالب Capture انه يمكن أن يكون خاص و مقيد
بينا Capture هو عام و مطلق .
القالب Match وله كذلك مجموعة تعرف بـ MatchCollection
نستطيع بهذا القالب معرفة هل تم التطابق من عدمه
كذلك نستطيع به أن نقوم بتكرار المطابقة , كما توضح لنا النصوص البرمجية التالية
Match m;
Regex rx = new Regex(str2);
int Counter;
Result = string.Empty;
m = rx.Match(txt2.Text);
while (m.Success) {
Result += m.Value.ToString + ControlChars.CrLf;
Counter += 1;
m = m.NextMatch;
}
this.txt3.Text = Result + "\r\n" + " There are " + Counter + " HTML Tags Founded ";التحليل
الخاصية Success ترجع لنا قيمة منطقية أما True أو False وبها
نستطيع معرفة التطابق .
السلوك NextMatch يمكننا من تكرار المطابقة .
كذلك هنالك ما يعرف بـ MatchEvaluator Delegate وهو معلوم لدى الجميع أنه عبارة
عن Function يتم مناداتهِ كلما وقع حدث معين , هذا الـ Delegate مخصص لعملية الإستبدال
Replace , و يتم إستخدامه على النحو التالي
string Str;
string StrRX;
private object Str = "Arab_Team_Group";
private object StrRX = "_";
Regex rx = new Regex(StrRX);
MatchEvaluator EVl = new MatchEvaluator(/* might be wrong, please check */ new EventHandler(ReplaceUnderScore));
private object Str = rx.Replace(Str, EVl);
private object MsgBox;
public string ReplaceUnderScore(Match m)
{
return " ";
}التحليل
أولاً لدينا نص بهذا الشكل Arab_Team_Group
ونريد حذف الـ underscore _ قمنا بتعريف MatchEvaluator
و أسندنا له الإجراء ReplaceUnderScore ليقوم بحذف الـ underscore كلما وجدت عن
طريق الوظيفة Replace بهذا الشكل Str = rx.Replace(Str, EVl)
كذلك نستطيع بدل هذه القصة كلها أن نقوم بالتالي فقط Str = rx.Replace(Str, " ")
ولا نحتاج إلى Delegate لإكمال المهمة .
تكمن فائدة الـ Delegate في التنظيم والترتيب Code Separation And Code Documentation
كذلك نستطيع من خلاله بعمليات التحقق قبل الإستبدال أو وضع شروط وفقاً لقيم ما .
هنالك القالب Regex وهو معلوم لمن تابع هذه السلسلة كونه صميم العمل core
ويتم تعريفه على النحو التالي
string StrRX = "^\\d.*$"; Regex rx = new Regex(StrRX);
هذا القالب لابد أن نقوم بعملية إستنساخ منه بإستخدام الكلمة المحجوزة New ثم أما أن نضع الـ Pattern مباشرةً أو
أن نضع متغير يحوي هذه الصيغة أو الـ Pattern
أو يتم تعريف هذا القالب مع إحدى قيم RegexOptions وهي عبارة عن Enumeration اي قيم معدودة و محصورة .
بهذا الشكل
private object rx = new Regex(str5, RegexOptions.None);
خصائص وسلوكيات Regex كالتالي
أولاً القالب Match يقبل النص المراد الإختبار عليه كممرر argument ويعود بقيمة من نوع قالب match
يتم إستخدامه بهذ الشكل
Result = string.Empty;
Match m;
Regex rx = new Regex("Color");
m = rx.Match("What is your Favorite Colour or Color ?");
Result = m.Value.ToString;
this.txt3.Text = Result;الوظيفة IsMatch تقبل النص المراد الإختبار عليه كممرر argument و تعود بقيمة منطقية
اما True تم التطابق أو False فشل التطابق , تستخدم بهذا الشكل
Result = string.Empty;
Regex rx = new Regex("Color");
Result = rx.IsMatch("What is your Favorite Colour or Color ?");
this.txt3.Text = Result;القيمة العائدة في المتغير Result ستكون True وفقاً للمثال هذا .
ثم القالب MatchCollection ذكرنا في الأعلى وهذا مثال أخر عليها .
Result = string.Empty;
Match m;
MatchCollection mc;
Regex rx = new Regex("");
mc = rx.Matches("What is your Favorite Colour or Color ?", "Colou?r");
Result = "how many time Matchs called " + mc.Count;
this.txt3.Text = Result;النتيجة عدد مرات التطابق ستكون 2 .
وفي هذا القالب كذلك كل من GroupNameFromNumber و GroupNumberFromName لجلب اسماء أو أرقام
المجموعات في الصيغة , بهذا الشكل
txt2.Text = "a b";
string RX = "(?<Group1>A)";
Regex r = new Regex(RX, RegexOptions.IgnoreCase);
Match m = r.Match(txt2.Text);
Group g1 = m.Groups(1);
Group g2 = m.Groups(2);
txt3.Text = "Name of Group one is : " + r.GroupNameFromNumber(1).ToString + "\r\n";
txt3.Text += "The Position of Group1 is : " + r.GroupNumberFromName("Group1").ToString;و البقية تقريباً مررنا عليها من خلال الدروس .
القيم المعدودة هي كالتالي
RegexOptions.None وتعني أنه لا خيار محدد .
RegexOptions.Compiled وتعني أن الـ pattern
يترجم ككل وهذا يأخذ وقت في بدء التشغيل ولكنه أسرع
RegexOptions.CultureInvariant ويعني التعامل مع الـ pattern وفقاً للثقافة لبلدٍ ما.
وهي قيمة حساسة Case sensitive في الـ MSDN الكثير عنها للإطلاع .
RegexOptions.ECMAScript وهي والله أعلم من إسمها أنها تخص الـ J# لانه
ECMA منبع الـ jScript و الـ Action Script و تعني إستخدام نمط البرمجة على نحوها ونصوصها.
RegexOptions.ExplicitCapture وهي عملية إحكام على المجموعات بحيث يتم تجاهل اي مجموعة لا
تحوي اسم أو رقم يميزها عن بقية المجموعات الأخرى. شاهد المثال التالي
txt2.Text = "one=1 two=2"; string RX = "\\w+=(?<group1>\\d)\\s\\w+=(?<2>\\d)"; Regex r = new Regex(RX, RegexOptions.ExplicitCapture); Match m = r.Match(txt2.Text); Group g1 = m.Groups(1); Group g2 = m.Groups(2); txt3.Text = "Group 1 is: " + g1.ToString + "\r\n"; txt3.Text += "Group 2 is: " + g2.ToString;
النتيجة ستكون 1 & 2
RegexOptions.IgnoreCase هذه القيمة تقوم بتجاهل الحساسية Case sensitive بحيث
يقبل كل من الحروف الصغيرة والكبيرة ولا فرق بينهما من حيث المطابقة . شاهد المثال التالي
txt2.Text = "a b"; string RX = "(?<1>A)\\s(?<2>B)"; Regex r = new Regex(RX, RegexOptions.IgnoreCase); Match m = r.Match(txt2.Text); Group g1 = m.Groups(1); Group g2 = m.Groups(2); txt3.Text = "Group 1 is: " + g1.ToString + "\r\n"; txt3.Text += "Group 2 is: " + g2.ToString;
النتيجة ستكون a b رغم أن الـ pattern يحوي A B .
RegexOptions.IgnorePatternWhitespace تقوم بتجاهل الفراغات التي تتخلل ال pattern
كما تقوم بتمكين كتابة التعليقات خلال الصيغة بهذا الشكل
txt2.Text = "a b "; string RX = "(?<1>a)\\s(?<2>b)#here is letter b"; Regex r = new Regex(RX, RegexOptions.IgnorePatternWhitespace); Match m = r.Match(txt2.Text); Group g1 = m.Groups(1); Group g2 = m.Groups(2); txt3.Text = "Group 1 is: " + g1.ToString + "\r\n"; txt3.Text += "Group 2 is: " + g2.ToString;
الناتج a و b رغم أن بعد الحرف b يوجد فراغ ولكن تم تجاهله .
كذلك هنالك تعليق بعد المجموعة الثانية بإستخدام الـ #
RegexOptions.Multiline تقوم بتغير نمط ^ بحيث يصبح له معنىً أخر وهو مطابقة بداية النص أو كل مقطع في النص
وينوب عن الأداة (?m)
للمزيد راجع الدرس السادس , ومثاله كالتالي :
const string str3 = "^'.+$";
Match m;
Regex rx = new Regex(str3, RegexOptions.Multiline);
int Counter;
m = rx.Match(txt2.Text);
while (m.Success) {
Counter += 1;
m = m.NextMatch;
}
MessageBox.Show(" There are " + Counter + " Comments in this String ");RegexOptions.RightToLeft وتعني بدء المطابقة من اليمين إلى الشمال بالنسبة للنص المراد
إختبار المطابقة عليه وليس الصيغة بذاتها . مثال ذلك
Result = string.Empty;
Match m;
Regex rx;
if (whichString == 1) {
rx = new Regex(str1);
} else if (whichString == 2) {
rx = new Regex(str2, RegexOptions.RightToLeft);
}
m = rx.Match(this.txt2.Text);
Result = m.Value.ToString;
this.txt3.Text = Result;RegexOptions.Singleline وهي إرجاع معنى الـ ^ على اساس أنه يقوم بمطابقة أولا النص فقط
وهو عكس RegexOptions.Multiline تماماً وهو كذلك مقدم على الأداة (?m) بحيث لو تم تعريفها في
الصيغة ثم قمنا بإستخدام القيمة SingleLine سيتم إعتماده و تجاهل الأداة (?m) . مثالهُ كالتالي
const string str3 = "(?m)^'.+$";
Match m;
Regex rx = new Regex(str3, RegexOptions.Singleline);
int Counter;
m = rx.Match(txt2.Text);
while (m.Success) {
Counter += 1;
m = m.NextMatch;
}
MessageBox.Show(" There are " + Counter + " Comments in this String ");الناتج سيكون تم العثور على تعليق واحد فقط .
أخيراً القالب RegexCompilationInfo نستطيع به معرفة كل من
1. الصيغة ,اي شكل التركيبة المتضمنه فيها.
2. اسم يعنون للصيغة (من حيث الترتيب والتنسيق)
3. هل هو عام أو خاص عن طريق القيمة الأخيرة من هذا القالب أما True أو False
4. معرفة اسم الحاوية NameSpace إذا كنت تضع الصيغ مرتبة في حاويات
5. معرفة نوع الخيار Options الذي يتضمن هذه الصيغة مثل SingleLine أو غير ذلك .
شاهد المثال التالي .
RegexCompilationInfo rxInfo = new RegexCompilationInfo("^\\d+$", RegexOptions.Singleline, "CheckNumber", "myNameSpace", true);
MsgBox(rxInfo.Pattern.ToString());
MsgBox(rxInfo.Name.ToString());
MsgBox(rxInfo.IsPublic.ToString());
MsgBox(rxInfo.Namespace.ToString());
MsgBox(rxInfo.Options.ToString());أجوبت الدروس السابقة
الدرس الثاني :
وهنا سؤال يطرح نفسه : في ماذا يستخدم Regex الأداة \ Backslash ؟
يستخدم الـ escaping backslash \ أما لأخطار Regex بأن هذه القيمة نصية وليست أداة أو أن هذا الحرف
أداة وليس حرف فمثلاً \. يراد بها النقطة و . يراد بها خانة واحدة
كذلك \d يراد بها رقم من صفر إلى تسعة و d يراد به حرف الـ d نفسه .
الدرس الثالث :
السؤال الأول : قم ببناء صغية لا تقبل الرقم سبعة 7
[^7]
السؤال الثاني : لو بنينا صيغة بهذا الشكل [A-z]
إضافة إلى الأحرف الكبيرة والصغيرة سيكون كل من [ \ ] ^ _ `
السؤال الثالث والأخير : قم ببناء صغية لا تقبل المسافة , وفقاً لما تعلمناه
Const str1 As String = "^[^ ]$"
الدرس الرابع :
سؤال هذا الدرس : أكتب الصيغة المناسبة لمطابقة القيمة التالية خانة تقبل من واحد إلى عشرة على واحد إلى عشرة
لا تقبل الصفر ولا يمكن أن تكون فارغة . مثلاً 1\10 لكن ليس 0\1 أو Null
"^([1-9]|10)\\([1-9]|10)$"
الدرس الخامس :
1 - yes
2 - yes
3 - yes
4 - No it means single digit or + character
5 - No it's limited to 249 only
6 - No it means single digit and {}
الدرس السادس :
ما هي الأخطاء المرتكبة في هذه التركيبة النصية
const string str3 = "\\A'.+\\Z";
private void Button3_Click(object sender, System.EventArgs e)
{
Match m;
Regex rx = new Regex(str3, RegexOptions.Singleline);
int Counter;
m = rx.Match(txt2.Text);
while (m.Success) {
Counter += 1;
m = m.NextMatch;
}
MessageBox.Show(" There are " + Counter + " Comments in this String ");
}الجواب : لا توجد أخطاء مرتكبة في الصيغة .
الدرس السابع :
1 - ^([1-9]{1,2}-){2}[1-9]{1,2}$
2 - ^([1-9]{1,2}-){5}[1-9]{1,2}$ or ^(([1-9]{1,2}-){2}){2}[1-9]{1,2}$
3 - Match the () characters
4 - Wrong Pattren because if you not use ^ at the beginning of the pattren then it means as the repeator tool
for instance ^[1-9]^2$ means repeat digit twice from 1 to 9 matches 11 22 and etc... this concept
does not impact on VB.NET , While Does on Other languages , so What does this pattren mean ?
In VB.NET the ^ tool has several meaning one it matchs the begining of the string or negates mean
if enclosed within [] , so whereas both of them not used then it has wrong meaning
and it acts as the begining Tool in the wrong position. God knows.
الدرس الثامن :
1 - No we use \2
2 - No we either write ?<Nums> or ?'Nums'
3 - No we refer to the Group name by single Qutation 'myGroup'
4 - NO After Starting ( Group
5 - NO we don't need Back Reference
6 - No we use $3
7 - <a([1-6])>.*?</a\1>
الدرس التاسع :
question 1 Answer 3
question 2 Answer 2
question 3 Answer 1
question 4 Answer (?<=<a[1|2|3|4]>).+(?=</a[1|2|3|4]>)
question 5 Answer ^\d{5,6}|(\d{1,6}(?=-)-\d{4})
الدرس العاشر :
Question 1 Answer Wrong the Correct Pattren is (r|h|s)ide
Question 2 Answer Wrong the Correct Pattren is (my|by)
Question 3 Answer Wrong it's Correct pattren with Group and gives Expected Result
Question 4 Answer Wrong it looks for the word Color, RightToLeft Doesn't effect on Pattrens
it effects on the text that the Regex from where it begins to matchs.
Question 5 Answer Wrong the Correct Conditions Tools are ? and |
Question 6 Answer Wrong the Correct Pattren is (my name is :?)
لا توجد أسئلة في هذا الدرس والله يوفقكم لما فيه الخيرو البركة
السلام عليكم .