本文同步自我的个人博客:http://www.52cik.com/2015/11/06/replace-all.html

关于字符串替换问题,其实是个很简单的问题,但却也不那么简单,至少对于很多新手而言,全局替换一直是个坑。

简单而强大的正则

可能你觉得要替换全局,就改成正则,然后加个 g 全局匹配就好了,例如:

  1. var str = "test-test-test";
  2. str = "test-test-test".replace("test", "ok");
  3. console.log(str);

改成正则:

  1. var str = "test-test-test";
  2. str = "test-test-test".replace(/test/g, "ok");
  3. console.log(str);

确实非常简单,但是如果出现需要转义的字符呢?

当然也难不倒大家,但是对于新手而言,正则就是一座无形的大山,完全无法越过。

无奈的正则

例如表情标签的替换呢?难道全部改成正则?那也要会正则的人花不少体力才能搞定吧。

今天群里的朋友就遇到这么个问题,表情标签如下:

  1. var faces = {
  2. "/::)": "weixiao",
  3. "/::~": "pizui",
  4. "/::B": "se",
  5. "/::|": "fadai",
  6. "/:8-)": "deyi",
  7. "/::<":"liulei",
  8. "/::$": "haixiu",
  9. "/::'(": "daku",
  10. "/::-|": "gangga"
  11. };

当然我只是截取了部分,好像有好几十个,如果全部改成正则,需要不少体力呢。

循环替换

这种情况,我们需要正常的字符串替换,例如结合 while + indexOf 实现。

  1. var faces = {
  2. "/::)": "weixiao",
  3. "/::~": "pizui",
  4. "/::B": "se",
  5. "/::|": "fadai",
  6. "/:8-)": "deyi",
  7. "/::<":"liulei",
  8. "/::$": "haixiu",
  9. "/::'(": "daku",
  10. "/::-|": "gangga"
  11. };
  12. var str = "/::)-/::B-/::)-/:8-)-/:8-)";
  13. for (var k in faces) {
  14. while(str.indexOf(k) > -1) {
  15. str = str.replace(k, faces[k]);
  16. }
  17. }
  18. console.log(str);

这样,基本功能实现,不过这是有问题的,如果有一个键值相同的,就会死循环例如:

  1. var faces = {
  2. "/::)": "weixiao",
  3. "/:hehe": "/:hehe"
  4. };
  5. var str = "/::)-/::B-/:hehe-/:8-)-/:8-)";
  6. for (var k in faces) {
  7. while(str.indexOf(k) > -1) {
  8. str = str.replace(k, faces[k]);
  9. }
  10. }
  11. console.log(str);

这样,就呵呵了,当然不一定会有这样的情况,但也不能肯定一定没有这样的情况。

改进循环

我们需要用到 indexOf 的第二个参数来规避这种情况,改进后的代码如下:

  1. var faces = {
  2. "/::)": "weixiao",
  3. "/:hehe": "/:hehe"
  4. };
  5. var str = "/::)-/::B-/:hehe-/:8-)-/:8-)";
  6. for (var k in faces) {
  7. var p = -1; // 字符出现位置
  8. var s = 0; // 下一次起始位置
  9. while((p = str.indexOf(k, s)) > -1) {
  10. s = p + faces[k].length; // 位置 + 值的长度
  11. str = str.replace(k, faces[k]);
  12. }
  13. }
  14. console.log(str);

好了,现在这样就没问题了,也不用担心死循环问题,而且替换大段文字的时候,性能比正则要好。 经过测试,确实正则快。

在大段正则匹配的时候,回溯会导致匹配性能问题,所以才一直认为正则慢,而这种情况的正则,不需要回溯,性能自然也极佳。

为了方便新手朋友使用,下面写个函数吧。

  1. /**
  2. * 字符串替换
  3. * @param {string} str 要被替换的字符串
  4. * @param {string} substr 要替换的字符串
  5. * @param {string} newstr 用于替换的字符串
  6. * @return {string} 替换后的新字符串
  7. */
  8. function replace(str, substr, newstr) {
  9. var p = -1; // 字符出现位置
  10. var s = 0; // 下一次起始位置
  11. while((p = str.indexOf(substr, s)) > -1) {
  12. s = p + newstr.length; // 位置 + 值的长度
  13. str = str.replace(substr, newstr);
  14. }
  15. return str;
  16. }
  17. console.log( replace("ssssss", "ss", "s") ); // sss

总结

我发现,我也只能写写这些小东西,唉。。

后记

在 4楼 Antineutrino 的测试中得知,正则方法比 while + indexOf 性能更佳。

之前一直认为正则就是慢的代名词,所以直接忽略了正则方法,现在又重新认识了正则,正则果然犀利。

抽空写了个正则版本的,把元字符种的几个符号转义下,就可以生成正则了。

网上那些正则版本中没有转义直接 new RegExp 的会导致各种bug,所以要处理下元字符的那些符号。

  1. /**
  2. * 字符串替换
  3. * @param {string} str 要被替换的字符串
  4. * @param {string} substr 要替换的字符串
  5. * @param {string} newstr 用于替换的字符串
  6. * @return {string} 替换后的新字符串
  7. */
  8. function replace(str, substr, newstr) {
  9. substr = substr.replace(/[.\\[\]{}()|^$?*+]/g, "\\$&"); // 转义字符串中的元字符
  10. var re = new RegExp(substr, "g"); // 生成正则
  11. return str.replace(re, newstr);
  12. }
  13. console.log( replace("ssssss", "ss", "s") ); // sss

replace 替换全部的正确姿势的更多相关文章

  1. JS中replace替换全部的正确应用

    一般使用 var str = "test-test-test"; str = "test-test-test".replace("test" ...

  2. 判断是否为gif/png图片的正确姿势

    判断是否为gif/png图片的正确姿势 1.在能取到图片后缀的前提下 1 2 3 4 5 6 7 8 9 //假设这是一个网络获取的URL NSString *path = @"http:/ ...

  3. 在Linux(ubuntu server)上面安装NodeJS的正确姿势

    上一篇文章,我介绍了 在Windows中安装NodeJS的正确姿势,这一篇,我们继续来看一下在Linux上面安装和配置NodeJS. 为了保持一致,这里也列举三个方法 第一个方法:通过官网下载安装 h ...

  4. replace替换语句

    t_sql语句:replace替换语句:update 表名 set 列名=REPLACE(列名,'替换的数据','替换后的数据')

  5. 【SQLite】使用replace替换字段中的字符

    使用replace替换字段中的字符 如:替换production表中的specification字段中的两个空格为一个空格: update production set specification = ...

  6. 关于js的replace替换

    关于js的replace替换 msgContent = msgContent.replace("a","b"); 这样的替换只会把第一个a替换成b,不会替换全部 ...

  7. 程序员取悦女朋友的正确姿势---Tips(iOS美容篇)

    前言 女孩子都喜欢用美图工具进行图片美容,近来无事时,特意为某人写了个自定义图片滤镜生成器,安装到手机即可完成自定义滤镜渲染照片.app独一无二,虽简亦繁. JH定律:魔镜:最漂亮的女人是你老婆魔镜: ...

  8. JAVA insert() 插入字符串 reverse() 颠倒 delete()和deleteCharAt() 删除字符 replace() 替换 substring() 截取子串

    insert() 插入字符串 StringBuffer insert(int index,String str) StringBuffer insert(int index,char ch) Stri ...

  9. ios监听ScrollView/TableView滚动的正确姿势

    主要介绍 监测tableView垂直滚动的舒畅姿势 监测scrollView/collectionView横向滚动的正确姿势 1.监测tableView垂直滚动的舒畅姿势 通常我们用KVO或者在scr ...

随机推荐

  1. cookie的读入和读出

    写入cookie中 在mvc的控制器中 HttpCookie GetUserID = new HttpCookie("uID", 要保存的值); GetUserID.Expires ...

  2. cocos2d-x之首选项数据初试

    bool HelloWorld::init() { if ( !Layer::init() ) { return false; } Size visibleSize = Director::getIn ...

  3. PPT制作教程:如何制作ppt

    PowerPoint(PPT)是专门用于制作演示文稿(俗称幻灯片).广泛运用于各种会议.产品演示.学校教学等.学会如何制作ppt,成为提升工作效 率的好帮手.PPT包含有很多的功能,我们可以根据个人喜 ...

  4. 在Myeclipse中添加User Library,用户自己的库

    在Myeclipse中添加User Library,用户自己的库 作用:可以将常用的jar包添加到一个固定的库中,避免每一次都要手动导入. 步骤: 1.选择项目,点击Myeclipse的window菜 ...

  5. Hive Word count

    --https://github.com/slimandslam/pig-hive-wordcount/blob/master/wordcount.hql DROP TABLE myinput; DR ...

  6. c++仿函数 functor

    内容整理自国外C++教材 先考虑一个简单的例子:假设有一个vector<string>,你的任务是统计长度小于5的string的个数,如果使用count_if函数的话,你的代码可能长成这样 ...

  7. CentOS7.2安装总结

    第一次自己写文章,想想还有点小激动呢.折腾了大半天,终于在一个没用的台式机上面装了个mini版的CentOS7.2.写这篇文章也是做个记载,要是以后再装要注意了. 一.安装过程 采用U盘安装.最初是准 ...

  8. Django项目中model增加了新字段怎样更新?

    Django是不直接支持syncdb更新数据库的字段的,必须重新建立. 或者改一个表名新建一个表... 刚刚想出来一招: 自己在表上面先加一个字段,然后再在model上面改,貌似是可以的.

  9. POJ 1269 Intersecting Lines --计算几何

    题意: 二维平面,给两条线段,判断形成的直线是否重合,或是相交于一点,或是不相交. 解法: 简单几何. 重合: 叉积为0,且一条线段的一个端点到另一条直线的距离为0 不相交: 不满足重合的情况下叉积为 ...

  10. java10-1 Object类

    Object:类      Object 是类层次结构的根类.每个类都使用 Object 作为超类. 每个类都直接或者间接的继承自Object类. Object类的方法: public int has ...