> For the complete documentation index, see [llms.txt](https://lochiwei.gitbook.io/web/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lochiwei.gitbook.io/web/js/val/prim/str/ext.md).

# String extension

[JS](/web/js.md) ⟩ [value](/web/js/val.md) ⟩ [primitive](/web/js/val/prim.md) ⟩ [String](/web/js/val/prim/str.md) ⟩ extension

{% hint style="success" %}
add custom methods to String.prototype.

```javascript
// 🔸 str.characters                - iterable iterator of characters
// 🔸 str.codePoints                - array of code points
// 🔸 str.codeUnits                 - array of code units
// 🔹 str.replaceWhitespaces()
```

{% endhint %}

{% tabs %}
{% tab title="💾 程式" %}

* replit ⟩ [String extension](https://replit.com/@pegasusroe/String-extension#ext/String_ext.js)

```javascript
// ⭐ install "grapheme-splitter": `npm install grapheme-splitter`

// 2023.01.03 - 19:40 + .codeUnits, .codePoints (support `GraphemeSplitter`)
//
// ⭐  String extension
// -------------------------------------------------------------------
// 🔸 str.characters                - iterable iterator of characters
// 🔸 str.codePoints                - array of code points
// 🔸 str.codeUnits                 - array of code units
// 🔹 str.replaceWhitespaces()
// -------------------------------------------------------------------

const { range } = require('./Iterable.js');      // iterable methods

// ⭐ import 'grapheme-splitter'
const GraphemeSplitter = require('grapheme-splitter');
const splitter = new GraphemeSplitter();
// -------------------------------------------------------------------

// String extension
Object.defineProperties(String.prototype, {

    // 🔹 str.replaceWhitespaces()
    replaceWhitespaces: {
        value: function(str = ',') {
            return this
                .trim()    // ⭐️ removes whitespace from both ends
                .replace(/\s+/g, str);
        },
    },

    // 🔸 str.characters
    // - real characters (grapheme clusters, may contain many code points)
    characters: {
        get: function() {
            // string -> iterable iterator
            return splitter.iterateGraphemes(this);
        },
    },

    // 🔸 str.codePoints
    // - 1 code point may contain 1 ~ 2 code units.
    codePoints: {
        get: function() {
            let codePoints = [];
            for (const char of this) {    // an iterator of "code points"
                codePoints.push(char.codePointAt(0));
            }
            return codePoints;
        },
    },

    // 🔸 str.codeUnits
    // - 16-bit code units
    codeUnits: {
        get: function() {
            return [...range(0, this.length - 1).map(i => this.charCodeAt(i))];
        },
    },
});

// export
module.exports = {};
```

{% endtab %}

{% tab title="💈範例" %}

```javascript
const _Number = require('./ext/Number_ext.js');      // Number extension
const _String = require('./ext/String_ext.js');      // String extension
const { range } = require('./ext/Iterable.js');      // iterable methods
// ---------------------------------------------------------------------------

// ⭐ import 'grapheme-splitter'
const GraphemeSplitter = require('grapheme-splitter');
const ilove = 'I❤️🏳️‍🌈';

// `.characters` iterates over "grapheme clusters".
ilove.characters.array,    // [ 'I', '❤️', '🏳️‍🌈' ]    (3 characters)
ilove.characters.map(ch => ch.codePoints).array,
// [ [ 73 ], [ 10084, 65039 ], [ 127987, 65039, 8205, 127752 ] ]    (7 code points)
//           [ '❤'  ,     ? ]  [ '🏳'  ,     ?,    ?, '🌈'  ]
//   ╰─I──╯  ╰───── ❤️ ─────╯  ╰──────────── 🏳️‍🌈 ─────────────╯

// `str.map` iterates over "code points"❗
// code point -> 1 or 2 code units
ilove.map(cp => cp.codeUnits).array,            // (9 code units)
// [
//   [ 73 ],
//   [ 10084 ],
//   [ 65039 ],
//   [ 55356, 57331 ],   // surrogate pair
//   [ 65039 ],
//   [ 8205 ],
//   [ 55356, 57096 ]    // surrogate pair
// ]
```

{% endtab %}

{% tab title="🔸 屬性" %}

* [str.isKeyword](/web/js/val/prim/str/ext/iskeyword.md) - check if a string is a [keyword](/web/js/grammar/token/keyword.md)
* [str.isReservedWord](/web/js/val/prim/str/ext/isreservedword.md) - check if a string a [reserved word](/web/js/grammar/token/keyword/reserved.md)
* [str.isPunctuator](/web/js/val/prim/str/ext/ispunctuator.md) - check if a string is a [punctuator](/web/js/grammar/token/punctuator.md)
  {% endtab %}

{% tab title="👥 相關" %}

* [Unicode](/web/js/val/prim/str/unicode.md) - about [code points](/web/js/val/prim/str/unicode/code-point.md), [code units](/web/js/val/prim/str/unicode/encode/utf16/code-unit.md) ...
  {% endtab %}

{% tab title="⬇️ 應用" %}

* [grapheme cluster](/web/js/val/prim/str/unicode/grapheme-cluster.md)
* [flag /u](/web/js/val/builtin/regex/flag/flag-u.md)
  {% endtab %}
  {% endtabs %}
