در جاوااسکریپت، دادهی متنی به عنوان رشته (string) ذخیره میشود. نوع جداگانهای برای یک کاراکتر مفرد وجود ندارد.
فرمت درونی برای رشتهها همیشه UTF-16 است، و به رمزگذاری صفحه بستگی ندارد.
کوتیشنها
بیایید انواع کوتیشنها را یادآوری کنیم.
رشتهها میتوانند در کوتیشنهای تکی، دوتایی یا backtickها محصور شوند:
let single = 'کوتیشن تکی';
let double = "کوتیشن دوتایی";
let backticks = `هاbacktick`;
کوتیشنهای تکی و دوتایی اساسا یکسان هستند. اگرچه، backtickها، با پیچیدن هر عبارتی در {...}$
، به ما اجازه میدهند که آن عبارت را درون رشته قرار دهیم:
function sum(a, b) {
return a + b;
}
alert(`1 + 2 = ${sum(1, 2)}.`); // 1 + 2 = 3.
یکی دیگر از مزایای استفاده از backtickها این است که اجازه میدهند تا رشته را در چند خط بنویسیم:
let guestList = `مهمانها:
* John
* Pete
* Mary
`;
alert(guestList); // لیستی از مهمانها، در چند خط
طبیعی به نظر میرسد نه؟ اما کوتیشنهای تکی یا دوتایی این چنین کار نمیکنند.
اگر ما با استفاده از آنها تلاش کنیم در چند خط بنویسیم، یک ارور به وجود خواهد آمد:
let guestList = "Guests: // Error: Unexpected token ILLEGAL
* John";
کوتیشنهای تکی و دوتایی از زمان بسیار قدیم در زبان وجود داشتند زمانی که نیاز به رشتههای چند خطی خیلی به چشم نمیآمد. Backtickها بعدها به وجود آمدند و به این ترتیب چند کاره هستند.
Backtickها به ما اجازه میدهند که یک “تابع الگو” قبل از backtick اول مشخص کنیم. سینتکس اینگونه است: func`string`
. تابع func
به طور خودکار صدا زده میشود، رشته را دریافت میکند و عبارات را ایجاد میکند و میتواند با آنها فرایندی انجام دهد. به این “الگوهای برچسب گذاری شده” میگویند. این ویژگی پیادهسازی الگوهای سفارشی را آسانتر میکند، اما در عمل خیلی کم استفاده میشود. میتوانید درباره آن در کتاب راهنما بیشتر بخوانید.
کاراکترهای خاص
اینکه با کوتیشنهای تکی و دوتایی رشتههای چند خطی بسازیم، با استفاده از “کاراکتر خط جدید”، که به صورت \n
نوشته میشود، امکان پذیر است که یک خط جدید را مشخص میکند:
let guestList = "مهمانها:\n * John\n * Pete\n * Mary";
alert(guestList); // لیستی چند خطی از مهمانها، درست مانند عبارت بالا
برای مثال، این دو خط برابر هستند، فقط به طور متفاوتی نوشته شدهاند:
let str1 = "Hello\nWorld"; // "ایجاد دو خط با استفاده از "نماد خط جدید
// هاbacktick ایجاد دو خط با استفاده از خط جدید و
let str2 = `Hello
World`;
alert(str1 == str2); // true
<<<<<<< HEAD کاراکترهای “خاص” دیگر و غیر متداول هم هستند:
There are other, less common special characters:
18b1314af4e0ead5a2b10bb4bacd24cecbb3f18e
کاراکتر | توضیحات |
---|---|
<<<<<<< HEAD | |
\n |
خط جدید |
\r |
فایلهای متنی ویندوز از ترکیب دو کاراکتر \r\n برای نمایش یک خط جدید استفاده میکند، در حالی که برای سیستمهای غیر ویندوزی \n این کار را انجام میدهد. |
دلیل آن مربوط به گذشتهها است. بیشتر نرمافزارهای ویندوزی \n را هم میشناسند. |
|
\' , \" , \` |
کوتیشنها |
\\ |
Backslash |
\t |
Tab |
\b , \f , \v |
Backspace, Form Feed, Vertical Tab – برای کامل بودن مطالب گفته شدهاند، از قدیم وجود دارند، امروزه استفاده نمیشوند (شما میتوانید همین حالا آنها را فراموش کنید). |
تمام کاراکترهای خاص با یک کاراکتر backslash \
شروع میشوند. همچنین به آن “کاراکتر فرار (escape character)” هم میگویند.
چون این کاراکتر خاص است، اگر بخواهیم یک backslash \
واقعی درون رشته نشان دهیم، باید آن را دوبل کنیم:
alert( `The backslash: \\` ); // The backslash: \
کوتیشنهای «escaped» \'
، \"
، \`
برای اضافه کردن یک کوتیشن به رشتهای که در همان نوع کوتیشن قرار گرفته است استفاده میشوند.
برای مثال:
alert( 'I\'m the Walrus!' ); // I'm the Walrus!
همانطور که میبینید، باید قبل از کوتیشن داخلی backslash \
بیاریم، وگرنه در غیر این صورت کوتیشن پایان رشته را نمایش میدهد.
قطعا فقط کوتیشنهایی که با کوتیشنهای پایانی یکسان هستند باید فراری شوند. پس، به عنوان یک راه حل زیباتر، به جای آن میتوانیم به کوتیشنهای دوتایی یا backtickها سوییچ کنیم:
alert( "I'm the Walrus!" ); // I'm the Walrus!
<<<<<<< HEAD
در کنار این کاراکترهای خاص، همچنین یک نشان خاص برای کدهای Unicode \u…
وجود دارد که کمی بعدتر در این فصل آن را پوشش میدهیم.
Besides these special characters, there’s also a special notation for Unicode codes \u…
, it’s rarely used and is covered in the optional chapter about Unicode.
18b1314af4e0ead5a2b10bb4bacd24cecbb3f18e
طول رشته
ویژگی length
دارای طول رشته است:
alert( `My\n`.length ); // 3
در نظر داشته باشید که \n
یک کاراکتر “خاص” مفرد است، پس طول در واقع 3
است.
length
یک ویژگی استبعضی اوقات افرادی که زمینهای در بعضی زبانهای برنامه نویسی دیگر دارند اشتباها str.length()
را به جای نوشتن str.length
صدا میزنند. اینگونه کار نمیکند.
<<<<<<< HEAD
لطفا در نظر داشته باشید که str.length
یک ویژگی عددی است نه یک تابع. نیازی به اضافه کردن پرانتر بعد از آن نیست.
Please note that str.length
is a numeric property, not a function. There is no need to add parenthesis after it. Not .length()
, but .length
.
18b1314af4e0ead5a2b10bb4bacd24cecbb3f18e
دسترسی داشتن به کاراکترها
<<<<<<< HEAD
برای دریافت یک کاراکتر در موقعیت pos
، از براکتها استفاده کنید یا متد str.charAt(pos) را صدا بزنید. اولین کاراکتر از موقعیت صفر شروع میشود:
To get a character at position pos
, use square brackets [pos]
or call the method str.at(pos). The first character starts from the zero position:
18b1314af4e0ead5a2b10bb4bacd24cecbb3f18e
let str = `Hello`;
// اولین کاراکتر
alert( str[0] ); // H
alert( str.at(0) ); // H
// آخرین کاراکتر
alert( str[str.length - 1] ); // o
alert( str.at(-1) );
<<<<<<< HEAD
براکتها روش مدرن دریافت کاراکتر هستند، در حالی که charAt
بنا به دلایلی مربوط به تاریخچه زبان وجود دارد.
تنها تفاوت میان آنها این است که اگر کاراکتری پیدا نشود، []
مقدار undefined
را برمیگرداند، و charAt
یک رشته خالی را برمیگرداند:
As you can see, the .at(pos)
method has a benefit of allowing negative position. If pos
is negative, then it’s counted from the end of the string.
So .at(-1)
means the last character, and .at(-2)
is the one before it, etc.
The square brackets always return undefined
for negative indexes, for instance:
18b1314af4e0ead5a2b10bb4bacd24cecbb3f18e
let str = `Hello`;
<<<<<<< HEAD
alert( str[1000] ); // undefined
alert( str.charAt(1000) ); // '' (یک رشته خالی)
=======
alert( str[-2] ); // undefined
alert( str.at(-2) ); // l
>>>>>>> 18b1314af4e0ead5a2b10bb4bacd24cecbb3f18e
همچنین ما میتوانیم با استفاده از for..of
برای کاراکترها حلقه بزنیم:
for (let char of "Hello") {
alert(char); // H,e,l,l,o (و غیره "l" سپس ،"e" سپس ،"H" میشود char)
}
رشتهها تغییرناپذیر هستند
رشتهها در جاوااسکریپت نمیتوانند تغییر کنند. اینکه یک کاراکتر را تغییر دهیم غیر ممکن است.
بیایید برای نشان دادن اینکه این کار نخواهد کرد امتحانش کنیم:
let str = 'Hi';
str[0] = 'h'; // ارور میدهد
alert( str[0] ); // کار نمیکند
یک راه حل این است که رشتهای کاملا جدید بسازیم و str
را به جای رشتهی قدیمی برابر با آن قرار دهیم.
برای مثال:
let str = 'Hi';
str = 'h' + str[1]; // رشته را جایگزین میکنیم
alert( str ); // hi
در بخشهای بعدی مثالهای بیشتری از این خواهیم دید.
تغییر بزرگی و کوچکی حروف
متدهای toLowerCase() و toUpperCase() بزرگی و کوچکی حروف را تغییر میدهند:
alert( 'Interface'.toUpperCase() ); // INTERFACE
alert( 'Interface'.toLowerCase() ); // interface
یا اگر بخواهیم یک کاراکتر را به حرف کوچک آن تبدیل کنیم اینگونه عمل میکنیم:
alert( 'Interface'[0].toLowerCase() ); // 'i'
جستجو برای یک زیر رشته
چند راه برای گشتن به دنبال یک زیر رشته در یک رشته وجود دارد.
متد str.indexOf
متد اول str.indexOf(substr, pos) است.
این متد به دنبال substr
درون str
میگردد، و از موقعیت pos
داده شده شروع میکند، و موقعیتی که زیر رشته مورد نظر پیدا شد یا اگر چیزی پیدا نشد -1
را برمیگرداند.
برای مثال:
let str = 'Widget with id';
alert( str.indexOf('Widget') ); // 0 ،در شروع رشته پیدا شد 'Widget' چون
alert( str.indexOf('widget') ); // -1 ،چیزی پیدا نشد، جستجو به بزرگی یا کوچکی حروف حساس است
alert( str.indexOf("id") ); // 1 ،(است id دارای ..idget) در موقعیت 1 پیدا شد "id"
پارامتر اختیاری دوم به ما اجازه جستجو از موقعیت داده شده را میدهد.
برای مثال، اولین "id"
که وجود دارد در موقعیت 1
است. برای پیدا کردن بعدی، بیایید جستجو را از موقعیت 2
شروع کنیم:
let str = 'Widget with id';
alert( str.indexOf('id', 2) ) // 12
اگر ما مشتاق این هستیم که تمام آنها را پیدا کنیم، میتوانیم indexOf
را دورن یک حلقه اجرا کنیم. تمام صدازدنهای جدید با موقعیتی بعد از موقعیت زیر رشتهی پیدا شده قبلی انجام میشود:
let str = 'As sly as a fox, as strong as an ox';
let target = 'as'; // بیایید به دنبال آن بگردیم
let pos = 0;
while (true) {
let foundPos = str.indexOf(target, pos);
if (foundPos == -1) break;
alert( `Found at ${foundPos}` );
pos = foundPos + 1; // جستجو را از موقعیت بعدی ادامه بده
}
الگوریتم یکسان را میتوان کوتاهتر نوشت:
let str = "As sly as a fox, as strong as an ox";
let target = "as";
let pos = -1;
while ((pos = str.indexOf(target, pos + 1)) != -1) {
alert( pos );
}
متد str.lastIndexOf(substr, position)
یک متد مشابه str.lastIndexOf(substr, position) هم وجود دارد که از انتهای رشته تا آغاز آن جستجو میکند.
این متد زیر رشتههای پیدا شده را با ترتیب برعکس لیست میکند.
یک چیز ناخوشایند در رابطه با indexOf
در if
وجود دارد. ما نمیتوانیم آن را اینگونه درون if
بگذاریم:
let str = "Widget with id";
if (str.indexOf("Widget")) {
alert("We found it"); // !کار نمیکند
}
در مثال بالا alert
نمایش نمیدهد زیرا str.indexOf("Widget")
مقدار 0
را برمیکرداند (به این معنی که زیر رشته مورد نظر را در موقعیت آغازین پیدا کرد). درست است، اما if
مقدار 0
را با false
برابر فرض میکند.
بنابراین، ما باید در واقع -1
را بررسی کنیم، به این شکل:
let str = "Widget with id";
if (str.indexOf("Widget") != -1) {
alert("We found it"); // !حالا کار میکند
}
متدهای includes، startsWith، endsWith
متد مدرنتر str.includes(substr, pos) با وابستگی به اینکه رشته str
درون خودش دارای زیر رشتهی substr
است یا نه مقدار true/false
را برمیگرداند.
اگر نیاز داشته باشیم که وجود یک زیر رشته را بررسی کنیم، اما به موقعیت آن نیازی نداریم این متد انتخاب مناسبی است:
alert( "Widget with id".includes("Widget") ); // true
alert( "Hello".includes("Bye") ); // false
آرگومان دوم و اختیاری str.includes
موقعیتی است که جستجو از آن شروع میشود:
alert( "Widget".includes("id") ); // true
alert( "Widget".includes("id", 3) ); // false وجود ندارد پس "id" از موقعیت 3 هیج
متدهای str.startsWith(بررسی شروع شدن رشته با یک زیر رشته) و str.endsWith(بررسی پایان یافتن رشته با یک زیر رشته) دقیقا کاری را که میگویند انجام میدهند:
alert( "Widget".startsWith("Wid") ); // true شروع میشود پس "Wid" با "Widget"
alert( "Widget".endsWith("get") ); // true پایان مییابد پس "get" با "Widget"
گرفتن یک زیر رشته
در جاوااسکریپت 3 متد برای گرفتن یک زیر رشته وجود دارد: substring
، substr
و slice
.
str.slice(start [, end])
-
قسمتی از رشته را از موقعیت
start
تاend
(شاملend
نمیشود) را برمیگرداند.برای مثال:
let str = "stringify"; alert( str.slice(0, 5) ); // 'strin' :زیر رشته از 0 تا 5 (شامل 5 نمیشود) alert( str.slice(0, 1) ); // 's' :از 0 تا 1، اما شامل 1 نمیشود، پس فقط کاراکتری که در 0 است
اگر هیچ آرگومان دومی در کار نباشد، سپس
slice
تا آخر رشته میرود:let str = "stringify"; alert( str.slice(2) ); // 'ringify' :از موقعیت دوم تا آخر
مقدارهای منفی برای
start/end
هم ممکن هستند. آنها به این معنی هستند که موقعیت از آخر رشته شمارش میشود:let str = "stringify"; // از موقعیت 4 از سمت راست شروع میشود، در موقعیت 1 از سمت راست پایان مییابد alert( str.slice(-4, -1) ); // 'gif'
str.substring(start [, end])
-
قسمتی از رشته بین
start
وend
را برمیگرداند (شاملend
نمیشود).این متد تقریبا مشابه با
slice
است، اما این اجازه را میدهد کهstart
بیشتر ازend
باشد (در این صورت مقدارهایstart
وend
را جابجا میکند).برای مثال:
let str = "stringify"; // یکسان هستند substring این دو برای alert( str.substring(2, 6) ); // "ring" alert( str.substring(6, 2) ); // "ring" // ...اینطور نیست slice اما برای alert( str.slice(2, 6) ); // "ring" (یکسان است) alert( str.slice(6, 2) ); // "" (یک رشته خالی)
آرگومانهای منفی (برخلاف slice) پشتیبانی نمیشوند، با آنها مانند
0
رفتار میشود. str.substr(start [, length])
-
قسمتی از رشته از
start
، تاlength
(طول) داده شده را برمیگرداند.در تضاد با متدهای قبلی، این متد به ما اجازه میدهد که به جای موقعیت پایانی
length
(طول) را تعیین کنیم:let str = "stringify"; alert( str.substr(2, 4) ); // 'ring' :از موقعیت دوم 4 کاراکتر را بگیر
اولین آرگومان میتواند برای شمارش از آخر، منفی باشد:
let str = "stringify"; alert( str.substr(-4, 2) ); // 'gi' :از موقعیت چهارم 2 کاراکتر را بگیر
بیایید این متدها را برای جلوگیری از هر گمراهی خلاصه کنیم:
متد | انتخاب میکند… | منفیها |
---|---|---|
slice(start, end) |
از start تا end (شامل end نمیشود) |
منفیها مجازند |
substring(start, end) |
بین start و end (شامل end نمیشود) |
مقدار منفی به معنای 0 است |
substr(start, length) |
از start به تعداد length کاراکتر میگیرد |
start منفی مجاز است |
تمام آنها میتوانند کار را انجام دهند. به طور رسمی، substr
یک اشکال جزئی دارد: این متد در هسته مشخصات جاوااسکریپت تعریف نشده است، اما در Annex B تعریف شده، که فقط ویژگیهای مختص به مرورگر را پوشش میدهد که به دلایلی مربوط به تاریخچه زبان وجود دارد. پس محیطهایی که مرورگر نباشند ممکن است از آن پشتیبانی نکنند. اما در عمل این متد همهجا کار میکند.
از بین دو متد دیگر، slice
مقداری قابل انعطافتر است، و آرگومانهای منفی را مجاز میداند و برای نوشتن کوتاهتر است.
پس برای استفادههای عملی به یاد داشتن slice
کافی است.
مقایسه رشتهها
همانطور که از فصل مقایسه ها (مقایسهها) میدانیم، رشتهها با ترتیب الفبایی کاراکتر به کاراکتر مقایسه میشوند.
گرچه، جزییاتی وجود دارد.
-
یک حرف کوچک انگلیسی همیشه از حرف بزرگ، بزرگتر است:
alert( 'a' > 'Z' ); // true
-
حروفی که علامت دارند “بدون ترتیب” هستند:
alert( 'Österreich' > 'Zealand' ); // true
اگر ما اسم این کشورها را مرتب کنیم این موضوع ممکن است باعث ایجاد نتایج عجیب شود. معمولا مردم توقع داشند که
Zealand
بعد ازÖsterreich
در لیست بیاید.
<<<<<<< HEAD برای فهمیدن اینکه چه چیزی رخ میدهد، بیایید نمایش داخلی رشتهها را در جاوااسکریپت مرور کنیم.
تمام رشتهها با استفاده از UTF-16 کدگذاری شدهاند. یعنی اینکه: هر کاراکتر یک کد عددی متناظر دارد. متدهای خاصی هستند که گرفتن کد از کاراکتر و برعکس را ممکن میسازند.
To understand what happens, we should be aware that strings in Javascript are encoded using UTF-16. That is: each character has a corresponding numeric code.
There are special methods that allow to get the character for the code and back:
18b1314af4e0ead5a2b10bb4bacd24cecbb3f18e
str.codePointAt(pos)
-
یک عدد دهدهی که نمایانگر کد کاراکتر در موقعیت
pos
است را برمیگرداند:// حروف با بزرگی یا کوچکی متفاوت کدهای متفاوت دارند alert( "z".codePointAt(0) ); // 122
<<<<<<< HEAD alert( “Z”.codePointAt(0) ); // 90 alert( “z”.codePointAt(0).toString(16) ); // 7a (اگر ما به مقدار هگزادسیمال کد نیاز داشته باشیم)
alert( "z".codePointAt(0).toString(16) ); // 7a (if we need a hexadecimal value)
18b1314af4e0ead5a2b10bb4bacd24cecbb3f18e
```
String.fromCodePoint(code)
-
یک کاراکتر با استفاده از
کد
عددی آن میسازد:alert( String.fromCodePoint(90) ); // Z alert( String.fromCodePoint(0x5a) ); // Z (همچنین میتوانیم از یک مقدار هگزادسیمال به عنوان آرگومان استفاده کنیم)
<<<<<<< HEAD
همچنین ما میتوانیم کاراکترهای Unicode را از طریق کد آنها با استفاده از \u
که بعد از آن کد hex میآید اضافه کنیم:
```js run
// 5a عدد 90 در سیستم عددی بر پایه 16 برابر است با
alert( '\u005a' ); // Z
```
حال بیایید با ساختن یک رشته از کاراکترهایی که کد 65..220
دارند آنها را نگاه بیاندازیم (حروف الفبای لاتین و کمی بیشتر):
Now let’s see the characters with codes 65..220
(the latin alphabet and a little bit extra) by making a string of them:
18b1314af4e0ead5a2b10bb4bacd24cecbb3f18e
let str = '';
for (let i = 65; i <= 220; i++) {
str += String.fromCodePoint(i);
}
alert( str );
// Output:
// ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
// ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜ
میبینید؟ کاراکترهای حروف بزرگ اول هستند، سپس چند حرف خاص، سپس کارکترهای حروف کوچک، و Ö
نزدیک به پایان خروجی است.
حالا واضح شد که چرا a > Z
.
کاراکترها از طریق کدهای عددی خود مقایسه میشوند. کد بزرگتر به معنای بزرگتر بودن کاراکتر است. کد a
(97) بزرگتر از کد Z
(90) است.
- تمام حروف کوچک انگلیسی بعد از حروف بزرگ واقع هستند چون کدهای آنها بزرگتر هستند.
- بعضی از حروف مانند
Ö
از حروف الفبای اصلی جدا هستند. اینجا، کد آن از هر چیزی بینa
تاz
بزرگتر است.
مقایسههای صحیح
الگوریتم “درست” برای انجام مقایسه رشتهها پیچیدهتر از چیزی است که بنظر میآید، چون الفبا برای زبانهای مختلف متفاوت است.
پس، مرورگر نیاز دارد که زبان را برای مقایسه کردن بداند.
<<<<<<< HEAD خوشبختانه، تمام مرورگرهای مدرن (IE10 به کتابخانه اضافی Intl.js احتیاج دارد) از استاندارد بینالمللیکردن ECMA-402 پشتیبانی میکنند.
Luckily, modern browsers support the internationalization standard ECMA-402.
18b1314af4e0ead5a2b10bb4bacd24cecbb3f18e
این استاندارد یک متد خاص را برای مقایسه رشتهها در زبانهای مختلف را مهیا میکند که از قوانین خودشان پیروی میشود.
صدازدن str.localeCompare(str2) یک عدد صحیح را برمیگرداند که نشان میدهد آیا str
با توجه به قوانین زبان، کمتر، مساوی یا برابر از str2
هست یا نه:
- اگر
str
کمتر ازstr2
باشد یک عدد منفی برمیگرداند. - اگر
str
بزرگتر ازstr2
باشد یک عدد مثبت برمیگرداند. - اگر آنها برابر باشند
0
را برمیگرداند.
برای مثال:
alert( 'Österreich'.localeCompare('Zealand') ); // -1
این متد دو آرگومان اضافی دارد که در مستندات مشخص شدهاند که به ما اجازه میدهند تا زبان را مشخص کنیم (به طور پیشفرض از شرایط فعلی بدست میآید، ترتیب حروف به زبان بستگی دارد) و قوانین اضافی را ایجاد کنیم مثل حساسیت بزرگی یا کوچکی حرف یا اینکه به یک صورت با "a"
و "á"
رفتار شود و غیره.
<<<<<<< HEAD
داخلیها، Unicode
این بخش بیشتر درون رشتهها پیش میرود. این اطلاعات در صورتی که شما قصد داشته باشید با اموجی، کاراکترهای تصویری نادر ریاضی یا نشانههای نادر دیگر کار کنید برای شما مفید خواهد بود.
کاراکترهای Unicode
همانطور که قبلا هم گفتیم، رشتههای جاوااسکریپت بر اساس Unicode است.
هر کاراکتر توسط یک دنباله از 1-4 بایت نشسان داده میشود.
جاوااسکریپت به ما اجازه میدهد که یک کاراکتر را نه با اضافه کردن آن به یک رشته به صورت مستقیم تعیین کنیم بلکه با استفاده از این سه نشانه توسط کد هگزادسیمال Unicode هم آن را مشخص کنیم:
-
\xXX
– یک کاراکتر که کد Unicode آنU+00XX
است.XX
دو رقم هگزادسیمال با مقداری بین00
وFF
است پس نشانه\xXX
فقط میتواند برای 256 کاراکتر اول Unicode استفاده شود (شامل تمام 128 ASCII کاراکتر میشود).این 256 کاراکتر اول شامل حروف الفبای لاتین، اکثر کاراکترهای سینتکس پایه و دیگر موارد میشوند. برای مثال،
"\x7A"
با"z"
یکسان است (UnicodeU+007A
). -
/uXXXX
– کاراکتری که کد Unicode آنU+XXXX
است (یک کاراکتر با کد هگزادسیمالXXXX
به صورت UTF-16 کدگذاری شده است).XXXX
باید دقیقا 4 رقم و با مقداری بین0000
وFFFF
باشد پس نشانه\uXXXX
میتواند برای 65536 کاراکتر اول استفاده شود. کاراکترهایی با مقدار Unicode بیشتر ازU+FFFF
هم میتوانند با این نشانه نمایش داده شوند اما در این صورت ما باید از چیزی به اصطلاح surrogate pair (ترجمه: جفت جایگیر) استفاده کنیم (درباره این جفت کمی بعدتر در این مقاله صحبت میکنیم). -
u{X…XXXXXX}
– کاراکتری با هر کد Unicode (یک کاراکتر با کد هگزادسیمال که به صورت UTF-32 کدگذاری شده است).X…XXXXXX
باید مقداری هگزادسیمال با 1 تا 6 بایت بین0
و10FFFF
باشد (بزرگترین کد تعریف شده توسط Unicode). این نشانه به ما اجازه میدهد تا به سادگی تمام کاراکترهای Unicode موجود را نمایش دهیم.
مثالهایی با Unicode:
alert( "\uA9" ); // © ،علامت کپیرایت
alert( "\u00A9" ); // © ،مانند بالا، با استفاده از نشانه هگزادسیمال 4 رقمی
alert( "\u044F" ); // я ،cyrillic حرف الفبای
alert( "\u2191" ); // ↑, نماد کمان رو به بالا
alert( "\u{20331}" ); // 佫 ،(طولانی Unicode) یک حرف تصویری چینی کمیاب
alert( "\u{1F60D}" ); // 😍 ،(طولانی دیگر Unicode یک) یک نماد صورت خندان
جفتهای جایگیر
تمام کاراکترهایی که اکثر اوقات استفاده میشوند کدهای 2 بایتی دارند. حروف در اکثر زبانهای اروپایی، اعداد، و حتی اکثر حروف تصویری، یک نمایش 2 بایتی دارند.
در ابتدا، جاوااسکریپت بر اساس کدگذاری UTF-16 بود که فقط 2 بایت به ازای هر کاراکتر را ممکن میساخت. اما 2 بایت فقط 65536 ترکیب را ممکن میسازد و این مقدار برای هر نشانه موجود کافی نیست.
پس نمادهای نادر با جفتی از کاراکترهای 2 بایتی که “جفت جایگیر” (surrogate pair) هم نامیده میشوند کدگذاری میشوند.
به عنوان یک عارضه جانبی، طول چنین نشانههایی 2
است:
alert( '𝒳'.length ); // 2، X اسکریپت ریاضی حرف بزرگ
alert( '😂'.length ); // 2، صورت با اشک شوق
alert( '𩷶'.length ); // 2، یک حرف تصویری نادر چینی
دلیلش این است که جفتهای جایگیر زمانی که جاوااسکریپت ساخته شد وجود نداشتند، و به این دلیل در حال حاضر توسط زبان به درستی پردازش نمیشوند!
ما در واقع در هر یک از رشتههای بالا یک نشانه مفرد داریم، اما length
طول 2
را نشان میدهد.
گرفتن یک نشانه میتواند آسان نباشد، چون بیشتر خاصیتهای زبان با جفتهای جایگیر مثل دو کاراکتر رفتار میکنند.
برای مثال، ما اینجا دو کاراکتر عجیب را در خروجی میتوانیم ببینیم:
alert( '𝒳'[0] ); // ...نشانههای عجیب
alert( '𝒳'[1] ); // قطعههایی از جفت جایگیر...
توجه کنید که قطعههای جفت جایگیر بدون یکدیگر هیچ معنیای ندارند. پس alertها در مثال بالا در واقع چیزهای بدرد نخور نمایش میدهند.
به طور فنی، جفتهای جایگیر هم با کدهای خود قابل شناسایی هستند: اگر یک کاراکتر کدی در فاصله 0xd800..0xdbff
داشته باشد، پس قطعه اول یک جفت جایگیر است. کاراکتر بعدی (قطعه دوم) باید کدی در فاصله 0xdc00..0xdfff
داشته باشد. این بازهها به طور اختصاصی برای جفتهای جایگیر رزرو شدهاند.
پس متدهای String.fromCodePoint
و str.codePointAt
برای کار کردن با جفتهای جایگیر به جاوااسکریپت اضافه شدند.
آنها اساسا با String.fromCharCode و str.charCodeAt یکسان هستند اما با جفتهای جایگیر به درستی رفتار میکنند.
میتوانید تفاوت را اینجا ببینید:
// را نتیجه میدهد 𝒳 جفتهای جایگیر را نمیناسد پس کد اولین قسمت charCodeAt
alert( '𝒳'.charCodeAt(0).toString(16) ); // d835
// جفتهای جایگیر را میشناسد codePointAt
alert( '𝒳'.codePointAt(0).toString(16) ); // 1d4b3 ،هر دو قسمت جفت جایگیر را میخواند
با این حال، اگر ما از موقعیت 1 انتخاب کنیم (و این کار اینجا اشتباه است)، سپس هر دوی آنها فقط قسمت دوم جفت را برمیگردانند:
alert( '𝒳'.charCodeAt(1).toString(16) ); // dcb3
alert( '𝒳'.codePointAt(1).toString(16) ); // dcb3
// قسمت دوم بیمعنای جفت
شما راههای بیشتری را برای کارکردن با جفتهای جایگیر را در فصل حلقهپذیرها میآموزید. همچنین احتمالا کتابخانههای خاصی برای آنها وجود دارد، اما هیج کدام به اندازه کافی معروف نیستند تا اینجا معرفی شوند.
We can’t just split a string at an arbitrary position, e.g. take str.slice(0, 4)
and expect it to be a valid string, e.g.:
ما نمیتوانیم یک رشته را در یک نقطه دلخواه جدا کنیم مثلا str.slic(0, 4)
را در نظر بگیریم و تقوع یک رشته معتبر را داشته باشیم، مثلا:
alert( 'hi 😂'.slice(0, 4) ); // hi [?]
اینجا میتوانیم یک کاراکتر بدرد نخور را در خروجی ببینیم (اولین قسمت از جفت جایگیر علامت خنده).
اگر میخواهید با اعتماد کامل با جفتهای جایگیر کار کنید از این موضوع آگاه باشید. شاید مشکل بزرگی نباشد اما شما حداقل باید بدانید که اتفاقی میافتد.
نشانههای تفکیک کننده و عادیسازی
در بسیاری از زبانها نشانههایی وجود دارند که ترکیبی از یک کاراکتر پایه و یک علامت در بالا/پایین آن هستند.
برای مثال، حرف a
حرف پایه برای àáâäãåā
است.
اکثر کاراکترهای «ترکیبشده» متداول کد خود را در جدول UTF-16 دارند. اما نه همه آنها، چون ترکیبات ممکن بسیار زیادی وجود دارد.
برای پشتیبانی از ترکیبات دلخواه، UTF-16 به ما اجازه میدهد که از چند کاراکتر Unicode استفاده کنیم: کاراکتر پایه که بعد از آن یک یا چند کاراکتر «علامت» میآید که آن را «زیبا میکند».
برای مثال، اگر ما یک حرف S
داشته باشیم که بعد از آن کاراکتر خاص «نقطه بالا» آمده باشد (کد \u0307
)، به صورت Ṡ نمایش داده میشود.
alert( 'S\u0307' ); // Ṡ
اگر ما نیاز به یک علامت اضافی در بالای حرف داشته باشیم (یا پایین آن)، مشکلی نیست، فقط کاراکتر علامت مورد نیاز را اضافه میکنیم.
برای مثال، اگر ما یک کاراکتر «نقطه پایین» (کد \u0323
) را ضمیمه کنیم، سپس ما «حرف S با نقطههایی در بالا و پایین آن» خوهیم داشت: Ṩ
.
برای مثال:
alert( 'S\u0307\u0323' ); // Ṩ
این روش انعطاف زیادی را مهیا میکند، اما یک مشکل جالب هم دارد: دو کاراکتر ممکن است که ظاهر یکسانی داشته باشند، اما با ترکیبات Unicode متفاوت نمایش داده شوند.
برای مثال:
let s1 = 'S\u0307\u0323'; // Ṩ ،نقطه بالا + نقطه پایین + S
let s2 = 'S\u0323\u0307'; // Ṩ ،نقطه پایین + نقطه بالا + S
alert( `s1: ${s1}, s2: ${s2}` );
alert( s1 == s2 ); // (!؟)میشود false با اینکه کاراکترها مشابه هستند اما
برای رفع این مشکل، یک الگوریتم «عادیسازی Unicode» وجود دارد که هر رشته را به یک شکل «عادی» درمیآورد.
این الگوریتم با str.normalize() پیادهسازی میشود.
alert( "S\u0307\u0323".normalize() == "S\u0323\u0307".normalize() ); // true
موضوع بامزهای است که در این مورد ما normalize()
در واقع یک دنباله از 3 کاراکتر را به یک کاراکتر تبدیل میکند: \u1e68
(S به همراه دو نقطه).
alert( "S\u0307\u0323".normalize().length ); // 1
alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true
در واقعیت، همیشه این مورد پیش نمیآید. به دلیل اینکه نماد Ṩ
به اندازه «کافی» متداول است، پس سازندگان Unicode آن را در جدول اصلی آوردند و به آن یک کد دادند.
اگر شما میخواهید درباره قوانین و انواع عادیسازی بدانید، آنها در ضمیمه استاندارد Unicode تعریف شدهاند: شکلهای عادیسازی Unicode، اما برای اکثر کارهای عملی و کاربردی اطلاعات این بخش کافی است.
خلاصه
- 3 نوع کوتیشن وجود دارد. Backtickها به ما این امکان را میدهند که رشته را به چند خط تقسیم کنیم و عبارتهایی را درون رشته جایگذاری کنیم
${…}
. - رشتهها در جاوااسکریپت با استفاده از UTF-16 کدگذاری شدهاند.
- ما میتوانیم از کاراکترهای خاص مانند
\n
استفاده کنیم و حروف را از طریق کد Unicode آنها با استفاده از\u...
بنویسیم. - برای گرفتن یک کاراکتر، از
[]
استفاده کنید. - برای گرفتن یک زیر رشته از
slice
یاsubstring
استفاده کنید. - برای تغییر بزرگی یا کوچکی حروف انگلیسی یک رشته، از
toLowerCase/toUpperCase
استفاده کنید. - برای گشتن به دنبال یک زیر رشته از
indexOf
یا برای بررسیهای ساده ازincludes/startsWith/endsWith
استفاده کنید. - برای مقایسه رشتهها با توجه به زبان آنها، از
localeCompare
استفاده کنید، در غیر این صورت آنها توسط کدهای کاراکتر مقایسه میشوند. =======
Summary
- There are 3 types of quotes. Backticks allow a string to span multiple lines and embed expressions
${…}
. - We can use special characters, such as a line break
\n
. - To get a character, use:
[]
orat
method. - To get a substring, use:
slice
orsubstring
. - To lowercase/uppercase a string, use:
toLowerCase/toUpperCase
. - To look for a substring, use:
indexOf
, orincludes/startsWith/endsWith
for simple checks. - To compare strings according to the language, use:
localeCompare
, otherwise they are compared by character codes.
18b1314af4e0ead5a2b10bb4bacd24cecbb3f18e
چند متد دیگر هم برای رشتهها وجود دارد:
str.trim()
– فاصله را از ابتدا و انتهای رشته حذف میکند («میتراشد»).str.repeat(n)
– رشته راn
بار تکرار میکند.- …و متدهای بیشتری در مستندات وجود دارند.
<<<<<<< HEAD رشتهها متدهایی را برای جستجو/جایگزینکردن عبارات با قاعده (regular expression) دارند. اما این یک بحث بزرگ است، پس در یک قسمت جدای این آموزش عبارات باقاعده (Regular Expression) توضیح داده شده است.
Strings also have methods for doing search/replace with regular expressions. But that’s big topic, so it’s explained in a separate tutorial section عبارات باقاعده (Regular Expression).
Also, as of now it’s important to know that strings are based on Unicode encoding, and hence there’re issues with comparisons. There’s more about Unicode in the chapter یونیکد، درون رشتهها. <<<<<<< HEAD
18b1314af4e0ead5a2b10bb4bacd24cecbb3f18e ======= 8d9ecb724c7df59774d1e5ffb5e5167740b7d321