روشهای ایجاد مقادیر رشتهای
یادآوری میکنم که در جاوااسکریپت میتوان مقادیر متنی را درون کوتیشنهای تکی، جفتی و بکتیک قرار داد.
strings.js
let single = 'single-quoted';
let double = "double-quoted";
let backticks = `backticks`;
کوتیشنهای تکی و جفتی کاملاً مشابه هم هستند اما بکتیکها این امکان را فراهم میکنند که عبارات (expressions)
را با استفاده از سینتکس ${expression} درون رشتهها قرار دهیم. با این کار، عبارت مورد نظر ارزیابی شده و
مقدارش به بخشی از رشته تبدیل میشود.
strings.js
let x = 5;
let y = 6;
console.log(`5 * 6 = ${5 * 6}`);
یک مزیت دیگر بکتیکها این است که امکان نوشتن متن در بیش از یک خط را فراهم میکنند.
strings.js
let languageList = `Languages:
* JavaScript
* Rust
* Python
`;
console.log(languageList);
اگر این مثال را اجرا کنیم، خواهیم دید که رشتهی متنی به همان شکلی که نوشته شده، با حفظ شکست خطها و
فاصلهها، در خروجی نمایش داده میشود.
Langages:
* JavaScript
* Rust
* Python
اما اگر این کار را با استفاده از کوتیشنهای تکی و جفتی انجام دهیم، با خطا مواجه میشویم. البته میتوان با
استفاده از کاراکتر \n در رشتههای ایجاد شده با کوتیشنهای تکی و جفتی شکست خط ایجاد کرد.
strings.js
let languageList = "Languages:\n * JavaScript\n * Rust\n * Python";
console.log(languageList);
\n یک کاراکتر گریز (escape character) است. کاراکترهای گریز در جاوااسکریپت برای نمایش کاراکترهای خاص در
رشتهها استفاده میشوند. این کاراکترها با یک بکاسلش (\) شروع میشوند تا به جاوااسکریپت بفهمانند که کاراکتر
بعد از آن معنای خاصی دارد و به عنوان بخشی از رشته به صورت مستقیم نمایش داده نمیشود. مهمترین کاراکترهای گریز
عبارتند از:
-
\n برای ایجاد یک خط جدید (new line) در رشتهها کاربرد دارد.
-
\t با ایجاد یک Tab افقی بین کاراکترهای رشته فاصله ایجاد میکند.
-
\' و \" و \` برای ایجاد کوتیشنهای تکی، جفتی و بکتیک در رشتهها کاربرد دارند.
-
\\ یک بکاسلش در رشته ایجاد میکند.
-
\b کاراکتر قبلی را از رشته حذف میکند.
-
\uxxxx برای درج کاراکترها از طریق کدهای یونیکد کاربرد دارد. برای مثال، \u00A9 کاراکتر کپیرایت را در
رشته نمایش میدهد.
در مثال زیر از این کاراکترهای گریز استفاده شده است.
strings.js
let str = "New line character: Hello\nWorld";
console.log(str);
str = "Horizontal tab character: Hello\tWorld";
console.log(str);
str = 'Apostrophe character: I\'m danial';
console.log(str);
str = 'Backslash character: D:\\Books\\title.pdf';
console.log(str);
str = 'Unicode character: \u00A9 2024';
console.log(str);
نتیجهی اجرای این کد به صورت زیر خواهد بود.
New line character: Hello
World
Horizontal tab character: Hello World
Apostrophe character: I'm danial
Backslash character: D:\Books\title.pdf
Unicode character: © 2024
دسترسی به کاراکترهای رشته
یک رشته دنبالهای از کاراکترهاست و دسترسی به هر کاراکتر رشته از طریق اندیس آن کاراکتر ممکن است. اندیس اولین
کاراکتر یک رشته برابر با صفر و اندیس دومین کاراکتر برابر با 1 و به طور کلی، اندیس کاراکتر n-ام برابر با n-1
است.
strings.js
let str = "Hello";
console.log(str[0]);
console.log(str[1]);
یک روش دیگر هم برای دسترسی به کاراکترهای رشتهها وجود دارد و آن استفاده از متدی به نام at() است. متد at() نسبت
به براکتها یک مزیت ویژه دارد و آن امکان استفاده از اندیسهای منفی است که باعث می شود شمارش از انتهای رشته
شروع شود.
strings.js
let str = "Hello";
console.log(str.at(-1));
console.log(str.at(-5));
اندیس آخرین عنصر یک رشته همواره برابر با -1 است و این یکی از مزایای اندیسگذاری منفی است که همیشه میتوان
بدون دانستن طول رشته، به آخرین کاراکتر رشته دسترسی داشت. توجه داشته باشید که اندیسگذاری منفی با براکتها
کار نمیکند و همیشه مقدار undefined را برمیگرداند.
حالا که از طول رشتهها نام بردیم، اجازه دهید شما را با پراپرتی length آشنا کنم که طول رشته، یعنی تعداد
کاراکترهای رشته را برمیگرداند.
strings.js
let str = "Hello";
console.log(str.length);
کسانی که سابقهی کار با زبانهای دیگری مثل پایتون را داشته باشند، گاهی اوقات پراپرتی length را به صورت
یک متد length() به کار میبرند و با خطا مواجه میشوند. دقت داشته باشید که در جاوااسکریپت، length یک پراپرتی
عددی است نه یک متد و بنابراین، به پرانتز نیاز ندارد.
تغییرناپذیری رشتهها
در جاوااسکریپت، رشتهها تغییرناپذیر یا immutable هستند؛ یعنی امکان ویرایش درجای آنها وجود ندارد. بنابراین،
کد زیر کار نمیکند.
strings.js
let str = "Hello";
str[0] = 'h';
console.log(str);
اگر این کد را اجرا کنید، خواهید دید که گزارهی دوم هیچ تأثیری ندارد و رشته همچنان به صورت Hello چاپ میشود.
حتی اگر از متدهایی که نوع string برای ویرایش رشتهها ارائه داده، استفاده کنیم، باز هم نتیجهای نخواهد داشت.
strings.js
let str = "Hello";
str.replace('H', 'h');
console.log(str);
در اینجا از متدی به نام replace() استفاده کردهایم که همانطور که نامش هم نشان میدهد، برای جابجایی یک کاراکتر
رشته با یک کاراکتر دیگر کاربرد دارد، اما باز هم تغییر مورد نظر روی رشته انجام نشده است. در واقع، همانطور که
گفته شد، علت کار نکردن دو مثال قبل، ماهیت تغیرناپذیر رشتههاست که ویرایش درجای آنها را غیرممکن میکند. برای
اینکه مثال بالا مطابق انتظار کار کند، باید آن را به صورت زیر ویرایش کنیم.
strings.js
let str = "Hello";
str = str.replace('H', 'h');
console.log(str);
متدهای مربوط به رشتهها
در این بخش قصد داریم مهمترین متدهای نوع string را معرفی کنیم و کاربرد آنها را ببینیم. اغلب این متدها از نوع
نمونهای (غیر استاتیک) هستند و بنابراین، به فرم str.method() که در آن str یک رشته است، قابل استفاده هستند.
تغییر بزرگی و کوچکی حروف
کار بررسی متدهای string را با دو متد toUpperCase() و toLowerCase() شروع میکنیم که کاربردشان از نامشان مشخص است.
متد toUpperCase() رشته را به یک رشته با حروف بزرگ تبدیل میکند و متد toLowerCase() رشته را به رشتهای با حروف
کوچک تبدیل میکند. در مثال زیر از این دو متد استفاده شده است.
strings.js
console.log('hello'.toUpperCase());
console.log('Hello'.toLowerCase());
let str = "Interface".toUpperCase();
console.log(str);
جستجو برای یک زیررشته
متدهایی که در این بخش معرفی میکنیم، برای جستجوی زیررشتهها کاربرد دارند؛ یعنی وقتی میخواهیم ببینیم آیا
عبارت متنی مورد نظرمان در یک رشته وجود دارد یا نه، از این متدها استفاده میکنیم. اولین متد indexOf() نام دارد
و دارای فرم کلی زیر است.
این متد به دنبال عبارت substr در رشتهی str میگردد و جستجو را از اندیس pos شروع میکند. اگر عبارت substr در
رشته باشد، اندیسی را که substr از آن شروع شده برمیگرداند و در غیر این صورت مقدار -1 را. در ضمن، pos یک
پارامتر اختیاری است که اگر آن را وارد نکنیم، برابر با صفر در نظر گرفته شده و بنابراین، جستجو از ابتدای رشته
شروع میشود.
strings.js
let str = 'Widget with id';
console.log(str.indexOf('Widget'));
console.log(str.indexOf('widget'));
console.log(str.indexOf("id"));
console.log(str.indexOf("id", 2));
حاصل اولین متد log() در مثال بالا مقدار صفر است؛ چون عبارت Widget در ابتدای رشتهی str قرار دارد. اما حاصل
دومین متد log() مقدار -1 است و این نشان میدهد که برای متد indexOf() بزرگی و کوچکی حروف مهم است و بنابراین، از
نظر این متد widget با Widget متفاوت است. سومین متد log() هم خروجی 1 را تولید میکند اما آخرین متد log() مقدار 12
را نمایش میدهد؛ چون این بار مقدار 2 برای پارامتر pos تعیین شده و نتیجتاً جستجو از سومین کاراکتر رشته شروع
میشود.
اگر همهی تکرارهای یک زیررشته در یک رشته را بخواهیم، باید از حلقههایی مانند while و for استفاده کنیم
که در درس بعدی معرفی میشوند.
یک روش مدرنتر برای جستجوی زیررشتهها، متد includes() است که دارای فرم کلی زیر است.
str.includes(substr, pos)
اگر عبارت substr در رشتهی str وجود داشته باشد، این متد مقدار true و در غیر این صورت مقدار false را
برمیگرداند. پارارمتر pos نیز مشخصکنندهی مکان شروع جستجو در رشته است.
strings.js
let str = 'Widget with id';
console.log(str.includes('Widget'));
console.log(str.includes('widget'));
console.log(str.includes("id"));
console.log(str.includes("id", 2));
نتیجهی اجرای کد بالا به صورت زیر خواهد بود که علت تولید این خروجی باید برایتان واضح باشد.
true
false
true
true
دو متد دیگر هم داریم که مشابه یا به عبارت بهتر، مکمل متد includes() هستند. یکی از این متدها startsWith() نام
دارد و دیگری endsWith() و فرم کلی این متدها به صورت زیر است.
str.startsWith(substr)
str.endsWith(substr)
متد اول بررسی میکند که آیا رشتهی str با مقدار substr شروع میشود یا خیر. در صورت مثبت بودن جواب، مقدار
true و در غیر این صورت مقدار false برگردانده میشود. متد دوم هم به همین ترتیب، بررسی میکند که آیا رشتهی
str با مقدار substr به پایان رسیده یا خیر.
strings.js
let str = 'Widget with id';
console.log(str.startsWith('Widget'));
console.log(str.endsWith('ab'));
استخراج زیررشتهها
در این بخش سه متد معرفی میکنیم که برای استخراج زیرشته از رشتهها کاربرد دارند؛ یعنی برای وقتی که میخواهیم
بخشی از یک رشته را از آن استخرج کنیم. این متدها عبارتند از: slice()، substring() و substr().
کار را با متد slice() شروع میکنیم که دارای فرم کلی زیر است.
این متد از اندیس start تا end-1 را از رشته استخراج میکند؛ یعنی اندیس پایانی که در اینجا end نامگذاری شده،
در زیررشتهی استخراجشده وجود نخواهد داشت.
strings.js
let str = "stringify";
console.log(str.slice(0, 5));
console.log(str.slice(0, 1));
اگر فقط یک آرگومان برای متد slice() فراهم کنیم، یعنی از این متد به صورت slice(start) استفاده کنیم، از start تا
انتهای رشته استخراج میشود. در ضمن، پارامترهای start و end میتوانند مقادیر منفی هم باشند که در این صورت،
شمارش اندیس از انتهای رشته انجام میشود.
strings.js
let str = "stringify";
console.log(str.slice(2));
console.log(str.slice(-4, -1));
متد بعدی substring() نام دارد و دارای فرم کلی زیر است.
str.substring(start, end)
ظاهراً که متد substring() مشابه متد slice() است و واقعاً هم همینطور است. یعنی پارامترهای start و end بهترتیب،
مشخصکنندهی اندیس ابتدایی و انتهایی زیررشتهی استخراجی هستند و خود end هم محاسبه نمیشود. اما دو تفاوت
نسبتاً کوچک بین این دو متد وجود دارد. اول این که در مورد متد substring() مقدار start میتواند از end بزرگتر
باشد که در این صورت، به طور خودکار جابجا میشوند. برای مثال، substring(6, 2) معادل با substring(2, 6) در نظر
گرفته میشود. تفاوت دیگر دو متد این است که بر خلاف slice() متد substring() از مقادیر منفی برای پارامترهای start
و end پشتیبانی نمیکند و مقادیر منفی را برابر با صفر فرض میکند.
و بالاخره آخرین متدی که به استخراج زیررشتهها مربوط است، متد substr() است که دارای فرم کلی زیر است.
str.substr(start, length)
برای این متد، پارامتر start اندیس شروع زیررشتهی استخراجی است و پارامتر length طول زیررشتهی استخراجی را
تعیین میکند. یعنی با شروع از start یک زیررشته به طول length از رشته استخراج میشود.
strings.js
let str = "stringify";
console.log(str.substr(2, 4));
console.log(str.substr(-4, 3));
پس ما سه متد برای استخراج زیررشته از رشتهها داریم که تقریباً مشابه هم هستند و حالا این سوال پیش میآید که
بهتر است از کدامیک از این متدها استفاده کنیم؟
متد substr() یک ضعف خاص دارد و آن این است که این متد در مستندات ES وجود ندارد، بلکه بحشی از Annex است که
ویزگیهایی را تعریف میکند که مختص مرورگرها هستند و به دلایل تاریخی نگه داشته شدهاند. بنابراین، لااقل از
نظر تئوری این امکان وجود دارد که محیطهای مستقل از مرورگرها از آن پشتیبانی نکنند. در vscode از عبارت
deprecated یا منقضیشده برای این متد استفاده میشود تا شما را تشویق کند از این متد استفاده نکنید. پس، بهتر
است آن را کنار بگذارید. از بین دو متد باقیمانده هم متد slice() با توجه به مزیت پشتیبانی از پارامترهای منفی به
متد substring() ارجحیت پیدا میکند. بنابراین، میتوان گفت در عمل، تسلط به متد slice() برای استخرج زیررشتهها
کفایت میکند. اما به هر حال، چون امکان رؤیت دو متد دیگر در کدهای دیگران و کتابخانههای جاوااسکریپتی وجود
دارد، باید با آنها هم آشنا باشیم.