Skip to content

Instantly share code, notes, and snippets.

@FlameWolf
Created August 7, 2025 11:56
Show Gist options
  • Save FlameWolf/dc2661ee6a7e77910235e7f9c8ae070f to your computer and use it in GitHub Desktop.
Save FlameWolf/dc2661ee6a7e77910235e7f9c8ae070f to your computer and use it in GitHub Desktop.
Reverse a Unicode text while preserving grapheme clusters
const segmenter = new Intl.Segmenter();
const zeroWidthSpace = "\u200B";
/**
* Checks if the combination of segments is a single grapheme unit.
* @param {Intl.SegmentData} combination
* @returns {Boolean}
*/
const isGraphemeUnit = combination => Array.from(segmenter.segment(combination)).length === 1;
/**
* Removes unwanted zero-width spaces based on their context in the text.
* @param {Intl.SegmentData} current
* @param {Number} index
* @param {Array<SegmentData>} source
* @returns
*/
const removeUnwantedZws = (current, index, { [index - 1]: previous, [index + 1]: next }) => {
const currentSegment = current.segment;
if (currentSegment === zeroWidthSpace) {
if (previous) {
return isGraphemeUnit(`${previous.segment}${currentSegment}`);
} else if (next) {
return isGraphemeUnit(`${currentSegment}${next.segment}`);
}
}
return true;
};
/**
* Adds a zero-width space to current grapheme segment to prevent it from combining with
* the previous segment if they could become a single grapheme unit when placed together.
* @param {Intl.SegmentData} current
* @param {Number} index
* @param {Array<SegmentData>} source
* @returns
*/
const mapGrapheme = (current, index, { [index - 1]: previous }) => {
const currentSegment = current.segment;
if (previous && isGraphemeUnit(`${currentSegment}${previous.segment}`)) {
return `${currentSegment}${zeroWidthSpace}`;
}
return currentSegment;
};
/**
* Reverses the Unicode text while preserving grapheme clusters and handling zero-width spaces.
* @param {String} text
* @returns
*/
const reverseUnicodeText = text => Array.from(segmenter.segment(text)).filter(removeUnwantedZws).map(mapGrapheme).reverse().join("");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment