From add7ca6a09d63c209a87e8faca015acc340f83ae Mon Sep 17 00:00:00 2001 From: I_am_Vietnam <91591390+ImVietnam@users.noreply.github.com> Date: Thu, 8 Jun 2023 16:23:57 +0700 Subject: [PATCH 1/6] Create 06-unicode --- 1-js/99-js-misc/06-unicode | 1 + 1 file changed, 1 insertion(+) create mode 100644 1-js/99-js-misc/06-unicode diff --git a/1-js/99-js-misc/06-unicode b/1-js/99-js-misc/06-unicode new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/1-js/99-js-misc/06-unicode @@ -0,0 +1 @@ + From 7fbfdabaf0c1643f10906550e24e0ae0a4c9d8d0 Mon Sep 17 00:00:00 2001 From: I_am_Vietnam <91591390+ImVietnam@users.noreply.github.com> Date: Thu, 8 Jun 2023 16:25:01 +0700 Subject: [PATCH 2/6] Delete 06-unicode --- 1-js/99-js-misc/06-unicode | 1 - 1 file changed, 1 deletion(-) delete mode 100644 1-js/99-js-misc/06-unicode diff --git a/1-js/99-js-misc/06-unicode b/1-js/99-js-misc/06-unicode deleted file mode 100644 index 8b1378917..000000000 --- a/1-js/99-js-misc/06-unicode +++ /dev/null @@ -1 +0,0 @@ - From 85d5c201f3a260a58e6aa3d37e475358c587571a Mon Sep 17 00:00:00 2001 From: I_am_Vietnam <91591390+ImVietnam@users.noreply.github.com> Date: Thu, 8 Jun 2023 16:26:34 +0700 Subject: [PATCH 3/6] Create article.md --- 1-js/99-js-misc/06-unicode/article.md | 172 ++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 1-js/99-js-misc/06-unicode/article.md diff --git a/1-js/99-js-misc/06-unicode/article.md b/1-js/99-js-misc/06-unicode/article.md new file mode 100644 index 000000000..4f144f824 --- /dev/null +++ b/1-js/99-js-misc/06-unicode/article.md @@ -0,0 +1,172 @@ + +# Unicode, String internals + +```warn header="Advanced knowledge" +The section goes deeper into string internals. This knowledge will be useful for you if you plan to deal with emoji, rare mathematical or hieroglyphic characters, or other rare symbols. +``` + +As we already know, JavaScript strings are based on [Unicode](https://en.wikipedia.org/wiki/Unicode): each character is represented by a byte sequence of 1-4 bytes. + +JavaScript allows us to insert a character into a string by specifying its hexadecimal Unicode code with one of these three notations: + +- `\xXX` + + `XX` must be two hexadecimal digits with a value between `00` and `FF`, then `\xXX` is the character whose Unicode code is `XX`. + + Because the `\xXX` notation supports only two hexadecimal digits, it can be used only for the first 256 Unicode characters. + + These first 256 characters include the Latin alphabet, most basic syntax characters, and some others. For example, `"\x7A"` is the same as `"z"` (Unicode `U+007A`). + + ```js run + alert( "\x7A" ); // z + alert( "\xA9" ); // ©, the copyright symbol + ``` + +- `\uXXXX` + `XXXX` must be exactly 4 hex digits with the value between `0000` and `FFFF`, then `\uXXXX` is the character whose Unicode code is `XXXX`. + + Characters with Unicode values greater than `U+FFFF` can also be represented with this notation, but in this case, we will need to use a so called surrogate pair (we will talk about surrogate pairs later in this chapter). + + ```js run + alert( "\u00A9" ); // ©, the same as \xA9, using the 4-digit hex notation + alert( "\u044F" ); // я, the Cyrillic alphabet letter + alert( "\u2191" ); // ↑, the arrow up symbol + ``` + +- `\u{X…XXXXXX}` + + `X…XXXXXX` must be a hexadecimal value of 1 to 6 bytes between `0` and `10FFFF` (the highest code point defined by Unicode). This notation allows us to easily represent all existing Unicode characters. + + ```js run + alert( "\u{20331}" ); // 佫, a rare Chinese character (long Unicode) + alert( "\u{1F60D}" ); // 😍, a smiling face symbol (another long Unicode) + ``` + +## Surrogate pairs + +All frequently used characters have 2-byte codes (4 hex digits). Letters in most European languages, numbers, and the basic unified CJK ideographic sets (CJK -- from Chinese, Japanese, and Korean writing systems), have a 2-byte representation. + +Initially, JavaScript was based on UTF-16 encoding that only allowed 2 bytes per character. But 2 bytes only allow 65536 combinations and that's not enough for every possible symbol of Unicode. + +So rare symbols that require more than 2 bytes are encoded with a pair of 2-byte characters called "a surrogate pair". + +As a side effect, the length of such symbols is `2`: + +```js run +alert( '𝒳'.length ); // 2, MATHEMATICAL SCRIPT CAPITAL X +alert( '😂'.length ); // 2, FACE WITH TEARS OF JOY +alert( '𩷶'.length ); // 2, a rare Chinese character +``` + +That's because surrogate pairs did not exist at the time when JavaScript was created, and thus are not correctly processed by the language! + +We actually have a single symbol in each of the strings above, but the `length` property shows a length of `2`. + +Getting a symbol can also be tricky, because most language features treat surrogate pairs as two characters. + +For example, here we can see two odd characters in the output: + +```js run +alert( '𝒳'[0] ); // shows strange symbols... +alert( '𝒳'[1] ); // ...pieces of the surrogate pair +``` + +Pieces of a surrogate pair have no meaning without each other. So the alerts in the example above actually display garbage. + +Technically, surrogate pairs are also detectable by their codes: if a character has the code in the interval of `0xd800..0xdbff`, then it is the first part of the surrogate pair. The next character (second part) must have the code in interval `0xdc00..0xdfff`. These intervals are reserved exclusively for surrogate pairs by the standard. + +So the methods [String.fromCodePoint](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint) and [str.codePointAt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt) were added in JavaScript to deal with surrogate pairs. + +They are essentially the same as [String.fromCharCode](mdn:js/String/fromCharCode) and [str.charCodeAt](mdn:js/String/charCodeAt), but they treat surrogate pairs correctly. + +One can see the difference here: + +```js run +// charCodeAt is not surrogate-pair aware, so it gives codes for the 1st part of 𝒳: + +alert( '𝒳'.charCodeAt(0).toString(16) ); // d835 + +// codePointAt is surrogate-pair aware +alert( '𝒳'.codePointAt(0).toString(16) ); // 1d4b3, reads both parts of the surrogate pair +``` + +That said, if we take from position 1 (and that's rather incorrect here), then they both return only the 2nd part of the pair: + +```js run +alert( '𝒳'.charCodeAt(1).toString(16) ); // dcb3 +alert( '𝒳'.codePointAt(1).toString(16) ); // dcb3 +// meaningless 2nd half of the pair +``` + +You will find more ways to deal with surrogate pairs later in the chapter . There are probably special libraries for that too, but nothing famous enough to suggest here. + +````warn header="Takeaway: splitting strings at an arbitrary point is dangerous" +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.: + +```js run +alert( 'hi 😂'.slice(0, 4) ); // hi [?] +``` + +Here we can see a garbage character (first half of the smile surrogate pair) in the output. + +Just be aware of it if you intend to reliably work with surrogate pairs. May not be a big problem, but at least you should understand what happens. +```` + +## Diacritical marks and normalization + +In many languages, there are symbols that are composed of the base character with a mark above/under it. + +For instance, the letter `a` can be the base character for these characters: `àáâäãåā`. + +Most common "composite" characters have their own code in the Unicode table. But not all of them, because there are too many possible combinations. + +To support arbitrary compositions, the Unicode standard allows us to use several Unicode characters: the base character followed by one or many "mark" characters that "decorate" it. + +For instance, if we have `S` followed by the special "dot above" character (code `\u0307`), it is shown as Ṡ. + +```js run +alert( 'S\u0307' ); // Ṡ +``` + +If we need an additional mark above the letter (or below it) -- no problem, just add the necessary mark character. + +For instance, if we append a character "dot below" (code `\u0323`), then we'll have "S with dots above and below": `Ṩ`. + +For example: + +```js run +alert( 'S\u0307\u0323' ); // Ṩ +``` + +This provides great flexibility, but also an interesting problem: two characters may visually look the same, but be represented with different Unicode compositions. + +For instance: + +```js run +let s1 = 'S\u0307\u0323'; // Ṩ, S + dot above + dot below +let s2 = 'S\u0323\u0307'; // Ṩ, S + dot below + dot above + +alert( `s1: ${s1}, s2: ${s2}` ); + +alert( s1 == s2 ); // false though the characters look identical (?!) +``` + +To solve this, there exists a "Unicode normalization" algorithm that brings each string to the single "normal" form. + +It is implemented by [str.normalize()](mdn:js/String/normalize). + +```js run +alert( "S\u0307\u0323".normalize() == "S\u0323\u0307".normalize() ); // true +``` + +It's funny that in our situation `normalize()` actually brings together a sequence of 3 characters to one: `\u1e68` (S with two dots). + +```js run +alert( "S\u0307\u0323".normalize().length ); // 1 + +alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true +``` + +In reality, this is not always the case. The reason is that the symbol `Ṩ` is "common enough", so Unicode creators included it in the main table and gave it the code. + +If you want to learn more about normalization rules and variants -- they are described in the appendix of the Unicode standard: [Unicode Normalization Forms](https://www.unicode.org/reports/tr15/), but for most practical purposes the information from this section is enough. From afadb20da6dfdb9a45a71c41126d53d77dfcdbe1 Mon Sep 17 00:00:00 2001 From: I_am_Vietnam <91591390+ImVietnam@users.noreply.github.com> Date: Thu, 8 Jun 2023 16:52:18 +0700 Subject: [PATCH 4/6] Update article.md --- 1-js/99-js-misc/06-unicode/article.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/1-js/99-js-misc/06-unicode/article.md b/1-js/99-js-misc/06-unicode/article.md index 4f144f824..5b32268ba 100644 --- a/1-js/99-js-misc/06-unicode/article.md +++ b/1-js/99-js-misc/06-unicode/article.md @@ -1,19 +1,19 @@ -# Unicode, String internals +# Unicode, Nội bộ chuỗi -```warn header="Advanced knowledge" -The section goes deeper into string internals. This knowledge will be useful for you if you plan to deal with emoji, rare mathematical or hieroglyphic characters, or other rare symbols. +```warn header="Kiến thức nâng cao" +Phần này đi sâu hơn vào bên trong chuỗi. Kiến thức này sẽ hữu ích cho bạn nếu bạn định xử lý biểu tượng cảm xúc, ký tự toán học hoặc chữ tượng hình hiếm hoặc các ký hiệu hiếm khác. ``` -As we already know, JavaScript strings are based on [Unicode](https://en.wikipedia.org/wiki/Unicode): each character is represented by a byte sequence of 1-4 bytes. +Như chúng ta đã biết, chuỗi JavaScript dựa trên [Unicode](https://en.wikipedia.org/wiki/Unicode): mỗi ký tự được đại diện bởi một chuỗi byte 1-4 byte. -JavaScript allows us to insert a character into a string by specifying its hexadecimal Unicode code with one of these three notations: +JavaScript cho phép chúng ta chèn một ký tự vào một chuỗi bằng cách chỉ định mã Unicode thập lục phân của nó bằng một trong ba ký hiệu sau: - `\xXX` - `XX` must be two hexadecimal digits with a value between `00` and `FF`, then `\xXX` is the character whose Unicode code is `XX`. + `XX` phải là hai chữ số thập lục phân có giá trị từ `00` đến `FF` thì `\xXX` là ký tự có mã Unicode là `XX`. - Because the `\xXX` notation supports only two hexadecimal digits, it can be used only for the first 256 Unicode characters. + Vì ký hiệu `\xXX` chỉ hỗ trợ hai chữ số thập lục phân, nên ký hiệu này chỉ có thể được sử dụng cho 256 ký tự Unicode đầu tiên. These first 256 characters include the Latin alphabet, most basic syntax characters, and some others. For example, `"\x7A"` is the same as `"z"` (Unicode `U+007A`). From 4dd60d98f20ca0597300742c2e116da2e0c2e468 Mon Sep 17 00:00:00 2001 From: I_am_Vietnam <91591390+ImVietnam@users.noreply.github.com> Date: Thu, 8 Jun 2023 20:52:36 +0700 Subject: [PATCH 5/6] Update article.md --- 1-js/99-js-misc/06-unicode/article.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/1-js/99-js-misc/06-unicode/article.md b/1-js/99-js-misc/06-unicode/article.md index 5b32268ba..29b0a6cae 100644 --- a/1-js/99-js-misc/06-unicode/article.md +++ b/1-js/99-js-misc/06-unicode/article.md @@ -1,5 +1,5 @@ -# Unicode, Nội bộ chuỗi +# Unicode, Bên trong chuỗi ```warn header="Kiến thức nâng cao" Phần này đi sâu hơn vào bên trong chuỗi. Kiến thức này sẽ hữu ích cho bạn nếu bạn định xử lý biểu tượng cảm xúc, ký tự toán học hoặc chữ tượng hình hiếm hoặc các ký hiệu hiếm khác. @@ -15,17 +15,17 @@ JavaScript cho phép chúng ta chèn một ký tự vào một chuỗi bằng c Vì ký hiệu `\xXX` chỉ hỗ trợ hai chữ số thập lục phân, nên ký hiệu này chỉ có thể được sử dụng cho 256 ký tự Unicode đầu tiên. - These first 256 characters include the Latin alphabet, most basic syntax characters, and some others. For example, `"\x7A"` is the same as `"z"` (Unicode `U+007A`). + 256 ký tự đầu tiên này bao gồm bảng chữ cái La-tinh, phần lớn kí tự cú pháp đơn giản, và một số ký tự khác. Ví dụ, `"\x7A"` giống như `"z"` (Unicode `U+007A`). ```js run alert( "\x7A" ); // z - alert( "\xA9" ); // ©, the copyright symbol + alert( "\xA9" ); // ©, ký hiệu bản quyền ``` - `\uXXXX` - `XXXX` must be exactly 4 hex digits with the value between `0000` and `FFFF`, then `\uXXXX` is the character whose Unicode code is `XXXX`. + `XXXX` phải có chính xác 4 chữ số hex với giá trị giữa `0000` và `FFFF`, sau đó `\uXXXX` là ký tự có mã Unicode là `XXXX`. - Characters with Unicode values greater than `U+FFFF` can also be represented with this notation, but in this case, we will need to use a so called surrogate pair (we will talk about surrogate pairs later in this chapter). + Các ký tự với giá trị Unicode lớn hơn `U+FFFF` cũng có thể được đại diện với ký hiệu này, nhưng trong trường hợp này, chúng ta sẽ cần phải sử dụng cái gọi là cặp thay thế (chúng ta sẽ nói về cặp thay thế sau trong chương này). ```js run alert( "\u00A9" ); // ©, the same as \xA9, using the 4-digit hex notation From ebab0bfa7ec5567f2b9534e1ac761cb3efde45a3 Mon Sep 17 00:00:00 2001 From: I_am_Vietnam <91591390+ImVietnam@users.noreply.github.com> Date: Fri, 9 Jun 2023 12:33:03 +0700 Subject: [PATCH 6/6] Update article.md --- 1-js/99-js-misc/06-unicode/article.md | 112 +++++++++++++------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/1-js/99-js-misc/06-unicode/article.md b/1-js/99-js-misc/06-unicode/article.md index 29b0a6cae..feabeddb1 100644 --- a/1-js/99-js-misc/06-unicode/article.md +++ b/1-js/99-js-misc/06-unicode/article.md @@ -25,141 +25,141 @@ JavaScript cho phép chúng ta chèn một ký tự vào một chuỗi bằng c - `\uXXXX` `XXXX` phải có chính xác 4 chữ số hex với giá trị giữa `0000` và `FFFF`, sau đó `\uXXXX` là ký tự có mã Unicode là `XXXX`. - Các ký tự với giá trị Unicode lớn hơn `U+FFFF` cũng có thể được đại diện với ký hiệu này, nhưng trong trường hợp này, chúng ta sẽ cần phải sử dụng cái gọi là cặp thay thế (chúng ta sẽ nói về cặp thay thế sau trong chương này). + Các ký tự với giá trị Unicode lớn hơn `U+FFFF` cũng có thể được biểu diễn với ký hiệu này, nhưng trong trường hợp này, chúng ta sẽ cần phải sử dụng cái gọi là cặp thay thế (chúng ta sẽ nói về cặp thay thế sau trong chương này). ```js run - alert( "\u00A9" ); // ©, the same as \xA9, using the 4-digit hex notation - alert( "\u044F" ); // я, the Cyrillic alphabet letter - alert( "\u2191" ); // ↑, the arrow up symbol + alert( "\u00A9" ); // ©, giống như \xA9, sử dụng ký hiệu hex 4 chữ số + alert( "\u044F" ); // я, chữ cái trong bảng chữ cái Cyrillic + alert( "\u2191" ); // ↑, biểu tượng mũi tên lên ``` - `\u{X…XXXXXX}` - `X…XXXXXX` must be a hexadecimal value of 1 to 6 bytes between `0` and `10FFFF` (the highest code point defined by Unicode). This notation allows us to easily represent all existing Unicode characters. + `X…XXXXXX` phải là giá trị thập lục phân từ 1 đến 6 byte trong khoảng từ `0` đến `10FFFF` (điểm mã cao nhất do Unicode xác định). Ký hiệu này cho phép chúng ta dễ dàng biểu diễn tất cả các ký tự Unicode hiện có. ```js run - alert( "\u{20331}" ); // 佫, a rare Chinese character (long Unicode) - alert( "\u{1F60D}" ); // 😍, a smiling face symbol (another long Unicode) + alert( "\u{20331}" ); // 佫, một ký tự tiếng Trung hiếm (mã Unicode dài) + alert( "\u{1F60D}" ); // 😍, một biểu tượng mặt cười (một mã Unicode dài khác) ``` -## Surrogate pairs +## Cặp thay thế -All frequently used characters have 2-byte codes (4 hex digits). Letters in most European languages, numbers, and the basic unified CJK ideographic sets (CJK -- from Chinese, Japanese, and Korean writing systems), have a 2-byte representation. +Tất cả các ký tự được sử dụng thường xuyên đều có mã 2 byte (4 chữ số hex). Các chữ cái trong hầu hết các ngôn ngữ châu Âu, số và bộ ký tự CJK thống nhất cơ bản (CJK - từ hệ thống chữ viết của Trung Quốc, Nhật Bản và Hàn Quốc), có biểu diễn 2 byte. -Initially, JavaScript was based on UTF-16 encoding that only allowed 2 bytes per character. But 2 bytes only allow 65536 combinations and that's not enough for every possible symbol of Unicode. +Ban đầu, JavaScript dựa trên mã hóa UTF-16 chỉ cho phép 2 byte cho mỗi ký tự. Nhưng 2 byte chỉ cho phép 65536 kết hợp và điều đó là không đủ cho mọi ký hiệu Unicode có thể có. -So rare symbols that require more than 2 bytes are encoded with a pair of 2-byte characters called "a surrogate pair". +Vì vậy, các ký hiệu hiếm yêu cầu nhiều hơn 2 byte được mã hóa bằng một cặp ký tự 2 byte được gọi là "cặp thay thế". -As a side effect, the length of such symbols is `2`: +Như một tác dụng phụ, độ dài của các ký hiệu như vậy là `2`: ```js run -alert( '𝒳'.length ); // 2, MATHEMATICAL SCRIPT CAPITAL X -alert( '😂'.length ); // 2, FACE WITH TEARS OF JOY -alert( '𩷶'.length ); // 2, a rare Chinese character +alert( '𝒳'.length ); // 2, CHỮ X IN HOA TRONG TOÁN HỌC +alert( '😂'.length ); // 2, KHUÔN MẶT VỚI NHỮNG GIỌT NƯỚC MẮT HẠNH PHÚC +alert( '𩷶'.length ); // 2, một Ký tự Trung Quốc hiếm ``` -That's because surrogate pairs did not exist at the time when JavaScript was created, and thus are not correctly processed by the language! +Đó là bởi vì các cặp thay thế không tồn tại vào thời điểm JavaScript được tạo ra và do đó không được ngôn ngữ xử lý chính xác! -We actually have a single symbol in each of the strings above, but the `length` property shows a length of `2`. +Chúng ta thực sự có một ký hiệu duy nhất trong mỗi chuỗi ở trên, nhưng thuộc tính `length` hiển thị độ dài là `2`. -Getting a symbol can also be tricky, because most language features treat surrogate pairs as two characters. +Lấy một ký hiệu cũng có thể khó khăn, bởi vì hầu hết các tính năng ngôn ngữ coi các cặp thay thế là hai ký tự. -For example, here we can see two odd characters in the output: +Ví dụ, ở đây chúng ta có thể thấy hai ký tự lẻ trong đầu ra: ```js run -alert( '𝒳'[0] ); // shows strange symbols... -alert( '𝒳'[1] ); // ...pieces of the surrogate pair +alert( '𝒳'[0] ); // hiện những ký tự lạ... +alert( '𝒳'[1] ); // ...các mảnh của cặp thay thế ``` -Pieces of a surrogate pair have no meaning without each other. So the alerts in the example above actually display garbage. +Các mảnh của một cặp thay thế không có ý nghĩa gì nếu không có nhau. Vì vậy, các cảnh báo trong ví dụ trên thực sự hiển thị rác. -Technically, surrogate pairs are also detectable by their codes: if a character has the code in the interval of `0xd800..0xdbff`, then it is the first part of the surrogate pair. The next character (second part) must have the code in interval `0xdc00..0xdfff`. These intervals are reserved exclusively for surrogate pairs by the standard. +Về mặt kỹ thuật, các cặp thay thế cũng có thể được phát hiện bằng mã của chúng: nếu một ký tự có mã trong khoảng `0xd800..0xdbff`, thì đó là phần đầu tiên của cặp thay thế. Ký tự tiếp theo (phần thứ hai) phải có mã trong khoảng `0xdc00..0xdfff`. Các khoảng thời gian này được dành riêng cho các cặp thay thế theo tiêu chuẩn. -So the methods [String.fromCodePoint](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint) and [str.codePointAt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt) were added in JavaScript to deal with surrogate pairs. +Vì vậy, các phương thức [String.fromCodePoint](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint) và [str.codePointAt](https://developer. mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt) đã được thêm vào JavaScript để xử lý các cặp thay thế. -They are essentially the same as [String.fromCharCode](mdn:js/String/fromCharCode) and [str.charCodeAt](mdn:js/String/charCodeAt), but they treat surrogate pairs correctly. +Về cơ bản, chúng giống như [String.fromCharCode](mdn:js/String/fromCharCode) và [str.charCodeAt](mdn:js/String/charCodeAt), nhưng chúng xử lý chính xác các cặp thay thế. -One can see the difference here: +Ta có thể thấy sự khác biệt ở đây: ```js run -// charCodeAt is not surrogate-pair aware, so it gives codes for the 1st part of 𝒳: +// charCodeAt không nhận biết cặp thay thế, vì vậy nó cung cấp mã cho phần đầu tiên của 𝒳: alert( '𝒳'.charCodeAt(0).toString(16) ); // d835 -// codePointAt is surrogate-pair aware -alert( '𝒳'.codePointAt(0).toString(16) ); // 1d4b3, reads both parts of the surrogate pair +// codePointAt nhận biết cặp thay thế +alert( '𝒳'.codePointAt(0).toString(16) ); // 1d4b3, đọc cả hai phần của cặp thay thế ``` -That said, if we take from position 1 (and that's rather incorrect here), then they both return only the 2nd part of the pair: +Điều đó nói rằng, nếu chúng ta lấy từ vị trí 1 (và điều đó khá sai ở đây), thì cả hai đều chỉ trả về phần thứ 2 của cặp: ```js run alert( '𝒳'.charCodeAt(1).toString(16) ); // dcb3 alert( '𝒳'.codePointAt(1).toString(16) ); // dcb3 -// meaningless 2nd half of the pair +// nửa sau của cặp vô nghĩa ``` -You will find more ways to deal with surrogate pairs later in the chapter . There are probably special libraries for that too, but nothing famous enough to suggest here. +Bạn sẽ tìm thấy nhiều cách hơn để xử lý các cặp thay thế ở phần sau của chương . Có lẽ cũng có những thư viện đặc biệt cho điều đó, nhưng không có gì đủ nổi tiếng để đề xuất ở đây. -````warn header="Takeaway: splitting strings at an arbitrary point is dangerous" -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.: +````warn header="Điều rút ra: tách chuỗi tại một điểm tùy ý là nguy hiểm" +Chúng ta không thể tách một chuỗi ở một vị trí tùy ý, ví dụ: lấy `str.slice(0, 4)` và mong đợi nó là một chuỗi hợp lệ, ví dụ: ```js run -alert( 'hi 😂'.slice(0, 4) ); // hi [?] +alert( 'chào 😂'.slice(0, 4) ); // chào [?] ``` -Here we can see a garbage character (first half of the smile surrogate pair) in the output. +Ở đây chúng ta có thể thấy một ký tự rác (nửa đầu của cặp thay thế nụ cười) trong đầu ra. -Just be aware of it if you intend to reliably work with surrogate pairs. May not be a big problem, but at least you should understand what happens. +Chỉ cần lưu ý về nó nếu bạn có ý định làm việc với các cặp thay thế một cách đáng tin cậy. Có thể không phải là một vấn đề lớn, nhưng ít nhất bạn nên hiểu những gì xảy ra. ```` -## Diacritical marks and normalization +## Dấu phụ và chuẩn hóa -In many languages, there are symbols that are composed of the base character with a mark above/under it. +Trong nhiều ngôn ngữ, có những ký hiệu bao gồm ký tự cơ sở có dấu ở trên/dưới ký tự đó. -For instance, the letter `a` can be the base character for these characters: `àáâäãåā`. +Chẳng hạn, ký tự `a` có thể là ký tự cơ bản cho các ký tự này: `àáâäãåā`. -Most common "composite" characters have their own code in the Unicode table. But not all of them, because there are too many possible combinations. +Hầu hết các ký tự "tổng hợp" phổ biến đều có mã riêng trong bảng Unicode. Nhưng không phải tất cả chúng, bởi vì có quá nhiều sự kết hợp có thể xảy ra. -To support arbitrary compositions, the Unicode standard allows us to use several Unicode characters: the base character followed by one or many "mark" characters that "decorate" it. +Để hỗ trợ các thành phần tùy ý, tiêu chuẩn Unicode cho phép chúng ta sử dụng một số ký tự Unicode: ký tự cơ sở theo sau là một hoặc nhiều ký tự "đánh dấu" "trang trí" cho nó. -For instance, if we have `S` followed by the special "dot above" character (code `\u0307`), it is shown as Ṡ. +Chẳng hạn, nếu chúng ta có `S` theo sau là ký tự "dấu chấm phía trên" đặc biệt (mã `\u0307`), nó sẽ được hiển thị là Ṡ. ```js run alert( 'S\u0307' ); // Ṡ ``` -If we need an additional mark above the letter (or below it) -- no problem, just add the necessary mark character. +Nếu chúng ta cần một dấu bổ sung phía trên chữ cái (hoặc bên dưới nó) -- không vấn đề gì, chỉ cần thêm ký tự dấu cần thiết. -For instance, if we append a character "dot below" (code `\u0323`), then we'll have "S with dots above and below": `Ṩ`. +Ví dụ, nếu chúng ta thêm một ký tự "dấu chấm bên dưới" (mã `\u0323`), thì chúng ta sẽ có "S có dấu chấm bên trên và bên dưới": `Ṩ`. -For example: +Ví dụ: ```js run alert( 'S\u0307\u0323' ); // Ṩ ``` -This provides great flexibility, but also an interesting problem: two characters may visually look the same, but be represented with different Unicode compositions. +Điều này mang lại sự linh hoạt tuyệt vời, nhưng cũng là một vấn đề thú vị: hai ký tự có thể trông giống nhau về mặt trực quan, nhưng được thể hiện bằng các thành phần Unicode khác nhau. -For instance: +Ví dụ: ```js run -let s1 = 'S\u0307\u0323'; // Ṩ, S + dot above + dot below -let s2 = 'S\u0323\u0307'; // Ṩ, S + dot below + dot above +let s1 = 'S\u0307\u0323'; // Ṩ, S + chấm trên + chấm dưới +let s2 = 'S\u0323\u0307'; // Ṩ, S + chấm dưới + chấm trên alert( `s1: ${s1}, s2: ${s2}` ); -alert( s1 == s2 ); // false though the characters look identical (?!) +alert( s1 == s2 ); // false mặc dù các ký tự trông giống hệt nhau (?!) ``` -To solve this, there exists a "Unicode normalization" algorithm that brings each string to the single "normal" form. +Để giải quyết vấn đề này, tồn tại thuật toán "Chuẩn hóa Unicode" đưa mỗi chuỗi về dạng "bình thường" duy nhất. -It is implemented by [str.normalize()](mdn:js/String/normalize). +Nó được thực hiện bởi [str.normalize()](mdn:js/String/normalize). ```js run alert( "S\u0307\u0323".normalize() == "S\u0323\u0307".normalize() ); // true ``` -It's funny that in our situation `normalize()` actually brings together a sequence of 3 characters to one: `\u1e68` (S with two dots). +Thật buồn cười là trong tình huống của chúng ta, `normalize()` thực sự tập hợp một chuỗi gồm 3 ký tự thành một: `\u1e68` (S có hai dấu chấm). ```js run alert( "S\u0307\u0323".normalize().length ); // 1 @@ -167,6 +167,6 @@ alert( "S\u0307\u0323".normalize().length ); // 1 alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true ``` -In reality, this is not always the case. The reason is that the symbol `Ṩ` is "common enough", so Unicode creators included it in the main table and gave it the code. +Trong thực tế, điều này không phải lúc nào cũng đúng. Lý do là ký hiệu `Ṩ` là "đủ phổ biến" nên những người tạo Unicode đã đưa nó vào bảng chính và đặt mã cho nó. -If you want to learn more about normalization rules and variants -- they are described in the appendix of the Unicode standard: [Unicode Normalization Forms](https://www.unicode.org/reports/tr15/), but for most practical purposes the information from this section is enough. +Nếu bạn muốn tìm hiểu thêm về các biến thể và quy tắc chuẩn hóa -- chúng được mô tả trong phần phụ lục của tiêu chuẩn Unicode: [Biểu mẫu chuẩn hóa Unicode](https://www.unicode.org/reports/tr15/), nhưng với hầu hết mục đích thực tế, thông tin từ phần này là đủ rồi.