jQuery:如何将文本与RegEx模式匹配并将结果包装在锚标记中?

时间:2010-09-25 04:28:22

标签: jquery regex twitter

我有一堆推文以普通文本形式返回,我希望根据RegEx匹配分配正确的链接标记。

这里有一条推文,我希望@Bundlehunt成为<a href="http://twitter.com/bundlehunt">@Bundlehunt</a>http://bundlehunt.com成为<a href="http://bundlehunt.com">http://bundlehunt.com</a>

示例推文:

joined @BundleHunt for a chance to win the 2010 Mega Bundle! 
http://bundlehunt.com * Only 10 Days Left!

听起来很简单我以为我使用了优秀的http://www.gskinner.com/RegExr/工具来查找以下2个与我的推文中的内容匹配的RegEx模式:

@twittername = /@(\w.+?)(?=\s)/gi
@links = /http:\/\/(.*)\.([a-zA-Z\.]){2,3}/gi

现在回到我的jQuery文档中,我正在尝试浏览文本并匹配RegEx,但这就是我迷失的地方......

我如何实际匹配纯文本,绕着锚标签并将匹配的文本插入正确的锚标签?

感谢阅读,

Jannis

2 个答案:

答案 0 :(得分:1)

如果您在不受信任的输入上使用jQuery的.html()方法,那么您的Web应用程序将容易受到跨站点脚本(XSS)攻击,这种攻击可以通过发布恶意推文来利用。避免此安全问题的最佳方法是使用正确的jQuery函数单独附加推文的每个部分,这些函数使用Web浏览器的DOM函数转换为HTML转义字符串。

  1. 首先,使用正则表达式替换(|符号)将两个正则表达式合并为一个。出于我的示例代码的目的,Twitter用户名正则表达式为/@\w+/gi,URL正则表达式为/(?:https?|ftp):\/\/.*?\..*?(?=\W?\s)/gi这些正则表达式与原始问题中的正则表达式不同;原始URL正则表达式似乎无法正常工作,我们不需要使用捕获组。因此,合并的正则表达式为/@\w+|(?:https?|ftp):\/\/.*?\..*?(?=\W?\s)/gi

  2. 每次正则表达式匹配时,请将匹配前的文本安全地添加到容器中。要在jQuery中执行此操作,请创建一个空的“span”元素,并使用.text()方法在其中插入文本。使用$('text here')会使XSS孔敞开。如果推文内容为<script>alert(document.cookie)</script>

  3. ,该怎么办?
  4. 检查匹配的第一个字符以确定如何格式化。 Twitter用户名以“@”开头,但URL不能。

  5. 格式化匹配并将其添加到容器中。同样,不要将不受信任的输入传递给$或jQuery函数;使用.attr()方法添加href和.text()方法等属性来添加链接文本。

  6. 处理完所有匹配后,添加推文的最后一个纯文本部分,该部分尚未在步骤3或4中添加。

  7. 示例代码(也在http://jsfiddle.net/6X6xD/3/):

    var tweet = 'joined @BundleHunt for a chance to win the 2010 Mega Bundle! http://bundlehunt.com * Only 10 Days Left! URL containing an at sign: http://www.last.fm/event/1196311+Live+@+Public+Assembly. This should not work: <scr'+'ipt>alert(document.cookie)</scr'+'ipt>';
    
    var combinedRegex = /@\w+|(?:https?|ftp):\/\/.*?\..*?(?=\W?\s)/gi,
        container = $('#tweet-container');
    
    var result, prevLastIndex = 0;
    combinedRegex.lastIndex = 0;
    while((result = combinedRegex.exec(tweet))) {
        // Append the text coming before the matched entity
        container.append($('<span/>').text(tweet.slice(prevLastIndex, result.index)));
        if(result[0].slice(0, 1) == "@") {
            // Twitter username was matched
            container.append($('<a/>')
                // .slice(1) cuts off the first character (i.e. "@")
                .attr('href', 'http://twitter.com/' + encodeURIComponent(result[0].slice(1)))
                .text(result[0])
            );
        } else {
            // URL was matched
            container.append($('<a/>')
                .attr('href', result[0])
                .text(result[0])
            );
        }
        // prevLastIndex will point to the next plain text character to be added
        prevLastIndex = combinedRegex.lastIndex;
    }
    // Append last plain text part of tweet
    container.append($('<span/>').text(tweet.slice(prevLastIndex)));
    

    注意:此答案的旧版本确实建议使用.html()方法。因为这是一个严重的安全问题,如上所述,我使用编辑按钮发布我的新答案,从视图中删除旧答案。

答案 1 :(得分:1)

最简单的方法是使用replace String的{​​{1}}方法:

Object

请参阅此处了解文档:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/replace


另一方面,如果你的字符串包含多个与正则表达式匹配的子字符串,则必须在循环中运行它,因为处理捕获组,即parens中的部分在JavaScript中很糟糕。