2010-09-25 31 views
2

我有一串推文作为纯文本返回,我希望通过并根据RegEx匹配分配适当的链接标签。jQuery:如何将文本与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正则表达式模式:

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

现在回到在我的jQuery文档中,我试图通过文本并匹配正则表达式,但这就是我迷失的地方...

我该如何确定g o关于匹配纯文本,围绕锚标签并将匹配的文本插入到适当的锚标签中?

感谢您的阅读,

Jannis

回答

1

如果你使用jQuery的html的()方法不受信任的输入,你的web应用程序将很容易受到跨站点脚本(XSS)攻击,将通过发布恶意推文而被利用。避免这种安全问题的最好方法是使用正确的使用Web浏览器DOM函数的jQuery函数将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. 检查匹配的第一个字符以确定如何对其进行格式化。 Twitter用户名以“@”开头,但URL不能。

  4. 格式化匹配并将其添加到容器。再次,不要将不可信的输入传递给$或jQuery函数;使用.attr()方法添加诸如href和.text()方法之类的属性以添加链接文本。

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

示例代码(也为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/[email protected]+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()方法。因为这是上述严重的安全问题,所以我使用编辑按钮发布我的新答案,从视图中删除旧答案。

+0

这太好了。非常感谢你! – Jannis 2010-10-16 23:41:50

1

最简单的办法就是使用StringObjectreplace方法:

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

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

    string.replace(
     TWITTER_NAME, 
     function(str,c1,c2) { 
      return "<a href=\"http://www.twitter.com/" + c1.toLowerCase() + ">" + str + "</a>" ; 
     } 
    ) ; 
    string.replace(LINK,"<a href=\"$&\">$&</a>") ; 

看到这里的文档:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/replace


在一个侧面说明,如果你的字符串包含匹配或者正则表达式,你将不得不在一个循环中运行这个,因为捕获组的处理,即一部分,在括号内部的多个子字符串,在JavaScript中是可怕的。

相关问题