javascript - JS RegExp 不适用于字母字符

标签 javascript regex

作为自定义所见即所得编辑器的一部分,我们被要求在启用时实现自动表情符号解析。为此,我们使用正则表达式将字符组合替换为其关联的 PNG 文件。

这是处理此代码的相关部分(它由 contenteditable 元素上的 onkeyup 事件触发;我已将其 trim 回相关部分):

// Parse emjoi:
this.parseEmoji = function()
{
    if( ! this.settings.parseSmileys )
    {
        return;
    }
    var _self    = this,
        url      = 'http://cdn.jsdelivr.net/emojione/assets/png/',
        $html    = this.$editor.html();

    // Loop through:
    for( var i in _self.emoji )
    {
        var re = new RegExp( '\\B' + _self.regexpEscape(i) + '\\B', 'g' ),
            em = _self.emoji[i];

        if( re.test($html) )
        {
            var replace = '<img class="lw-emoji" height="16" src="'+(url + em[0] + '.png')+'" alt="'+em[1]+'" />';
            this.insertAtCaret( replace );

            _self.$editor.html(function() { return $(this).html().replace(re, ''); });
        }
    }

};

这里是 regexpEscape() 函数:

// Escape a string so that it's RegExp safe!
this.regexpEscape = function( txt )
{
    return txt.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
};

我们将系统中使用的所有表情符号定义在一个对象中,该对象由字符组合本身引用,如下所示:

this.emoji = {
    ':)'  : [ '1F642', 'Smiling face' ],
    ':-)' : [ '1F642', 'Smiling face' ],
    ':D'  : [ '1F601', 'Happy face' ],
    ':-D' : [ '1F601', 'Happy face' ],
    ':\'(': [ '1F622', 'Crying face' ],
    ':('  : [ '1F614', 'Sad face' ],
    ':-(' : [ '1F614', 'Sad face' ],
    ':P'  : [ '1F61B', 'Cheeky' ],
    ':-P' : [ '1F61B', 'Cheeky' ],
    ':/'  : [ '1F615', 'Unsure face' ],
    ':-/' : [ '1F615', 'Unsure face' ],
    'B)'  : [ '1F60E', 'Too cool face' ],
    'B-)' : [ '1F60E', 'Too cool face' ]
};

现在,奇怪的是,任何包含字母字符的字符组合都不会被替换,并且无法通过 re.test() 函数。例如::):-):(:'( 都可以毫无问题地被替换。但是,:DB) 没有。

谁能解释为什么字母字符会导致 RegExp 内部出现问题?

Paired-back jsFiddle Demo

最佳答案

问题是 \B是上下文相关的,如果有一个单词字符开始模式,一个单词字符必须在输入字符串中出现在它之前才能匹配。同样的方式在模式的末尾,\B在模式的末尾将要求相同类型的符号紧随其后出现。

为避免该问题,通常使用基于环视的解决方案:(?<!\w)YOUR_PATTERN(?!\w) .但是,在 JS 中,不支持后视。它可以在稍后的替换函数中使用捕获组和反向引用来解决。

因此,要正确替换这些案例,您需要将那部分代码更改为

var re = new RegExp( '(^|\\W)' + _self.regexpEscape(i) + '(?!\\w)' ),
   em = _self.emoji[i]; // match the pattern when not preceded and not followed by a word character

if( re.test($html) )
{
   var replace = '<img class="lw-emoji" height="16" src="'+(url + em[0] + '.png')+'" alt="'+em[1]+'" />';
   this.insertAtCaret( replace );

   _self.$editor.html(function() { return $(this).html().replace(re, '$1'); }); // restore the matched symbol (the one \W matched) with $1
}

这是 updated fiddle .

关于javascript - JS RegExp 不适用于字母字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34265871/

相关文章:

java - 使用正则表达式验证美国电话号码格式

java - float / double 的正则表达式

javascript - 如何将值从 HTML 传递到 Node JS?

javascript - 构造函数第二次失败,但不是第一次

javascript - 点击链接后 javascript 不工作

Python - 如何匹配文本文件中多行的特定单词/数字并将它们存储在单独的列表中

javascript - 在 JS/JQuery 中,我可以从多维数组中提取单个元素并将其存储在另一个数组中吗?

javascript - JSON/JQUERY/JS - 从对象访问属性

asp.net - sql查询修复表中的电话号码问题

c# - 这个正则表达式是什么意思