This article is available in English too, check it out here.
المحتويات
محتويات هذا الموضوع:
- المحتويات
- نظرة خاطفة
- مقدمة
- دعم نظام التشغيل
- معالجة النصوص
- مقارنة النصوص
- خاتمة
نظرة خاطفة
يركز هذا الدرس على عملية معالجة النصوص String Processing التي تحتوي على علامات وحروف معينة مثل علامات التشكيل في اللغة العربية أو بعض العلامات مثل الموجودة في الألمانية أو العبرية التي يمكن دمجها مع الحروف. وبما أن هذا الدرس يتكلم باللغة العربية فسوف تكون أمثلتنا على حروف وكلمات عربية.
مقدمة
في بعض اللغات مثل العربية، العبرية، والألمانية يمكن دمج بعض الحروف مع الحرف الأصلي إشارة إلى طريقة معينة للنطق بهذا الحرف. فمثلا يمكنك دمج الضمتان مع كلمة “محمدٌ” إشارة إلى أن هذا الكلمة مرفوعة ويجب أن تنطق بطريقة معينة.
ويسمى الحرف الأول الذي تمدج معه هذه العلامات أو التشكيلات يسمى الحرف الأصلي Base Character. أما أي علامة آخر تدمج معه فتسمى الحرف المدموج Combining Character. ويمكن دمج أكثر من حرف مع بعض. فيمكننا مثلا دمج الشدة والفتحة على حرف الميم الثاني في “محمَّد” وبهذا بدلا من أن تصبح الكلمة ثلاثة حروف خالصة، يصبح الحرف الثالث مؤلف من الحرف الأصلي وحرفي دمج. ويمكننا تشكيل الكلمة تشكيلا كاملا فتصبح مثلا “مُحَمَّـدٌ”.
وكما نعرف كل حرف يظهر على الشاشة له كود (ترميز) ANSI معين. فمثلا الحرف A له الكود 65 أو 0x41 بالترميز الست-عشري. ومثل الحروف الأصلية، فالعلامات أيضا كل علامة لها رمز أو كود معين.
دعم نظام التشغيل
يقدم نظام التشغيل الكثير من الدعم لعلامات التشكيل في اللغة العربية. الجدول التالي يوضح أهم الحروف والعلامات، الرموز الخاصة بها، واختصارات لوحة المفاتيح المستخدمه لكتابتها.
الترميز | العلامة | الاسم | الاختصار |
0x064B | ![]() |
فتحتان | Shift + W |
0x064C | ![]() |
ضمتان | Shift + R |
0x064D | ![]() |
كسرتان | Shift + S |
0x064E | ![]() |
فتحة | Shift + Q |
0x064F | ![]() |
ضمة | Shift + E |
0x0650 | ![]() |
كسرة | Shift + A |
0x0651 | ![]() |
شدة | Shift + ~ |
0x0652 | ![]() |
سكون | Shift + X |
بالإضافة إلى ذلك يوفر نظام التشغيل أداة متميزة جدا تقوم بعرض جميع الحروف الموجودة في جدول ANSI بالخط الذي اختاره المستخدم. فيمكنك من خلالها إضافة أي حروف أو علامات ربما تكون غير موجودة في لوحة مفاتيحك. كما يمكنك أيضا مراجعة الأكواد والترميز الخاص بهذه الحروف ومعرفة العلاقات التي تربطها.
وهذه الأداة تسمى خريطة الأحرف Character Map. ويمكن تشغيلها بطريقتين:
- عن طريق Start->Programs->Accessories->System Tools->Character Map.
- أو عن طريق كتابة الأمر charmap.exe في أمر التشغيل Run.
وهذه لقطة من البرنامج:

معالجة النصوص
ماذا لو كان النص الذي أدخله المستخدم يحوي أحد أو بعض هذه الأحرف؟ كيف سيتم التعامل معه برمجيا؟ مما فهمناه في المقدمة فعلامات التشكيل هي حروف منفردة ولكنها تظهر فوق الحرف الأصلي الواقع قبلها. إذا فكلمة “محمد” تختلف كثيرا عن “مُحمد”، فالأولى أربعة أحرف أما الثانية فهي خمسة!
ولكن هل هذا ما نريده حقا؟ ماذا عن المشاكل الواقعة من أحد أخطاء المستخدم في كتابة اسمه أو أحد البيانات الخاصة به؟
الحل بسيط جدا! بداية نأخذ اسم نبينا العدنان محمد -صلى الله عليه وسلم- ونقوم بتشكيله فقط بضمة فوق الميم الأولى وبشدة وفتحة فوق الميم الأخرى، لتصبح الكلمة حقيقة عبارة عن هذه السلسلة من الأحرف (على الترتيب):
- ميم
- ضمة
- حا
- ميم
- شدة
- فتحة
- دال
ولكنها مجازا عبارة عن أربعة أحرف فقط (على الترتيب):
- ميم مضمومة
- حا
- ميم مشددة بالفتح
- دال
إذا فالمطلوب الآن وضع تحليلان برمجيا لهذه الكلمة، أحدهما يقوم بسرد حروفها حقيقة فتصبح سبعة أحرف، والآخر يقوم بسردها مجازا فتصبح أربعة أحرف فقط. وسنبدأ بالأول.
الكود التالي يقوم بسرد النص بالطريقة المعروفة والتي تسفر عن فك الأحرف المدموجة لتصبح الكلمة سبعة أحرف:
// C# string name = "مُحمَّد"; string result = String.Empty; for (int i = 0; i < name.Length; i++) result += String.Format("{0}t{1}b", i, name(i)); MessageBox.Show(result);
' VB.NET Dim name As String = "مُحمَّد" Dim result As String = String.Empty For i As Integer = 0 To name.Length - 1 result &= String.Format("{0}{1}{2}{3}", i, vbTab, name(i), vbNewLine) Next MessageBox.Show(result)
والآن إلى النقطة الأكثر إثارة وهي سرد الحروف بدون فكها لتكون الكلمة في المثال معنا هي أربعة أحرف فقط. ويتم ذلك عن طريق التصنيفان TextElementEnumerator و StringInfo والموجودان في الـ Namespace المسمى System.Globalization.
بعد إضافة System.Globalization إلى قائمة الـ Namespaces المستخدمة في البرنامج باستخدام جملة using في C# أو Imports في VB.NET يمكنك استخدام الكود التالي لسرد حروف الكلمة بدون فك الدمج فتصبح أربعة أحرف فقط:
// C# string name = "مُحمَّد"; string result = String.Empty; TextElementEnumerator enumerator = StringInfo.GetTextElementEnumerator(name); while (enumerator.MoveNext()) result += String.Format("{0}t{1}b", enumerator.ElementIndex, enumerator.Current); MessageBox.Show(result);
' VB.NET Dim name As String = "مُحمَّد" Dim result As String = String.Empty Dim enumerator As TextElementEnumerator = _ StringInfo.GetTextElementEnumerator(name) While enumerator.MoveNext() result &= String.Format("{0}{1}{2}{3}", _ enumerator.ElementIndex, vbTab, _ enumerator.Current, vbNewLine) End While MessageBox.Show(result)
نلاحظ أنه رغم مراعاة عدم فك الأحرف تم مراعاة مكان كل حرف أي الـ Index الخاص به.
مقارنة النصوص
ماذا عن مقارنة نص بدون حروف مدموجة بنص آخر بحروف مدموجة مثلا مقارنة “محمد” بـ “مُحمَّد”؟ رغم أن النصوص متماثلة والفرق فقط هو في التشكيل، فإن الكود لا يعلم ذلك هو فقط يعلم أن النص الأول هو أربعة أحرف والآخر هو سبعة أحرف وبالتالي فالفرق واضح.
هل نقوم باستخدام الكود السابق لمقارنة كل حرف على حدة؟ سوف تكون العملية مرهقة وفي الغالب ستحدث العديد من الأخطاء. إذا ما هو الحل؟ الحل هو في استخدام أحد النسخ من الأمر String.Compare والذي يمكننا من تحديد الأوامر الخاصة بالنصوص المدموجة.
هيا بنا نستكشف الكود التالي والذي يقوم بعقد مقارنات بين النصوص بثلاث طرق مختلفة (لاحظ أن الطريقة الأولى والثانية في الحقيقة متماثلتان):
// C# string name1 = "محمد"; string name2 = "مُحمَّد"; // الطريقة الأولى if (name1 == name2) MessageBox.Show("النصوص متماثلة"); else MessageBox.Show("النصوص مختلفة"); // الطريقة الثانية if (String.Compare(name1, name2) == 0) MessageBox.Show("النصوص متماثلة"); else MessageBox.Show("النصوص مختلفة"); // الطريقة الثالثة والجديدة if (String.Compare(name1, name2, System.Threading.Thread.CurrentThread.CurrentCulture, CompareOptions.IgnoreSymbols) == 0) MessageBox.Show("النصوص متماثلة"); else MessageBox.Show("النصوص مختلفة");
' VB.NET Dim name1 As String = "محمد" Dim name2 As String = "مُحمَّد" ' الطريقة الأولى If (name1 = name2) Then MessageBox.Show("النصوص متماثلة") Else MessageBox.Show("النصوص مختلفة") End If ' الطريقة الثانية If (String.Compare(name1, name2) = 0) Then MessageBox.Show("النصوص متماثلة") Else MessageBox.Show("النصوص مختلفة") End If ' الطريقة الثالثة والجديدة If (String.Compare(name1, name2, _ System.Threading.Thread.CurrentThread.CurrentCulture, _ CompareOptions.IgnoreSymbols) = 0) Then MessageBox.Show("النصوص متماثلة") Else MessageBox.Show("النصوص مختلفة") End If
نلاحظ فشل الطريقة الأولى والثانية بينما نجحت الطريقة الأخيرة.
إذا ما هو هذا السحر الذي قام به الأمر System.Globalization.CompareOptions.IgnoreSymbols؟ يقوم هذا الأمر CompareOptions.IgnoreSymbols بتجاهل أي علامات Symbols غير الحروف.
وللأسف لا يمكننا الاعتماد بشكل أساسي على هذا الأمر فهو يقوم بتجاهل جميع العلامات مثل المسافات وعلامات التنصيص والنسبة المئوية وغيرها!!! لهذا فالنص “محمد الشيمي” هو بالنسبة له مماثل تماما لـ “محمدالشيمي” بدون المسافة الفاصلة!
خاتمة
كان هذا عرض سريع وموجز لفكرة التعامل مع علامات التشكيل ونحوها برمجيا. ونترك باقي الأفكار والحلول لفكر القارئ ولبحثه. ونرجوا أن نكون قد وفقنا في عرض الموضوع.
مجهود اكثر من رائع من رجل يستحق التقدير
إعجابإعجاب
🙂
إعجابإعجاب
مجهود اكثر من رائع من رجل يستحق التقدير
إعجابإعجاب
🙂
إعجابإعجاب
هذا الموضوع جميل جدًا 🙂
قد يفيد في المقارنة بينالنصوص بغض النظر عن التشكيل
كما قد يفيد في إزالة التشكيل وتزيين الأسماء وعناوين المواضيع في المواقع التي يضيفها الكتاب
وأيضًا قد يفيد في عمل خدمة تنافس خدمة جوجل تشكيل ^__^
شكرًا لك
إعجابإعجاب
نعم، برغم أن هذه الطريقة طريقة بدائية جدا إلا أنها توضح الفكرة والمفهوم العام وهذا ما قصدته من هذا الموضوع. وبإذن الله في مواضيع قادمة سوف نتطرق إلى مواضيع وأفكار أبعد من ذلك وسنتحدث بتفصيل أكثر عن تقنيات معالجة النصوص.
إعجابإعجاب
جزاك الله كل خير يا هندسه علي المدونة المميزة دي 🙂
إعجابإعجاب
جزاكم الله خيرا! 🙂
إعجابإعجاب
بجد الله ينور
إعجابإعجاب
بارك الله فيك
وأتمنى لو كان الموضوع يشمل اعادة قيمة الأحرف المشبوكة التي تظهر لنا لأي نص يتم إدخالة بناء على فونت معين
مثلا إذا أدخلت كلمة
“ثم”
للخط Traditional Arabic
يعيد لي أنه رمز واحد وهو U+FC12
لأنه الحرفين يظهر بشكل رمز واحد لأنهما من الحروف المركبة
تحياتي
إعجابإعجاب