All guides
No guide matches your search.
أدوات النصوص
تطبيع النصوص الفارسية والعربية، وإصلاح نصف المسافة، والكشف عن اللغة والاتجاه، وبناء المعرّفات النصية الصالحة للروابط، مع السلوك الدقيق وحالات الحافة لكل أداة.
On this page
Normalizer
UTF-8 غير صالح
تستبدل normalize() وfixHalfSpace() وclean() أولًا كل بايت ليس جزءًا من تسلسل UTF-8 صالح بالمحرف U+FFFD (محرف الاستبدال)، ثم تطبّق كل خطواتها. والناتج دائمًا UTF-8 صالح، ولا حاجة إلى إضافة مثل mbstring.
يجعل الصنف RtlyKit\Text\Normalizer النص الفارسي قابلًا للمقارنة والتخزين. فمدخلات المستخدمين تخلط بين أشكال الحروف العربية والفارسية (لوحة المفاتيح العربية تكتب «ي» و«ك»)، وتتضمن حركات وتطويلًا ومسافات زائدة؛ فتبدو الكلمة نفسها متطابقة على الشاشة لكنها تفشل في مقارنة السلاسل أو في البحث في قاعدة البيانات.
normalize()
تفعل Normalizer::normalize($text, $removeDiacritics = true) ما يلي:
- تتحول الحروف العربية إلى نظيراتها الفارسية: «ك» إلى «ک»، و«ي» «ى» «ے» إلى «ی»، و«ة» «ۀ» إلى «ه»، و«ؤ» إلى «و»، و«إ» «أ» «ٱ» إلى «ا».
- تتحول الأرقام العربية الهندية (
٠-٩) إلى أرقام فارسية (۰-۹). أما الأرقام الإنجليزية فتُترك كما هي. - يُحذف التطويل (tatweel، المحرف U+0640).
- تُحذف الحركات، أي علامات الحركات القصيرة (من U+064B إلى U+065F وU+0670)، إلا إذا مرّرت
falseوسيطًا ثانيًا. - تُختزل سلاسل المسافات البيضاء (المسافات والجداول والأسطر الجديدة) إلى مسافة واحدة، وتُقصّ الأطراف.
<?php
require 'vendor/autoload.php';
use RtlyKit\Text\Normalizer;
use function RtlyKit\normalize_text;
echo Normalizer::normalize("علي كتاب ١٢٣ 456"), "\n"; // علی کتاب ۱۲۳ 456
echo Normalizer::normalize("كــتاب"), "\n"; // کتاب
echo Normalizer::normalize(" سلام \n\t دنیا "), "\n"; // سلام دنیا
echo Normalizer::normalize("أحمد إبراهيم مؤمن ة"), "\n"; // احمد ابراهیم مومن ه
echo Normalizer::normalize("ثَبْت ١٢٣ 456"), "\n"; // ثبت ۱۲۳ 456
echo Normalizer::normalize("ثَبْت", false), "\n"; // ثَبْت (تبقى الحركات)
echo normalize_text('كتاب'), "\n"; // کتابما تتركه كما هو. الهمزة المنفردة «ء» و«ئ» تُترك عمدًا دون مساس، لأن لهما معنى في الكلمات الفارسية والعربية. ونصف المسافة (ZWNJ) يُحفظ: فتخرج «میخواهم» مطابقة بايتًا ببايت. والحروف الإنجليزية لا تتغير.
تستدعي الدالة المساعدة normalize_text() الدالة Normalizer::normalize() بالقيم الافتراضية.
fixHalfSpace()
نصف المسافة (ZWNJ، U+200C) هو ما يجعل «میخواهم» تظهر صحيحة. وكثيرًا ما يترك النسخ واللصق عدة منها متتالية، أو واحدة معلّقة بجوار مسافة أو في نهاية النص. تنظّف fixHalfSpace() ذلك:
- تُحذف الواصلات الناعمة (U+00AD).
- تُختزل سلسلة من محارف ZWNJ إلى واحد.
- يُحذف ZWNJ الواقع مباشرة قبل المسافة البيضاء أو بعدها.
- تُحذف محارف ZWNJ في بداية النص ونهايته تمامًا.
$a = "می\u{200C}\u{200C}\u{200C}خواهم";
echo preg_match_all('/./u', $a), ' ', preg_match_all('/./u', Normalizer::fixHalfSpace($a)), "\n"; // 10 8
$b = "\u{200C}سلام \u{200C}دنیا\u{200C}";
echo preg_match_all('/./u', $b), ' ', preg_match_all('/./u', Normalizer::fixHalfSpace($b)), "\n"; // 12 9
echo Normalizer::fixHalfSpace($b), "\n"; // سلام دنیالا تُدرج أنصاف المسافات الناقصة، ولا تختزل المسافات العادية.
clean()
الدالة Normalizer::clean() هي النسخة الشاملة للتخزين والبحث. تحذف أولًا المحارف الخفية: المسافة ذات العرض الصفري (U+200B) ووصلة العرض الصفري (U+200D) وعلامة ترتيب البايت (U+FEFF)، ثم تشغّل normalize() وfixHalfSpace()، وتضم المسافات البيضاء مرة أخيرة. ويبقى ZWNJ المحرف الوحيد ذو العرض الصفري الذي يُحتفظ به.
$c = "كتاب\u{200B}ي ١٢٣";
echo Normalizer::clean($c), "\n"; // کتابی ۱۲۳أما تطبيق normalize() وحدها على النص نفسه فكان سيترك المسافة ذات العرض الصفري داخل الكلمة، ولهذا وُجدت clean(). استخدمها قبل تخزين النصوص التي يدخلها المستخدمون أو فهرستها.
Detector
يجيب RtlyKit\Text\Detector عن أسئلة الكتابة (script) واللغة والاتجاه. كل دوالّه ساكنة (static) ولا تُطلق استثناءً أبدًا. ويُعامَل UTF-8 غير الصالح كما في Normalizer: يصبح كل بايت سيئ U+FFFD، وهو محرف محايد ليس حرفًا ولا من اليمين إلى اليسار، فيتوقف الجواب على الجزء الصالح من النص فقط. وعلامة ترتيب البايت (U+FEFF) لا تُعدّ محرفًا من اليمين إلى اليسار.
isPersian() و isArabic()
كلتاهما استدلال تقريبي (heuristic) للنص المكتوب بالخط العربي. تُعرف الفارسية من الحروف الموجودة في الفارسية وحدها (پ چ ژ گ، والشكلان الفارسيان ک وی، والأرقام الفارسية). وتُعرف العربية من ي ك ى ة والأرقام العربية الهندية. أما الحروف المشتركة بين اللغتين، ومنها «ه» وصور الهمزة، فلا تُحتسب. ويُعدّ النص فارسيًا عندما تكون الحروف الفارسية الخالصة بتكرار لا يقل عن الحروف العربية الخالصة، فحالات التعادل والنصوص التي لا تحوي حروفًا مميِّزة تُعدّ فارسية.
use RtlyKit\Text\Detector;
var_dump(Detector::isPersian('سلام')); // bool(true)، لا حروف مميِّزة، فارسية افتراضياً
var_dump(Detector::isPersian('گچپژ')); // bool(true)
var_dump(Detector::isArabic('مرحبا بكم')); // bool(true)
var_dump(Detector::isArabic('كتاب ي')); // bool(true)
var_dump(Detector::isPersian('hello')); // bool(false)، لا خط عربي إطلاقاً
var_dump(Detector::isPersian('۱۲۳')); // bool(true)، أرقام فارسية
var_dump(Detector::isArabic('٣٤٥')); // bool(true)، أرقام عربية هندية
var_dump(Detector::isPersian('')); // bool(false)من المفيد أن تعرف. هذه الدوال تستدل على اللغة من تكرار الحروف، وليست محدِّدًا دقيقًا للغة. فالنصوص القصيرة جدًا والأسماء والكلمات العربية المكتوبة داخل نص فارسي قد تكون ملتبسة، والنص الذي يخلط العربية بالفارسية قد يميل إلى أيٍّ منهما. استخدمها لاختيار قيمة افتراضية معقولة، لا لقرار يجب أن يكون صحيحًا دائمًا.
الاتجاه و RTL
containsRtl($text): هل يحتوي النص على أي محرف من خط يُكتب من اليمين إلى اليسار (العبرية والعربية وملحقاتها والسريانية والتانا وN'Ko وغيرها، وأشكال العرض العربية) أو أحد عناصر التحكم الصريحة من اليمين إلى اليسار: RLM (U+200F) وRLE (U+202B) وRLO (U+202E) وRLI (U+2067). ولا تحسبdirection()هذه العناصر: فهي تنظر إلى أول حرف فقط.direction($text): تُرجع'rtl'أو'ltr'بحسب أول حرف قوي ، وفق قاعدة Unicode للنص ثنائي الاتجاه. الأرقام وعلامات الترقيم والمسافات محايدة. والنص الذي لا يحوي حروفًا يُرجع'ltr'. وتعامل الخطوط نفسها التي تعاملهاcontainsRtl()على أنها من اليمين إلى اليسار، ومنها خطوط تاريخية مثل الفينيقي والأفستي والنبطي.isHebrew($text): هل يحتوي النص على حروف عبرية.
var_dump(Detector::containsRtl('abc')); // bool(false)
echo Detector::direction('سلام hello'), "\n"; // rtl
echo Detector::direction('Hello مرحبا'), "\n"; // ltr (الحرف الأول لاتيني)
echo Detector::direction('۱۲۳'), "\n"; // ltr (الأرقام محايدة ولا يوجد حرف)
var_dump(Detector::isHebrew('שלום')); // bool(true)تغلّف الدالتان المساعدتان contains_rtl() وtext_direction() الدالتين containsRtl() وdirection(). استخدم direction() للسمة dir في HTML على النصوص التي ينشئها المستخدمون.
isRtlLocale()
تخبرك isRtlLocale($locale) إن كان وسم اللغة المحلية (locale) يُكتب من اليمين إلى اليسار. تقسّم الوسم عند - و_ (ويُهمل اللاحق مثل .UTF-8 أو @euro)، وتتجاهل حالة الأحرف والمسافات المحيطة. ويحسم الوسم الفرعي للخط من أربعة أحرف: فـ Arab وHebr وسائر الخطوط التي تُكتب من اليمين إلى اليسار تعطي true، وأي خط آخر يعطي false حتى مع لغة تُكتب من اليمين إلى اليسار (fa-Latn وar-Latn وsd-Deva قيمها false). وبلا وسم للخط تحسم اللغة: fa وar وhe وur وps وug وdv وckb وazb وغيرها تعطي true.
var_dump(Detector::isRtlLocale('fa_IR')); // bool(true)
var_dump(Detector::isRtlLocale('ar-SA')); // bool(true)
var_dump(Detector::isRtlLocale('ckb-IQ')); // bool(true)
var_dump(Detector::isRtlLocale('az-Arab')); // bool(true)، الوسم الفرعي للخط هو الحاسم
var_dump(Detector::isRtlLocale('fa-Latn')); // bool(false)، الوسم الفرعي للخط هو الحاسم
var_dump(Detector::isRtlLocale('ku')); // bool(false)، "ku" وحدها ليست في قائمة اللغات RTL
var_dump(Detector::isRtlLocale('en')); // bool(false)
var_dump(Detector::isRtlLocale('')); // bool(false)Slugify
تحوّل Slugify::make($text, $separator = '-') العنوان إلى معرّف نصي (slug) ملائم للروابط مع إبقاء الحروف الفارسية والعربية مقروءة. ولا تُجري أي نقحرة (transliteration) أبدًا.
- يُطبَّع النص بـ
Normalizer::normalize(). - تتحول المسافات البيضاء وأنصاف المسافات إلى الفاصل. ويُحذف أولًا المحرف U+0001 الحرفي إن وُجد في النص، فلا يعمل فاصلًا أبدًا.
- يُحذف كل شيء عدا الحروف (من أي خط) وعلامات الدمج والأرقام (من أي مجموعة) والواصلات والشرطات السفلية. وتختفي علامات الترقيم والرموز التعبيرية.
- تُختزل الواصلات والشرطات السفلية والفواصل المتكررة إلى واحد، وتُقصّ الفواصل من الطرفين. ويحدث هذا قبل إدخال نص الفاصل، فالنص الذي يساوي الفاصل أو يحتويه يبقى:
Slugify::make('maxx', 'x')تعطيmaxx. - تُحوَّل النتيجة إلى أحرف صغيرة بترميز UTF-8.
use RtlyKit\Text\Slugify;
echo Slugify::make('سلام دنیا'), "\n"; // سلام-دنیا
echo Slugify::make("کتاب\u{200C}خانه ملی"), "\n"; // کتاب-خانه-ملی
echo Slugify::make('Hello, World!'), "\n"; // hello-world
echo Slugify::make(' A--B__C '), "\n"; // a-b_c
echo Slugify::make('سلام!!! دنیا؟'), "\n"; // سلام-دنیا
echo Slugify::make('۱۲۳ ابر'), "\n"; // ۱۲۳-ابر
echo Slugify::make('كتاب ي'), "\n"; // کتاب-ی
echo Slugify::make('سلام 😀 دنیا'), "\n"; // سلام-دنیا
echo Slugify::make('عکس.jpg'), "\n"; // عکسjpg
var_dump(Slugify::make('$%^&')); // string(0) ""أمران يجب الانتباه إليهما. الأرقام الإنجليزية تبقى إنجليزية، أما الأرقام الفارسية والعربية الهندية فتصبح كلتاهما فارسية، فشغّل Digits::toEnglish() أولًا إن أردت أرقام ASCII في الروابط. والنقطة تُحذف ولا تُعامل فاصلاً، فتلتصق امتدادات الملفات باسمها (عکسjpg)؛ فأنشئ المعرّف النصي للاسم وللامتداد كلٍّ على حدة.
الفاصل
مرّر أي سلسلة وسيطًا ثانيًا: '_'، أو سلسلة أطول، أو سلسلة فارغة لضم الكلمات دون أي فاصل.
echo Slugify::make('سلام دنیا', '_'), "\n"; // سلام_دنیا
echo Slugify::make('سلام دنیا', ''), "\n"; // سلامدنیا
echo Slugify::make('Hello World', '--'), "\n"; // hello--worldالفاصل محدود بـ 64 بايت ويجب أن يكون UTF-8 صالحًا. والنص نفسه يجب أن يكون UTF-8 صالحًا كذلك. الفاصل الأطول من الحد يُثير RtlyKitException بالرمز input_too_long، وأي نص أو فاصل غير صالح يُثيره بالرمز invalid_argument (والسياق argument يقول أيهما):
try {
Slugify::make('Hello World', str_repeat('x', 65));
} catch (\RtlyKit\Exceptions\RtlyKitException $e) {
echo $e->getMessage(), ' [', $e->getErrorCode()->value, "]\n";
// The slug separator is too long. [input_too_long]
}
try {
Slugify::make("abc\xff");
} catch (\RtlyKit\Exceptions\RtlyKitException $e) {
echo $e->getMessage(), ' [', $e->getErrorCode()->value, "]\n";
// The text to slugify must be valid UTF-8. [invalid_argument]
}المعرّفات الفارغة والتفرّد. العنوان المكوَّن من علامات ترقيم فقط يُنتج سلسلة فارغة، وقد تُنتج عناوين مختلفة المعرّف النصي نفسه. عالج الحالة الفارغة (مثلًا بالرجوع إلى معرّف رقمي)، واطلب التفرّد في طبقة التخزين لديك.
الترميز. تحتاج Slugify إلى UTF-8 صالح في النص وفي الفاصل معًا. والبايتات غير الصالحة في النص تُثير RtlyKitException بالرمز invalid_argument، لأن المعرّف النصي مُعرِّف ولا ينبغي أن تمرّ منه بايتات سيئة. أما Normalizer فأكثر تسامحًا: يعمل بأفضل جهد ويُرجع المُدخَل الذي لا يستطيع معالجته كما هو. ويستخدم التحويل إلى أحرف صغيرة تحويل Unicode البسيط ولا يحتاج إلى أي امتداد في PHP.
Was this page helpful?