أساسيات JavaScript

النصوص وطرق التعامل مع النصوص

45 دقيقة الدرس 5 من 60

مقدمة في النصوص في جافاسكريبت

النصوص (Strings) هي واحدة من اهم انواع البيانات الاساسية في جافاسكريبت. النص هو سلسلة من الاحرف تستخدم لتمثيل المحتوى النصي. سواء كنت تعرض اسم مستخدم او تبني عنوان URL او تحلل بيانات من واجهة برمجة تطبيقات او تنسق مخرجات لصفحة ويب، فان النصوص موجودة في كل مكان في برمجة جافاسكريبت. في هذا الدرس ستتعلم كيفية انشاء النصوص وفهم طبيعتها غير القابلة للتغيير واتقان العديد من الطرق المدمجة التي توفرها جافاسكريبت للتعامل مع النصوص.

انشاء النصوص

توفر جافاسكريبت ثلاث طرق لانشاء النصوص الحرفية: علامات الاقتباس المفردة وعلامات الاقتباس المزدوجة والقوالب النصية (backticks). جميعها تنتج نصوصا صالحة لكن لكل منها مزاياها الخاصة حسب السياق.

مثال: انشاء النصوص بعلامات الاقتباس المفردة والمزدوجة

// علامات الاقتباس المفردة
let firstName = 'Alice';

// علامات الاقتباس المزدوجة
let lastName = "Johnson";

// يمكنك تداخل نوع داخل الآخر
let sentence = "She said, 'Hello!'";
let another = 'He replied, "Hi there!"';

// احرف الهروب عند استخدام نفس نوع الاقتباس
let escaped = 'It\'s a beautiful day';
let escapedDouble = "She said, \"Goodbye!\"";

console.log(firstName);   // Alice
console.log(sentence);    // She said, 'Hello!'
console.log(escaped);     // It's a beautiful day

تتصرف علامات الاقتباس المفردة والمزدوجة بشكل متماثل في جافاسكريبت. الاختيار بينهما مسالة تفضيل شخصي او تفضيل الفريق. توصي العديد من ادلة الاسلوب باختيار واحد والالتزام به باستمرار في جميع انحاء قاعدة التعليمات البرمجية.

القوالب النصية

القوالب النصية التي قدمت في ES6 (ES2015) تستخدم احرف backtick وتوفر ميزات قوية لا توفرها علامات الاقتباس العادية. فهي تدعم ادراج المتغيرات والنصوص متعددة الاسطر والتعبيرات المدمجة.

مثال: القوالب النصية وادراج المتغيرات

let name = 'Alice';
let age = 28;

// ادراج المتغيرات باستخدام ${}
let greeting = `Hello, my name is ${name} and I am ${age} years old.`;
console.log(greeting);
// Hello, my name is Alice and I am 28 years old.

// التعبيرات داخل القوالب النصية
let price = 19.99;
let quantity = 3;
let total = `Total: $${(price * quantity).toFixed(2)}`;
console.log(total);  // Total: $59.97

// النصوص متعددة الاسطر
let poem = `Roses are red,
Violets are blue,
JavaScript is awesome,
And so are you.`;
console.log(poem);

// بدون القوالب النصية ستحتاج الى الربط او احرف الهروب
let oldWay = 'Roses are red,\n' +
             'Violets are blue,\n' +
             'JavaScript is awesome,\n' +
             'And so are you.';

// القوالب النصية الموسومة (متقدم)
function highlight(strings, ...values) {
    return strings.reduce((result, str, i) => {
        return result + str + (values[i] ? `<strong>${values[i]}</strong>` : '');
    }, '');
}
let highlighted = highlight`Welcome ${name}, you are ${age}!`;
console.log(highlighted);
// Welcome <strong>Alice</strong>, you are <strong>28</strong>!
نصيحة: القوالب النصية هي الطريقة المفضلة لبناء النصوص التي تتضمن متغيرات او تعبيرات. فهي تجعل الكود اكثر قراءة من ربط النصوص بعامل +. استخدمها كلما احتجت لادراج قيم داخل نص.

عدم قابلية النصوص للتغيير

مفهوم مهم يجب فهمه هو ان النصوص في جافاسكريبت غير قابلة للتغيير (immutable). هذا يعني انه بمجرد انشاء نص لا يمكنك تغيير احرف فردية فيه. اي عملية تبدو وكانها تعدل النص تنشئ في الواقع نصا جديدا تماما.

مثال: النصوص غير قابلة للتغيير

let word = 'Hello';

// محاولة تغيير حرف لا تعمل
word[0] = 'J';
console.log(word);  // Hello (لم يتغير!)

// يجب انشاء نص جديد بدلا من ذلك
word = 'J' + word.slice(1);
console.log(word);  // Jello

// الطرق تعيد دائما نصوصا جديدة
let original = 'JavaScript';
let upper = original.toUpperCase();
console.log(original);  // JavaScript (لم يتغير)
console.log(upper);     // JAVASCRIPT (نص جديد)
خطا شائع: يحاول المبتدئون غالبا تعديل نص بتعيين قيمة لفهرس مثل str[0] = 'X'. هذا يفشل بصمت في الوضع العادي ويطرح خطا في الوضع الصارم. تذكر دائما ان طرق النصوص تعيد نصوصا جديدة -- فهي لا تعدل النص الاصلي ابدا.

طول النص

خاصية length تعيد عدد وحدات الترميز UTF-16 في النص. بالنسبة لمعظم الاحرف الشائعة هذا يساوي عدد الاحرف. انتبه الى ان بعض الاحرف مثل الرموز التعبيرية قد تحسب كوحدتين ترميز او اكثر.

مثال: خاصية طول النص

let text = 'JavaScript';
console.log(text.length);  // 10

let empty = '';
console.log(empty.length);  // 0

let spaces = '  Hello  ';
console.log(spaces.length);  // 9 (المسافات تحسب!)

let emoji = 'Hello 😀';
console.log(emoji.length);  // 8 (الرمز التعبيري يستخدم وحدتي ترميز!)

الوصول الى الاحرف: charAt والاقواس المربعة

يمكنك الوصول الى احرف فردية في نص باستخدام طريقة charAt() او صيغة الاقواس المربعة. كلاهما يستخدم الفهرسة من الصفر مما يعني ان الحرف الاول في الموضع 0.

مثال: الوصول الى الاحرف

let str = 'JavaScript';

// باستخدام charAt()
console.log(str.charAt(0));   // J
console.log(str.charAt(4));   // S
console.log(str.charAt(20));  // '' (نص فارغ للفهرس خارج النطاق)

// باستخدام الاقواس المربعة
console.log(str[0]);   // J
console.log(str[4]);   // S
console.log(str[20]);  // undefined (وليس نص فارغ!)

// الحرف الاخير
console.log(str.charAt(str.length - 1));  // t
console.log(str[str.length - 1]);         // t

// باستخدام طريقة at() (ES2022) - تدعم الفهرسة السالبة
console.log(str.at(0));    // J
console.log(str.at(-1));   // t (الحرف الاخير)
console.log(str.at(-2));   // p (ما قبل الاخير)
ملاحظة: الفرق الرئيسي بين charAt() والاقواس المربعة هو ما يعيدانه للفهارس خارج النطاق. charAt() تعيد نصا فارغا '' بينما الاقواس المربعة تعيد undefined. طريقة at() الاحدث تدعم الفهارس السالبة مما يجعلها مريحة جدا للوصول الى الاحرف من نهاية النص.

البحث داخل النصوص: indexOf و lastIndexOf و includes

توفر جافاسكريبت عدة طرق للبحث عن نص داخل نص آخر. هذه ضرورية لمهام مثل التحقق والتحليل والمنطق الشرطي بناء على محتوى النص.

مثال: indexOf و lastIndexOf

let sentence = 'The quick brown fox jumps over the lazy dog';

// indexOf - تجد اول تطابق (تعيد الفهرس او -1)
console.log(sentence.indexOf('fox'));      // 16
console.log(sentence.indexOf('the'));      // 31 (حساسة لحالة الاحرف!)
console.log(sentence.indexOf('The'));      // 0
console.log(sentence.indexOf('cat'));      // -1 (غير موجود)

// indexOf مع موضع البداية (البحث من فهرس معين)
console.log(sentence.indexOf('o', 15));    // 17 (تجد 'o' في 'fox')
console.log(sentence.indexOf('o', 18));    // 26 (تجد 'o' في 'over')

// lastIndexOf - تجد آخر تطابق (تبحث للخلف)
console.log(sentence.lastIndexOf('o'));    // 41 ('o' في 'dog')
console.log(sentence.lastIndexOf('the'));  // 31

// نمط شائع: التحقق من وجود نص فرعي
if (sentence.indexOf('fox') !== -1) {
    console.log('وجدنا الثعلب!');
}

مثال: includes و startsWith و endsWith

let url = 'https://www.example.com/products?page=1';

// includes - تعيد قيمة منطقية
console.log(url.includes('https'));    // true
console.log(url.includes('http://')); // false
console.log(url.includes('example')); // true

// startsWith - تتحقق من بداية النص
console.log(url.startsWith('https://'));  // true
console.log(url.startsWith('http://'));   // false
console.log(url.startsWith('www', 8));   // true (من الموضع 8)

// endsWith - تتحقق من نهاية النص
let file = 'document.pdf';
console.log(file.endsWith('.pdf'));    // true
console.log(file.endsWith('.doc'));    // false
console.log(file.endsWith('ment', 8)); // true (تتحقق من اول 8 احرف)

// مثال عملي: التحقق من انواع الملفات
function isImageFile(filename) {
    let lower = filename.toLowerCase();
    return lower.endsWith('.jpg') ||
           lower.endsWith('.jpeg') ||
           lower.endsWith('.png') ||
           lower.endsWith('.gif') ||
           lower.endsWith('.webp');
}

console.log(isImageFile('photo.JPG'));   // true
console.log(isImageFile('data.csv'));    // false
نصيحة: فضل استخدام includes() على indexOf() !== -1 لتحسين القراءة عندما تحتاج فقط للتحقق مما اذا كان نص فرعي موجودا. استخدم indexOf() عندما تحتاج الى الموضع الفعلي للتطابق.

استخراج النصوص الفرعية: slice و substring

طريقتان شائعتان لاستخراج اجزاء من نص هما slice() وsubstring(). كلاهما يقبل معاملات البداية والنهاية ويعيد نصا جديدا لكنهما يتعاملان مع الحالات الحدية بشكل مختلف.

مثال: slice و substring

let text = 'JavaScript is awesome';

// slice(start, end) - النهاية غير مشمولة
console.log(text.slice(0, 10));    // JavaScript
console.log(text.slice(11));       // is awesome (الى النهاية)
console.log(text.slice(0, 4));     // Java

// slice مع فهارس سالبة (تحسب من النهاية)
console.log(text.slice(-7));       // awesome
console.log(text.slice(-7, -1));   // awesom
console.log(text.slice(-11, -8));  // is

// substring(start, end) - النهاية غير مشمولة
console.log(text.substring(0, 10));  // JavaScript
console.log(text.substring(11));     // is awesome

// الفرق الرئيسي: substring تبدل المعاملات اذا كانت البداية اكبر من النهاية
console.log(text.substring(10, 0));  // JavaScript (ابدلت الى 0, 10)
console.log(text.slice(10, 0));      // '' (نص فارغ بدون تبديل)

// substring تعامل الارقام السالبة كصفر
console.log(text.substring(-5));     // JavaScript is awesome (عوملت كـ 0)
console.log(text.slice(-5));         // esome (5 احرف من النهاية)

// مثال عملي: استخراج امتداد الملف
function getExtension(filename) {
    let dotIndex = filename.lastIndexOf('.');
    if (dotIndex === -1) return '';
    return filename.slice(dotIndex + 1).toLowerCase();
}

console.log(getExtension('photo.JPG'));      // jpg
console.log(getExtension('archive.tar.gz')); // gz
console.log(getExtension('README'));          // ''
ملاحظة: في جافاسكريبت الحديثة يفضل استخدام slice() على substring() لان سلوكها مع الفهارس السالبة اكثر سهولة وفائدة. طريقة substr() القديمة مهملة ويجب تجنبها في الكود الجديد.

استبدال المحتوى: replace و replaceAll

تتيح لك طريقة replace() استبدال اجزاء من نص بمحتوى جديد. بشكل افتراضي تستبدل اول تطابق فقط. طريقة replaceAll() التي قدمت في ES2021 تستبدل كل التطابقات.

مثال: replace و replaceAll

let message = 'I love cats. Cats are great. I have two cats.';

// replace - اول تطابق فقط
console.log(message.replace('cats', 'dogs'));
// I love dogs. Cats are great. I have two cats.

// replace حساسة لحالة الاحرف
console.log(message.replace('Cats', 'Dogs'));
// I love cats. Dogs are great. I have two cats.

// replaceAll - جميع التطابقات (حساسة لحالة الاحرف)
console.log(message.replaceAll('cats', 'dogs'));
// I love dogs. Cats are great. I have two dogs.

// استخدام التعبيرات النمطية مع العلم العام لاستبدال الكل
console.log(message.replace(/cats/gi, 'dogs'));
// I love dogs. dogs are great. I have two dogs.

// الاستبدال بدالة
let prices = 'Item A: $10, Item B: $25, Item C: $5';
let doubled = prices.replace(/\$(\d+)/g, function(match, amount) {
    return '$' + (parseInt(amount) * 2);
});
console.log(doubled);
// Item A: $20, Item B: $50, Item C: $10

// مثال عملي: تنظيف مدخلات المستخدم
function sanitizeHTML(input) {
    return input
        .replaceAll('&', '&amp;')
        .replaceAll('<', '&lt;')
        .replaceAll('>', '&gt;')
        .replaceAll('"', '&quot;')
        .replaceAll("'", '&#039;');
}

let userInput = '<script>alert("XSS")</script>';
console.log(sanitizeHTML(userInput));
// &lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;

تقسيم وربط النصوص

تقسم طريقة split() نصا الى مصفوفة من النصوص الفرعية بناء على فاصل. طريقة join() في المصفوفات تفعل العكس -- تجمع عناصر المصفوفة في نص واحد. معا تشكلان ثنائيا قويا لمعالجة النصوص.

مثال: split و join

// تقسيم اساسي
let csv = 'apple,banana,cherry,date';
let fruits = csv.split(',');
console.log(fruits);  // ['apple', 'banana', 'cherry', 'date']

// تقسيم مع حد
let limited = csv.split(',', 2);
console.log(limited);  // ['apple', 'banana']

// تقسيم الى احرف فردية
let chars = 'Hello'.split('');
console.log(chars);  // ['H', 'e', 'l', 'l', 'o']

// تقسيم بالمسافات
let words = '  Hello   World  '.trim().split(/\s+/);
console.log(words);  // ['Hello', 'World']

// join - دمج المصفوفة في نص
let joined = fruits.join(' - ');
console.log(joined);  // apple - banana - cherry - date

let noSeparator = ['J', 'S'].join('');
console.log(noSeparator);  // JS

// مثال عملي: تحويل الى حالة العنوان
function toTitleCase(str) {
    return str
        .toLowerCase()
        .split(' ')
        .map(word => word.charAt(0).toUpperCase() + word.slice(1))
        .join(' ');
}

console.log(toTitleCase('hello world from javascript'));
// Hello World From Javascript

// مثال عملي: تحويل slug الى عنوان قابل للقراءة
function slugToTitle(slug) {
    return slug.split('-').map(word =>
        word.charAt(0).toUpperCase() + word.slice(1)
    ).join(' ');
}

console.log(slugToTitle('my-awesome-blog-post'));
// My Awesome Blog Post

ازالة المسافات الفارغة

ادارة المسافات الفارغة امر بالغ الاهمية عند التعامل مع مدخلات المستخدم وتحليل البيانات ومقارنة النصوص. توفر جافاسكريبت ثلاث طرق لازالة المسافات غير المرغوب فيها من النصوص.

مثال: trim و trimStart و trimEnd

let padded = '   Hello, World!   ';

// trim - تزيل المسافات من كلا الطرفين
console.log(padded.trim());       // 'Hello, World!'
console.log(padded.trim().length); // 13

// trimStart (تعرف ايضا بـ trimLeft) - تزيل من البداية
console.log(padded.trimStart());  // 'Hello, World!   '

// trimEnd (تعرف ايضا بـ trimRight) - تزيل من النهاية
console.log(padded.trimEnd());    // '   Hello, World!'

// مثال عملي: تنظيف مدخلات النموذج
function cleanInput(value) {
    return value.trim().replace(/\s+/g, ' ');
}

console.log(cleanInput('   John    Doe   '));  // 'John Doe'

حشو النصوص: padStart و padEnd

تحشو طريقتا padStart() وpadEnd() نصا باحرف حتى يصل الى طول محدد. هاتان مفيدتان بشكل لا يصدق لتنسيق المخرجات مثل الارقام والتواريخ والنص المحاذي.

مثال: padStart و padEnd

// padStart - تضيف الحشو في البداية
let num = '5';
console.log(num.padStart(3, '0'));   // 005
console.log(num.padStart(5, '0'));   // 00005
console.log(num.padStart(1, '0'));   // 5 (طويل بما يكفي بالفعل)

// padEnd - تضيف الحشو في النهاية
let item = 'Apple';
console.log(item.padEnd(10, '.'));   // Apple.....
console.log(item.padEnd(10));        // 'Apple     ' (الحشو الافتراضي مسافة)

// مثال عملي: تنسيق قائمة اسعار
let items = [
    { name: 'Coffee', price: 4.50 },
    { name: 'Sandwich', price: 12.00 },
    { name: 'Cake', price: 8.75 }
];

items.forEach(item => {
    let name = item.name.padEnd(15, '.');
    let price = item.price.toFixed(2).padStart(8);
    console.log(`${name}$${price}`);
});
// Coffee.........$    4.50
// Sandwich.......$   12.00
// Cake...........$    8.75

// مثال عملي: اخفاء رقم بطاقة الائتمان
function maskCard(cardNumber) {
    let last4 = cardNumber.slice(-4);
    return last4.padStart(cardNumber.length, '*');
}

console.log(maskCard('4532015112830366'));
// ************0366

تكرار النصوص

تنشئ طريقة repeat() نصا جديدا بتكرار النص الاصلي عددا محددا من المرات. هذا مفيد لانشاء الانماط وبناء الفواصل وبناء العناصر المرئية.

مثال: طريقة repeat

console.log('Ha'.repeat(3));     // HaHaHa
console.log('-'.repeat(30));     // ------------------------------
console.log('abc'.repeat(0));    // '' (نص فارغ)

// مثال عملي: انشاء شريط تقدم بسيط
function progressBar(percent, width = 20) {
    let filled = Math.round(width * percent / 100);
    let empty = width - filled;
    return '[' + '#'.repeat(filled) + '-'.repeat(empty) + ']' + ` ${percent}%`;
}

console.log(progressBar(75));   // [###############-----] 75%
console.log(progressBar(30));   // [######--------------] 30%
console.log(progressBar(100));  // [####################] 100%

تحويل حالة الاحرف

توفر جافاسكريبت طرقا لتحويل النصوص الى احرف كبيرة او صغيرة. هذه ضرورية للمقارنات غير الحساسة لحالة الاحرف والتنسيق.

مثال: toUpperCase و toLowerCase

let mixed = 'Hello World';
console.log(mixed.toUpperCase());  // HELLO WORLD
console.log(mixed.toLowerCase());  // hello world

// مقارنة غير حساسة لحالة الاحرف
let input = 'JavaScript';
let expected = 'javascript';
console.log(input === expected);                        // false
console.log(input.toLowerCase() === expected.toLowerCase()); // true

// مثال عملي: بحث غير حساس لحالة الاحرف
function searchArray(arr, query) {
    let lowerQuery = query.toLowerCase();
    return arr.filter(item => item.toLowerCase().includes(lowerQuery));
}

let languages = ['JavaScript', 'Python', 'Java', 'TypeScript'];
console.log(searchArray(languages, 'java'));
// ['JavaScript', 'Java']

// تحويل حالة الاحرف مع مراعاة اللغة
let turkish = 'Istanbul';
console.log(turkish.toLocaleLowerCase('tr')); // istanbul
console.log(turkish.toLocaleLowerCase('en')); // istanbul

مقارنة النصوص

تتم مقارنة النصوص في جافاسكريبت حرفا بحرف باستخدام قيم نقاط ترميز يونيكود. فهم هذا امر حيوي لعمليات الترتيب والتنظيم. طريقة localeCompare() توفر مقارنة تراعي اللغة وتحترم القواعد الخاصة بكل لغة.

مثال: مقارنة النصوص

// المقارنة الاساسية (تستخدم نقاط ترميز يونيكود)
console.log('a' < 'b');     // true
console.log('B' < 'a');     // true (الاحرف الكبيرة تاتي اولا في يونيكود)
console.log('10' < '9');    // true (تقارن حرفا بحرف: '1' < '9')

// localeCompare للترتيب الصحيح
let words = ['banana', 'Apple', 'cherry'];

// الترتيب الافتراضي (حساس لحالة الاحرف ترتيب يونيكود)
console.log(words.sort());
// ['Apple', 'banana', 'cherry']

// ترتيب يراعي اللغة
words.sort((a, b) => a.localeCompare(b, 'en', { sensitivity: 'base' }));
console.log(words);
// ['Apple', 'banana', 'cherry'] (ترتيب ابجدي صحيح)

// localeCompare تعيد -1 او 0 او 1
console.log('a'.localeCompare('b'));  // -1 (a تاتي قبل b)
console.log('b'.localeCompare('a'));  // 1 (b تاتي بعد a)
console.log('a'.localeCompare('a'));  // 0 (متساويتان)

// الترتيب الرقمي مع localeCompare
let files = ['file10', 'file2', 'file1', 'file20'];
files.sort((a, b) => a.localeCompare(b, 'en', { numeric: true }));
console.log(files);
// ['file1', 'file2', 'file10', 'file20']

التعامل مع يونيكود والرموز التعبيرية

نصوص جافاسكريبت مشفرة داخليا بترميز UTF-16. معظم الاحرف الشائعة تستخدم وحدة ترميز واحدة بحجم 16 بت لكن الاحرف خارج المستوى متعدد اللغات الاساسي (BMP) بما في ذلك معظم الرموز التعبيرية تستخدم وحدتي ترميز تسميان زوج بديل (surrogate pair). هذا له آثار مهمة على عمليات النصوص.

مثال: التعامل مع يونيكود والرموز التعبيرية

// الاحرف العادية: وحدة ترميز واحدة لكل حرف
let hello = 'Hello';
console.log(hello.length);  // 5

// الرموز التعبيرية: وحدتا ترميز (زوج بديل)
let smile = '😀';
console.log(smile.length);      // 2 (وليس 1!)
console.log(smile.charAt(0));   // يعرض نصف زوج البديل
console.log(smile.codePointAt(0)); // 128512 (نقطة الترميز الصحيحة)

// التكرار بـ for...of يتعامل مع الازواج البديلة بشكل صحيح
let text = 'Hi 😀!';
for (let char of text) {
    console.log(char);
}
// H, i, (مسافة), 😀, !

// عامل الانتشار يتعامل ايضا مع الازواج البديلة
let characters = [...'Hi 😀!'];
console.log(characters);        // ['H', 'i', ' ', '😀', '!']
console.log(characters.length); // 5 (العدد الصحيح!)

// الحصول على العدد الحقيقي للاحرف
function trueLength(str) {
    return [...str].length;
}

console.log(trueLength('Hello 😀 World 🌍'));  // 15

// تسلسلات هروب يونيكود
let omega = '\u03A9';          // حرف اوميجا اليوناني الكبير
console.log(omega);             // Ω

let rocket = '\u{1F680}';      // هروب نقطة ترميز يونيكود (ES6)
console.log(rocket);            // (رمز الصاروخ)

// تطبيع يونيكود (مهم للمقارنة)
let cafe1 = 'caf\u00e9';      // e مع تشكيل (نقطة ترميز واحدة)
let cafe2 = 'cafe\u0301';     // e + تشكيل مدمج (نقطتا ترميز)
console.log(cafe1 === cafe2);           // false (تمثيلات مختلفة!)
console.log(cafe1.normalize() === cafe2.normalize()); // true
خطا شائع: استخدام .length او charAt() على نصوص تحتوي على رموز تعبيرية او احرف يونيكود خاصة غالبا يعطي نتائج غير متوقعة. استخدم دائما [...str].length للعدد الحقيقي للاحرف وحلقات for...of للتكرار الصحيح على النصوص التي تحتوي على رموز تعبيرية.

طرق ربط النصوص

هناك عدة طرق لدمج النصوص في جافاسكريبت. فهم الخيارات يساعدك في اختيار النهج الاكثر قراءة وكفاءة لكل موقف.

مثال: طرق ربط النصوص

let first = 'Hello';
let second = 'World';

// عامل الجمع
let result1 = first + ' ' + second;
console.log(result1);  // Hello World

// القوالب النصية (مفضلة لسهولة القراءة)
let result2 = `${first} ${second}`;
console.log(result2);  // Hello World

// طريقة concat (اقل شيوعا)
let result3 = first.concat(' ', second);
console.log(result3);  // Hello World

// بناء النصوص في حلقة -- استخدم مصفوفة + join للكفاءة
let parts = [];
for (let i = 1; i <= 5; i++) {
    parts.push(`Item ${i}`);
}
let list = parts.join(', ');
console.log(list);  // Item 1, Item 2, Item 3, Item 4, Item 5
نصيحة: عند بناء النصوص في حلقة تجنب الربط المتكرر بـ +=. بدلا من ذلك ادفع الاجزاء الى مصفوفة واستخدم join() في النهاية. هذا النمط اكثر نظافة وافضل اداء لاعداد كبيرة من التكرارات.

انماط نصية عملية

لنلق نظرة على بعض الانماط الواقعية التي تجمع بين عدة طرق للنصوص. هذه توضح كيف تعمل الطرق معا لحل مهام البرمجة الشائعة.

مثال: عمليات نصية شائعة في العالم الحقيقي

// تحويل camelCase الى kebab-case
function camelToKebab(str) {
    return str.replace(/([A-Z])/g, '-$1').toLowerCase();
}
console.log(camelToKebab('backgroundColor'));  // background-color
console.log(camelToKebab('fontSize'));          // font-size

// اقتطاع النص مع علامة حذف
function truncate(str, maxLength) {
    if (str.length <= maxLength) return str;
    return str.slice(0, maxLength - 3) + '...';
}
console.log(truncate('This is a very long sentence', 15));
// This is a ve...

// عد تكرارات نص فرعي
function countOccurrences(str, sub) {
    return str.split(sub).length - 1;
}
console.log(countOccurrences('banana', 'an'));  // 2

// عكس نص
function reverseString(str) {
    return [...str].reverse().join('');
}
console.log(reverseString('Hello'));     // olleH
console.log(reverseString('Hello 😀')); // 😀 olleH (آمن مع الرموز التعبيرية!)

// التحقق مما اذا كان النص متناظرا
function isPalindrome(str) {
    let cleaned = str.toLowerCase().replace(/[^a-z0-9]/g, '');
    return cleaned === reverseString(cleaned);
}
console.log(isPalindrome('racecar'));                // true
console.log(isPalindrome('A man a plan a canal Panama')); // true

تمرين عملي

ابنِ مكتبة ادوات نصية بانشاء الدوال التالية. اختبر كل واحدة بثلاث مدخلات مختلفة على الاقل:

  1. capitalize(str) -- تاخذ جملة وتحول الحرف الاول من كل كلمة الى حرف كبير (مثلا "hello world" تصبح "Hello World").
  2. countWords(str) -- تعد عدد الكلمات في نص مع التعامل الصحيح مع المسافات المتعددة والمسافات في البداية والنهاية.
  3. slugify(str) -- تحول نصا الى slug صديق لعناوين URL بتحويله الى احرف صغيرة واستبدال المسافات بشرطات وازالة الاحرف الخاصة (مثلا "Hello World! 2024" تصبح "hello-world-2024").
  4. extractEmails(str) -- تجد وتعيد جميع عناوين البريد الالكتروني من كتلة نصية كمصفوفة (تلميح: استخدم split و filter مع includes).
  5. maskEmail(email) -- تخفي عنوان بريد الكتروني بعرض اول حرفين والنطاق فقط (مثلا "alice@example.com" تصبح "al***@example.com").

لكل دالة فكر في الحالات الحدية: النصوص الفارغة والنصوص التي تحتوي على مسافات فقط والنصوص ذات الاحرف الخاصة والنصوص ذات التنسيق غير المعتاد. استخدم الطرق التي تعلمتها في هذا الدرس -- split وjoin وtrim وslice وreplace وtoLowerCase وincludes وpadEnd وغيرها.

ES
Edrees Salih
منذ 12 ساعة

We are still cooking the magic in the way!