JSFiddle - React, Tailwind, and code Playground

HTML

<div id="test">Once upon a time... There was no history. Nothing. Oops</div>

<p>
Usage:<br /><ol>
<li>Define a <code>dictionary</code>. Each key will be used only once.</li>
<li>Define <code>content</code>. A new string will be created, based on this string.</li>
<li><em>Optionally</em>, define a <code>replacehandler</code> function. This function is called at each match. The return value will be used to replace the matched phrase.<br />The default <code>replacehandler</code> will return the dictionary's matching phrase. The function should take two arguments: <code>key</code> and <code>dictionary</code>.</li>
<li>Call <code>replaceOnceUsingDictionary(dictionary, content, replacehandler)</code></li>
<li>Do something with the return value, e.g. showing it to the user.</li></ol>
</p>
<p>This demo is written by <a href="http://stackoverflow.com/users/938089/rob-w" target="_blank">Rob W</a>. If you find a bug, or need help, feel free to contact me.</p>

CSS

.highlight {
    background: yellow;
}

JavaScript

var dictionary = {
    "history": "war . ",
    "no": "in a",
    "nothing": "",
    "oops": "",
    "time": "while",
    "there": "We",
    "upon": "in",
    "was": "get involved"
};
var test = document.getElementById("test"),
    content = test.innerHTML;
test.innerHTML = replaceOnceUsingDictionary(dictionary, content, function(key, dictionary){
    return '<span class="highlight">' + dictionary[key] + '</span>';
});

/*
 * @name        replaceOnceUsingDictionary
 * @author      Rob W http://stackoverflow.com/users/938089/rob-w
 * @description Replaces phrases in a string, based on keys in a given dictionary.
 *               Each key is used only once, and the replacements are case-insensitive
 * @param       Object dictionary  {key: phrase, ...}
 * @param       String content
 * @param       Function replacehandler
 * @returns     Modified string
 */
function replaceOnceUsingDictionary(dictionary, content, replacehandler) {
    if (typeof replacehandler != "function") {
        // Default replacehandler function.
        replacehandler = function(key, dictionary){
            return dictionary[key];
        }
    }
    
    var patterns = [], // \b is used to mark boundaries "foo" doesn't match food
        patternHash = {},
        oldkey, key, index = 0,
        output = [];
    for (key in dictionary) {
        // Case-insensitivity:
        key = (oldkey = key).toLowerCase();
        dictionary[key] = dictionary[oldkey];
        
        // Sanitize the key, and push it in the list
        patterns.push('\\b(?:' + key.replace(/([[^$.|?*+(){}])/g, '\\$1') + ')\\b');
        
        // Add entry to hash variable, for an optimized backtracking at the next loop
        patternHash[key] = index++;
    }
    var pattern = new RegExp(patterns.join('|'), 'gi'),
        lastIndex = 0;

    // We should actually test using !== null, but for foolproofness,
    //  we also reject empty strings
    while (key = pattern.exec(content)) {
        // Case-insensitivity
 ...