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

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

简单而强大的正则

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

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

改成正则:

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

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

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

无奈的正则

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

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

var faces = {
"/::)": "weixiao",
"/::~": "pizui",
"/::B": "se",
"/::|": "fadai",
"/:8-)": "deyi",
"/::<":"liulei",
"/::$": "haixiu",
"/::'(": "daku",
"/::-|": "gangga"
};

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

循环替换

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

var faces = {
"/::)": "weixiao",
"/::~": "pizui",
"/::B": "se",
"/::|": "fadai",
"/:8-)": "deyi",
"/::<":"liulei",
"/::$": "haixiu",
"/::'(": "daku",
"/::-|": "gangga"
}; var str = "/::)-/::B-/::)-/:8-)-/:8-)"; for (var k in faces) {
while(str.indexOf(k) > -1) {
str = str.replace(k, faces[k]);
}
} console.log(str);

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

var faces = {
"/::)": "weixiao",
"/:hehe": "/:hehe"
}; var str = "/::)-/::B-/:hehe-/:8-)-/:8-)"; for (var k in faces) {
while(str.indexOf(k) > -1) {
str = str.replace(k, faces[k]);
}
} console.log(str);

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

改进循环

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

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

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

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

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

/**
* 字符串替换
* @param {string} str 要被替换的字符串
* @param {string} substr 要替换的字符串
* @param {string} newstr 用于替换的字符串
* @return {string} 替换后的新字符串
*/
function replace(str, substr, newstr) {
var p = -1; // 字符出现位置
var s = 0; // 下一次起始位置 while((p = str.indexOf(substr, s)) > -1) {
s = p + newstr.length; // 位置 + 值的长度
str = str.replace(substr, newstr);
} return str;
} console.log( replace("ssssss", "ss", "s") ); // sss

总结

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

后记

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

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

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

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

/**
* 字符串替换
* @param {string} str 要被替换的字符串
* @param {string} substr 要替换的字符串
* @param {string} newstr 用于替换的字符串
* @return {string} 替换后的新字符串
*/
function replace(str, substr, newstr) {
substr = substr.replace(/[.\\[\]{}()|^$?*+]/g, "\\$&"); // 转义字符串中的元字符
var re = new RegExp(substr, "g"); // 生成正则
return str.replace(re, newstr);
} 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. cocos2d-x之物理引擎之碰撞监测

    #include "HelloWorldScene.h" USING_NS_CC; #define RED_BIT_MASK    0b0100 #define GREEN_BIT ...

  2. C++类所占内存大小计算

    C++类所占内存大小计算 说明:笔者的操作系统是32位的. class A {}; sizeof( A ) = ? sizeof( A ) = 1明明是空类,为什么编译器说它是1呢? 空类同样可以实例 ...

  3. ASN.1(抽象语法标记)

    一.简介 ASN.1是一种对分布式计算机系统间交换的数据消息进行抽象描述的规范化语言.   二.教程 http://www.epubit.com.cn/book/onlinechapter/14877

  4. hdu 1542 Atlantis(线段树,扫描线)

    Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total S ...

  5. excel vba 当cell的值变化时 进行判断操作

    示例效果: ----------- 在excel的sheet1中, 当A列的值 大于100时 ,其对应B列背景显示红色,C列显示"有数据" 否则,B列背景色正常,C列清空相应的数据 ...

  6. 数据持久化之sqlite基本用法

    一.ACID 即原子性(Atomicity).一致性(Consistency).隔离性(Isolation).持久性(Durability). 原子性:整个事务中的所有操作,要么全部完成,要么全部不完 ...

  7. 如何实现ZBrush 4R7中按钮颜色的自定义

          本文详细讲解在ZBrush® 4R7中如何改变按钮颜色. Zbrush默认的开关按钮颜色为橙黄色,若您不喜欢当前颜色,可以通过“Icolors”功能按钮下的各命令来更改界面开关颜色及透明度 ...

  8. 边工作边刷题:70天一遍leetcode: day 81

    Encode and Decode Strings 要点:题的特点:不是压缩,而是encode为字节流.所以需要找delimiter来分割每个word,但是delimiter可能是字符本身,所以可以用 ...

  9. 【转】UVALive 5964 LCM Extreme --欧拉函数

    题目大意:求lcm(1,2)+lcm(1,3)+lcm(2,3)+....+lcm(1,n)+....+lcm(n-2,n)+lcm(n-1,n)解法:设sum(n)为sum(lcm(i,j))(1& ...

  10. HDU 3667 费用流(拆边)

    题意:有n个城市(1~n),m条有向边:有k件货物要从1运到n,每条边最多能运c件货物,每条边有一个危险系数ai,经过这条路的费用需要ai*x2(x为货物的数量),问所有货物安全到达的费用. 思路:c ...