Languages
[Edit]
EN

JavaScript - reverse string that contains emoji, surrogate characters and Asian characters

5 points
Created by:
Blessing-D
574

In this short article, we would like to show you the correct way to reverse strings that may contain emojisurrogate characters, and Asian characters using JavaScript.

Quick solution:

// ONLINE-RUNNER:browser;

const text = 'Hi there ! 💻🙂😀😋';
const reversion = '\u202e' + text + '\u202c'; // \u202c used to avoid affecting the following text

console.log(reversion);

Warning: the above solution only diplsays text as reversed - go to next seaction to see characters real reversion.

 

String reversion with emojis, surrogate characters and Asian characters made with JavaScript.
String reversion with emojis, surrogate characters, and Asian characters made with JavaScript.

Real reversion examples

Example 1:

In this section, you can find source code that makes reversion on some characters to get reversed string.

// ONLINE-RUNNER:browser;

function isHighSurrogate(code) {
    return code >= 0xD800 && code <= 0xDBFF;
}

function isLowSurrogate(code) {
    return code >= 0xDC00 && code <= 0xDFFF;
}

function isVariationSelectors(code) {
    return code >= 0xFE00 && code <= 0xFE0F;
}

function isCombiningMark(code) {
    return code >= 0x0300 && code <= 0x036F ||
           code >= 0x1AB0 && code <= 0x1AFF ||
           code >= 0x1DC0 && code <= 0x1DFF ||
           code >= 0x20D0 && code <= 0x20FF ||
           code >= 0xFE20 && code <= 0xFE2F;
}

function reverseString(text) {
    let result = '';
    for (var i = 0; i < text.length; i += 1) {
        var a = text.charCodeAt(i); // potential high surrogate
        var character;
        if (isHighSurrogate(a)) {
            if (i + 1 < text.length) {
                var b = text.charCodeAt(i + 1); // potential low surrogate
                if (isLowSurrogate(b)) {
                    i += 1;
                    character = String.fromCharCode(a, b);
                } else {
                    character = String.fromCharCode(a);
                }
            } else {
                break;
            }
        } else {
            character = String.fromCharCode(a);
            while (i + 1 < text.length) {
                var c = text.charCodeAt(i + 1); // potential combining mark or variation selector
                if (isCombiningMark(c) || isVariationSelectors(c)) {
                    i += 1;
                    character += String.fromCharCode(c);
                } else {
                    break;
                }
            }
        }
        result = character + result;
    }
    return result;
}


// Usage example:

// -- e.g. 1

var text1 = 'Example text ...';
var reversion1 = reverseString(text1);

console.log(text1);       // Example text ...
console.log(reversion1);  // ... txet elpmaxE
console.log();


// -- e.g. 2

var text2 = '❤️💻🙂😍😊😀🤑😁😋🤗';
var reversion2 = reverseString(text2);

console.log(text2);       // ❤️💻🙂😍😊😀🤑😁😋🤗
console.log(reversion2);  // 🤗😋😁🤑😀😊😍🙂💻❤️
console.log();


// -- e.g. 3

var data = [
    {
        // Nothing special
        'input': 'ma\xF1ana',
        'expected': 'ana\xF1am'
    },
    {
        // Combining mark
        'input': 'man\u0303ana',
        'expected': 'anan\u0303am'
    },
    {
        // Multiple combining marks
        'input': 'foo\u0303\u035C\u035D\u035Ebar',
        'expected': 'rabo\u0303\u035C\u035D\u035Eof'
    },
    {
        // Astral symbol (surrogate pair)
        'input': 'foo\uD834\uDF06bar',
        'expected': 'rab\uD834\uDF06oof'
    },
    {
        // Unpaired surrogates
        'input': 'foo\uD834bar\uDF06baz',
        'expected': 'zab\uDF06rab\uD834oof'
    },
    {
        // Zalgo
        'input': 'H\u0339\u0319\u0326\u032E\u0349\u0329\u0317\u0317\u0367\u0307\u030F\u030A\u033EE\u0368\u0346\u0352\u0306\u036E\u0303\u034F\u0337\u032E\u0323\u032B\u0324\u0323 \u0335\u031E\u0339\u033B\u0300\u0309\u0313\u036C\u0351\u0361\u0345C\u036F\u0302\u0350\u034F\u0328\u031B\u0354\u0326\u031F\u0348\u033BO\u031C\u034E\u034D\u0359\u035A\u032C\u031D\u0323\u033D\u036E\u0350\u0357\u0300\u0364\u030D\u0300\u0362M\u0334\u0321\u0332\u032D\u034D\u0347\u033C\u031F\u032F\u0326\u0309\u0312\u0360\u1E1A\u031B\u0319\u031E\u032A\u0317\u0365\u0364\u0369\u033E\u0351\u0314\u0350\u0345\u1E6E\u0334\u0337\u0337\u0317\u033C\u034D\u033F\u033F\u0313\u033D\u0350H\u0319\u0319\u0314\u0304\u035C',
        'expected': 'H\u0319\u0319\u0314\u0304\u035C\u1E6E\u0334\u0337\u0337\u0317\u033C\u034D\u033F\u033F\u0313\u033D\u0350\u1E1A\u031B\u0319\u031E\u032A\u0317\u0365\u0364\u0369\u033E\u0351\u0314\u0350\u0345M\u0334\u0321\u0332\u032D\u034D\u0347\u033C\u031F\u032F\u0326\u0309\u0312\u0360O\u031C\u034E\u034D\u0359\u035A\u032C\u031D\u0323\u033D\u036E\u0350\u0357\u0300\u0364\u030D\u0300\u0362C\u036F\u0302\u0350\u034F\u0328\u031B\u0354\u0326\u031F\u0348\u033B \u0335\u031E\u0339\u033B\u0300\u0309\u0313\u036C\u0351\u0361\u0345E\u0368\u0346\u0352\u0306\u036E\u0303\u034F\u0337\u032E\u0323\u032B\u0324\u0323H\u0339\u0319\u0326\u032E\u0349\u0329\u0317\u0317\u0367\u0307\u030F\u030A\u033E'
    }
];
    
for (var i = 0; i < data.length; ++i) {
    var item = data[i];
    var reversion = reverseString(item.input);
    console.log(item.input + ' ---> ' + reversion + '\n\n');
}

 

Example 2:

In this section, you can find source code that uses Intl.Segmenter class to get reversed string.

Note:

The Intl.Segmenter was added in ECMAScript 2023.

// ONLINE-RUNNER:browser;

const createReversor = (locales) => {
    const segmenter = new Intl.Segmenter(locales, {
        granularity: "grapheme"
    });
    return (text) => {
        const iterator = segmenter.segment(text)
        let result = '';
        for (let {segment} of iterator) {
            result = segment + result;
        }
        return result;
    }
};


// Usage example:

const reverseString = createReversor('en');


// -- e.g. 1

var text1 = 'Example text ...';
var reversion1 = reverseString(text1);

console.log(text1);       // Example text ...
console.log(reversion1);  // ... txet elpmaxE
console.log();


// -- e.g. 2

var text2 = '❤️💻🙂😍😊😀🤑😁😋🤗';
var reversion2 = reverseString(text2);

console.log(text2);       // ❤️💻🙂😍😊😀🤑😁😋🤗
console.log(reversion2);  // 🤗😋😁🤑😀😊😍🙂💻❤️
console.log();


// -- e.g. 3

var data = [
    {
        // Nothing special
        'input': 'ma\xF1ana',
        'expected': 'ana\xF1am'
    },
    {
        // Combining mark
        'input': 'man\u0303ana',
        'expected': 'anan\u0303am'
    },
    {
        // Multiple combining marks
        'input': 'foo\u0303\u035C\u035D\u035Ebar',
        'expected': 'rabo\u0303\u035C\u035D\u035Eof'
    },
    {
        // Astral symbol (surrogate pair)
        'input': 'foo\uD834\uDF06bar',
        'expected': 'rab\uD834\uDF06oof'
    },
    {
        // Unpaired surrogates
        'input': 'foo\uD834bar\uDF06baz',
        'expected': 'zab\uDF06rab\uD834oof'
    },
    {
        // Zalgo
        'input': 'H\u0339\u0319\u0326\u032E\u0349\u0329\u0317\u0317\u0367\u0307\u030F\u030A\u033EE\u0368\u0346\u0352\u0306\u036E\u0303\u034F\u0337\u032E\u0323\u032B\u0324\u0323 \u0335\u031E\u0339\u033B\u0300\u0309\u0313\u036C\u0351\u0361\u0345C\u036F\u0302\u0350\u034F\u0328\u031B\u0354\u0326\u031F\u0348\u033BO\u031C\u034E\u034D\u0359\u035A\u032C\u031D\u0323\u033D\u036E\u0350\u0357\u0300\u0364\u030D\u0300\u0362M\u0334\u0321\u0332\u032D\u034D\u0347\u033C\u031F\u032F\u0326\u0309\u0312\u0360\u1E1A\u031B\u0319\u031E\u032A\u0317\u0365\u0364\u0369\u033E\u0351\u0314\u0350\u0345\u1E6E\u0334\u0337\u0337\u0317\u033C\u034D\u033F\u033F\u0313\u033D\u0350H\u0319\u0319\u0314\u0304\u035C',
        'expected': 'H\u0319\u0319\u0314\u0304\u035C\u1E6E\u0334\u0337\u0337\u0317\u033C\u034D\u033F\u033F\u0313\u033D\u0350\u1E1A\u031B\u0319\u031E\u032A\u0317\u0365\u0364\u0369\u033E\u0351\u0314\u0350\u0345M\u0334\u0321\u0332\u032D\u034D\u0347\u033C\u031F\u032F\u0326\u0309\u0312\u0360O\u031C\u034E\u034D\u0359\u035A\u032C\u031D\u0323\u033D\u036E\u0350\u0357\u0300\u0364\u030D\u0300\u0362C\u036F\u0302\u0350\u034F\u0328\u031B\u0354\u0326\u031F\u0348\u033B \u0335\u031E\u0339\u033B\u0300\u0309\u0313\u036C\u0351\u0361\u0345E\u0368\u0346\u0352\u0306\u036E\u0303\u034F\u0337\u032E\u0323\u032B\u0324\u0323H\u0339\u0319\u0326\u032E\u0349\u0329\u0317\u0317\u0367\u0307\u030F\u030A\u033E'
    }
];
    
for (var i = 0; i < data.length; ++i) {
    var item = data[i];
    var reversion = reverseString(item.input);
    console.log(item.input + ' ---> ' + reversion + '\n\n');
}

 

References

  1. Universal Character Set characters - Wikipedia

  2. Combining character - Wikipedia
  3. Variation Selectors (Unicode block)

  4. Universal Character Set characters - Surrogates - Wikipedia

Alternative titles

  1. JavaScript - reverse text that contains emoji, surrogate characters and Asian characters
Donate to Dirask
Our content is created by volunteers - like Wikipedia. If you think, the things we do are good, donate us. Thanks!
Join to our subscribers to be up to date with content, news and offers.
Native Advertising
🚀
Get your tech brand or product in front of software developers.
For more information Contact us
Dirask - we help you to
solve coding problems.
Ask question.

❤️💻 🙂

Join