最近在做JS算法项目时发现一个令我匪夷所思的问题, 这里想记录一下问题。

首先介绍一下字符串replace()方法的基本用法。

replace() 方法使用一个替换值(replacement)替换掉一个匹配模式(pattern)在原字符串中某些或所有的匹配项,并返回替换后的字符串。这个替换模式可以是字符串或者RegExp(正则表达式),替换值可以是一个字符串或者一个函数。

语法EDIT

str.replace(regexp|substrnewSubStr|function[, flags])

参数

regexp
一个 RegExp 对象。该正则所匹配的内容会被第二个参数的返回值替换掉。
substr
一个要被 newSubStr 替换的字符串。
newSubStr
替换掉第一个参数在原字符串中的匹配部分。该字符串中可以内插一些特殊的变量名。
function

一个用来创建新子字符串的函数,该函数的返回值将替换掉第一个参数匹配到的结果。该函数的参数描述请参考 指定一个函数作为参数 小节。

返回值

一个部分或全部匹配由替代模式所取代的新的字符串。

关于这个方法具体的信息参考MDN再好不过了。

String.prototype.replace() - JavaScript | MDN

现在有一个非常简单的需求:将HTML代码中的特殊字符进行实体转义:

先看一个简单的输出没有错误的版本:

正确方法一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function convertHTML(str) {
  // :)
  var pattern=/[&<>"']/g;
  return str.replace(pattern,function(match){
    switch(match){
        case "<":
        return "&lt;";
        case ">":
        return "&gt;";
        case "&":
        return "&amp;";
        case "\"":
        return "&quot;";
        case "\'":
        return "&apos;";
    }
  });
}
console.log(convertHTML("<Tom & Jerry>"));//&lt;Tom &amp; Jerry&gt;

指定一个函数作为第二个参数。在这种情况下,当匹配执行后, 该函数就会执行。 函数的返回值作为替换字符串。 (注意:  上面提到的特殊替换参数在这里不能被使用。) 另外要注意的是, 如果第一个参数是正则表达式, 并且其为全局匹配模式, 那么这个方法将被多次调用, 每次匹配都会被调用。

后来我对上述的代码进行了改造,使代码看起来更明了:

正确方法二:

1
2
3
4
5
6
7
8
9
10
11
12
13
function convertHTML(str) {
  // &colon;&rpar;
  var pattern=/[&<>"']/g;
  rules={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&apos;"};
 return str.replace(pattern,function(match){
    return  rules[match];
  });
 
 
}
console.log(convertHTML("<Tom & Jerry>"));//&lt;Tom &amp; Jerry&gt;

很明显非常简单的一个改造,我将规则键值对放在了rules对象中,输出结果同样也是正确的。

接下来,我发现貌似使用RegExp构造函数属性还能使代码变得更加简单。RegExp构造函数属性如下表所示:

其中一个叫做lastMatch的属性深深吸引了我。我在想能不能像下面这样改造一下:

错误方法:

1
2
3
4
5
6
function convertHTML(str) {
  var pattern=/[&<>"']/g;
  rules={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&apos;"};
  return str.replace(pattern,rules[RegExp.lastMatch]);
}
console.log(convertHTML("<Tom & Jerry>"));

写完这个代码,突然觉得自己聪明绝世,飘飘然了呢,然而一瓢冷水泼下来了。运行结果如下:

 
1
undefinedTom undefined Jerryundefined

这是什么鬼,貌似该替换的字符都被替换成了undefined。接下来我加入了一条测试语句:

 
1
2
3
4
5
6
7
8
9
function convertHTML(str) {
  // &colon;&rpar;
  var pattern=/[&<>"']/g;
  rules={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&apos;"};

  var result=str.replace(pattern,rules[RegExp.lastMatch]);

//下面是测试代码

  console.log(RegExp.lastMatch);//>
  return result;
}
console.log(convertHTML("<Tom & Jerry>"));

根据测试代码,最后匹配的是“>”说明匹配是正确的,但是最后为什么没有按照规则进行替换呢,我想应该是replace()方法的实现机制我们没有弄清楚,网上没有找到相关的资料,所以只能提醒自己以后不能写这样的代码了,在这种情况下,还是乖乖函数作为第二个参数。。。。。。等等,用函数做第二个参数,我又进行了下面的修改:

1
2
3
4
5
6
7
8
9
10
function convertHTML(str) {
  // &colon;&rpar;
  var pattern=/[&<>"']/g;
  rules={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&apos;"};
  var result=str.replace(pattern,function(){
    return rules[RegExp.lastMatch]
  });
  return result;
}
console.log(convertHTML("<Tom & Jerry>"));//&lt;Tom &amp; Jerry&gt;

注意上面我还是使用了正则表达式函数属性与方法二是有区别的,但是结果却是离奇的正确了。(难道闭包作怪)

 

replace()究竟隐藏着什么秘密,还有待挖掘??

字符串的replace()方法隐藏着什么不可告人秘密?的更多相关文章

  1. js中字符串的replace方法区分单双引号

    今天遇到一问题,js文件中调用字符串的replace方法,不起作用. 后来排查可能觉得replace("<option  value='1'>admin</option&g ...

  2. 浅谈JavaScript的字符串的replace方法

    JavaScript字符串提供了一个replace方法.replace方法可以接受两个参数:第一个参数可以使RegExp对象或者一个字符串,第二个参数可以是一个字符串或者一个函数.如果第一个参数是字符 ...

  3. 字符串替换replace方法

    字符串替换replace方法: http://www.w3school.com.cn/jsref/jsref_replace.asp http://www.cnblogs.com/skywang/ar ...

  4. C#自定义字符串替换Replace方法

    前一阵遇到一个如标题的算法题,是将原有字符串的某些片段替换成指定的新字符串片段,例如将源字符串:abcdeabcdfbcdefg中的cde替换成12345,得到结果字符串:ab12345abcdfb1 ...

  5. JQuery字符串替换replace方法

    在日常的js开发中,常常会用到JQuery, 当要把字符串中的内容替换时,如果使用类似C#的string.replace方法,如下 var str='aabbccaa'; str=str.replac ...

  6. js 字符串的replace() 方法和实现replaceAll() 方法

    一.js中字符串的替换使用replace() 方法,但它只替换第一个匹配子串.如下例: <script type="text/javascript"> var sour ...

  7. JavaScript字符串替换replace方法

    在日常的js开发中, 当要把字符串中的内容替换时,如果使用类似C#的string.replace方法,如下 var str='aabbccaa'; str=str.replace('aa','dd') ...

  8. 字符串函数 replace() 方法妙用

    alert('10 12 14 16'.replace(/d+/g,function(match){ return parseInt(match,10) > 10 ? '*' : match; ...

  9. 【转载】C#中string类使用Replace方法来替换字符串

    在C#的字符串操作过程中,有时候需要替换字符串中的某个子字符串,此时就可以使用到字符串类自带的Replace方法来实现,Replace方法将查找到所有符合被替换的子字符串,然后将之全部替换为目标字符串 ...

随机推荐

  1. bzoj2038小z的袜子

    用平面曼哈顿距离最小生成树或者莫队算法都可以吖QwQ~ 然而显然后者更好写(逃~) 莫队怎么写就看图吧QwQ~ 话说我一开始没开long long然后拍了3000组没拍出错交上去Wa了QAQ #inc ...

  2. Protobuf for Python测试保存和读取文件

    安装pip, setuptools, and wheel 如果已经从python.org,安装啦Python 2 >=2.7.9 or Python 3 >=3.4 ,那么就已经有啦pip ...

  3. 【Beta】第六次任务发布

    PM #103 #85 日常管理&dev版宣传&新增报告管理后台. 后端 #101 完成收藏功能 完成管理员权限表的生成和接入(按位压缩权限表) 验收条件:收藏功能能够正常使用.能够区 ...

  4. <<< html5本地储存

    类似与Cookies,但由于Cookies储存量太小,大小也只有4-5KB的样子,html5的本地储存能存5M大小的数据 html5本地储存属性有,localStorage和sessionStorag ...

  5. 搬家到cnblogs

    从openshift搬到LOFTER再到点点然后来cnblogs,晃悠一大圈,主要是没时间学习很多东西,再加上cnblogs的搜索收录情况比较好一点(百 度搜索).另外听闻百度空间bye-bye了,以 ...

  6. 面试题目——《CC150》数组与字符串

    面试题1.1:实现一个算法,确定一个字符串的所有字符是否全都不同.假使不允许使用额外的数据结构,又该如何处理? 注意:ASCII字符共有255个,其中0-127的字符有字符表 第一种解法:是<C ...

  7. Tomcat基本入门知识及发布,虚拟访问及启动碰到的错误,虚拟目录,虚拟路径,各种Tomcat的配置

    Tomcat容器入门介绍 转自javaresearch.com由timgball 整理 Tomcat是一个免费的开源Web服务器,最新版本是5.5.1,支持Servlet2.4,JSP2.0,非常适合 ...

  8. ROS 5.x自动定时备份并发送到邮箱(实用)

    博主使用ROS已经有很长一段时间了,但经常会忘记备份配置与数据库,加上ROS本身自带的User-Man数据库并不是非常稳定,1年中总会出现1-2次数据丢失的情况.所以费了一定功夫才找到真正可用自动备份 ...

  9. ViewHolder的改进写法

    先看看ViewHolder通用写法         ViewHolder holder = null;         if(convertView == null){                 ...

  10. 【荐2】Total Commander 7.57 配置选项 个性化设置备份,,,开启时如何自动最大化???(二)

    最近安装了下新版的“Total Commander 7.56”,发现它的默认设置是如此的不好用,现把对其个性化设置备份如下(符合大部分用户的操作习惯): 默认打开Total Commander 7.5 ...