关于HTML在线编辑文本的编码与解码

很多在线编辑的网页都需要对用户输入的文本进行html的编码,避免输入的内容影响正常的网页排版,重新编辑时又需要进行对应的解码操作。用google搜索了一下,发现网上引用最多的两个函数是:

//编码
function HTMLEncode(str)  
{
var s = "";
if (str.length == 0) return "";
s = str.replace(/&/g, "&");
s = s.replace(/</g, "&lt;");
s = s.replace(/>/g, "&gt;");
s = s.replace(/ /g, "&nbsp;");
s = s.replace(/\'/g, "'");
s = s.replace(/\"/g, "&quot;");
s = s.replace(/\n/g, "<br>");
return s;
}

function HTMLDecode(str)  
{
var s = "";
if (str.length == 0) return "";
s = str.replace(/&amp;/g, "&");
s = s.replace(/&lt;/g, "<");
s = s.replace(/&gt;/g, ">");
s = s.replace(/&nbsp;/g, " ");
s = s.replace(/'/g, "\'");
s = s.replace(/&quot;/g, "\"");
s = s.replace(/<br>/g, "\n");
return s;
}

这两个函数存在以下问题,假如用户输入的文本为:

我输入了一些html标签\n&<div>就这么多</div>

那么使用HTMLEncode的结果是:

我输入了一些html标签<br>&amp;&lt;div&gt;就这么多&lt;/div&gt;
这个结果没有问题,但是如果我用这个输出结果再执行一次HTMLEncode,结果就是:

我输入了一些html标签&lt;br&gt;&amp;amp;&amp;lt;div&amp;gt;就这么多&amp;lt;/div&amp;gt;

没错!其中的&又被编码了一次,而且把<br>也进行了编码,其实理想情况下,多次调用HTMLEncode,应该结果保持不变。问题出现在HTMLEncode中的:

s = str.replace(/&/g, "&amp;");
s = s.replace(/</g, "&lt;");
s = s.replace(/>/g, "&gt;");
这句话中,它没有考虑传入的字符串是否已经经过编码了,而且没有考虑<和>是不是<br>中的,所以我们将改为:
s = str.replace(/&(?!(amp;|lt;|gt;|nbsp;|quot;))/g, "&amp;");
s = s.replace(/<(?!br>)/g, "&lt;");
s = s.replace(/(<br)?>/g, function ($0, $1) { return ($1 ? $0 : "&gt;"); });
第一句表示只有&后面跟的不是lt;|gt;|nbsp;|quot;这些时,才替换为&amp;。
第二句与第一句话类似,表示<后面跟的不是br>时,才替换>为&lt;。
第三句就比较费解了,这句想要达到的效果是当>前面的字符不是<br时替换>为&gt;,它需要用到正则表达式中的negative lookbehind功能,但是javascript的正则表达式却不支持这以特性,如果支持的话,写起来就简单了,如下:
s = s.replace(/(?<!<br)>/g, "&gt;");
所以在javascript中想要达到同样的效果只能使用变通的办法,replace的第二个参数可以是一个函数,可以对匹配的结果进行处理之后再返回一个替换用的字符串,其中$0,$1,$2……可以作为参数使用,分别表示匹配到的完整字符串,第一个子表达式,第二个子表达式……,所以下面这句话的意思是:
s = s.replace(/(<br)?>/g, function ($0, $1) { return ($1 ? $0 : "&gt;"); });
先匹配>前面有<br或者没有<br(用?匹配),函数的功能是,如果前面有<br,也就是$1不为空,就使用匹配到的整个字符串$0替换(也就是没有变化),如果前面没有<br,也就是说$1为空,这时就返回&gt;替换>。

完整的HTMLEncode和HTMLDecode如下:
function HTMLEncode(str) {
    var s = "";
    if (str.length == 0) return "";
    s = str.replace(/&(?!(amp;|lt;|gt;|nbsp;|quot;))/g, "&amp;");
    s = s.replace(/<(?!br\>)/g, "&lt;");
    s = s.replace(/(<br)?>/g, function ($0, $1) { return ($1 ? $0 : "&gt;"); });
    s = s.replace(/ /g, "&nbsp;");
    s = s.replace(/\'/g, "'");
    s = s.replace(/\"/g, "&quot;");
    s = s.replace(/\n/g, "<br>");
    return s;
}


function HTMLDecode(str) {
    var s = "";
    if (str.length == 0) return "";
    s = str.replace(/&amp;/g, "&");
    s = s.replace(/&lt;/g, "<");
    s = s.replace(/&gt;/g, ">");
    s = s.replace(/&nbsp;/g, " ");
    s = s.replace(/'/g, "\'");
    s = s.replace(/&quot;/g, "\"");
    s = s.replace(/<br>/g, "\n");
    return s;
}

顺便说一下:CSDN博客的源代码编辑真的非常糟糕!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值