【问题标题】:Find and replace by a dictionary, using keys only once通过字典查找和替换,仅使用一次键
【发布时间】:2012-01-30 03:47:04
【问题描述】:

这是Find multiple keywords within a dictionary的后续。

我的问题是……

  1. 第一个是:我相信这匹配不完整的单词。就像我的字典中的 short 一样,它与该词很快匹配。我将如何阻止这一切?

  2. 第二个不那么重要但很好的是:我将如何使它每个内容只匹配一次?所以short不会在同一个内容区域内被定义两次。

谢谢!

【问题讨论】:

    标签: javascript regex search dictionary replace


    【解决方案1】:

    我已经实现了以下附加要求:

    • 在查找short时不要匹配shortly(因为shortly是一个不同的词)
    • 字典中的键只能使用一次。
      示例输入:key=foo,replacement=bar,content=foo foo
      输出:bar foo(仅替换第一个 foo)。

    演示:http://jsfiddle.net/bhGE3/3/

    用法:

    1. 定义dictionary。每个密钥只能使用一次。
    2. 定义content。将基于此字符串创建一个新字符串。
    3. 可选地,定义一个replacehandler 函数。这个函数在每场比赛中被调用。返回值将用于替换匹配的短语。
      默认replacehandler 将返回字典的匹配短语。该函数应接受两个参数:keydictionary
    4. 致电replaceOnceUsingDictionary(dictionary, content, replacehandler)
    5. 处理输出,例如。向用户显示content

    代码:

    var dictionary = {
        "history": "war . ",
        "no": "in a",
        "nothing": "",
        "oops": "",
        "time": "while",
        "there": "We",
        "upon": "in",
        "was": "get involved"
    };
    var content = "Once upon a time... There was no history. Nothing. Oops";
    content = replaceOnceUsingDictionary(dictionary, content, function(key, dictionary){
        return '_' + dictionary[key] + '_';
    });
    alert(content);
    // End of implementation
    
    /*
    * @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
            key = key[0].toLowerCase();
    
            // Add to output buffer
            output.push(content.substring(lastIndex, pattern.lastIndex - key.length));
            // The next line is the actual replacement method
            output.push(replacehandler(key, dictionary));
    
            // Update lastIndex variable
            lastIndex = pattern.lastIndex;
    
            // Don't match again by removing the matched word, create new pattern
            patterns[patternHash[key]] = '^';
            pattern = new RegExp(patterns.join('|'), 'gi');
    
            // IMPORTANT: Update lastIndex property. Otherwise, enjoy an infinite loop
            pattern.lastIndex = lastIndex;
        }
        output.push(content.substring(lastIndex, content.length));
        return output.join('');
    }
    

    【讨论】:

    • 嘿 Rob W。非常感谢您花时间编写代码。我希望有一天能达到一定程度的编程信心,在那里我也可以为其他人做同样的事情。我有一件快速的事情,我认为我可以解决,但我想我会问。密钥返回完全小​​写,所以如果原始内容是短的,那么它会以短的形式返回。就像我说的那样,我可能可以通过摆脱两个 .toLowerCase() 并将其添加到字典 [key.toLowerCase()] 来解决它,但我想我会先问。谢谢。
    • 如果要支持不区分大小写的匹配,字典的键必须是小写或大写。原因是 JavaScript 是一种区分大小写的语言。 dictionary.Foo 不等于 dictionary.foo。在当前应用程序中,只有新(替换)短语的情况是相关的。只有当整个字典都区分大小写时,才能保留键的大小写。
    • 是的,我的字典会区分大小写。都是小写的。
    • 嘿@rob-w 看起来上面的解决方案不再适用于chrome firefox,但IE很好。高光没有正确渲染,我很难让它工作。有什么想法吗?我知道谷歌刚刚发布了一个新的更新。检查演示站点。它不适用于 chrome,谢谢!
    • @Jared 我已经更新了代码。 Chrome 对函数声明与表达式执行严格的规则。它现在正在工作;)
    猜你喜欢
    • 1970-01-01
    • 2019-09-20
    • 1970-01-01
    • 1970-01-01
    • 2021-10-08
    • 1970-01-01
    • 2011-03-10
    • 2011-09-18
    • 1970-01-01
    相关资源
    最近更新 更多