replace 替换全部的正确姿势
本文同步自我的个人博客: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 替换全部的正确姿势的更多相关文章
- JS中replace替换全部的正确应用
		一般使用 var str = "test-test-test"; str = "test-test-test".replace("test" ... 
- 判断是否为gif/png图片的正确姿势
		判断是否为gif/png图片的正确姿势 1.在能取到图片后缀的前提下 1 2 3 4 5 6 7 8 9 //假设这是一个网络获取的URL NSString *path = @"http:/ ... 
- 在Linux(ubuntu server)上面安装NodeJS的正确姿势
		上一篇文章,我介绍了 在Windows中安装NodeJS的正确姿势,这一篇,我们继续来看一下在Linux上面安装和配置NodeJS. 为了保持一致,这里也列举三个方法 第一个方法:通过官网下载安装 h ... 
- replace替换语句
		t_sql语句:replace替换语句:update 表名 set 列名=REPLACE(列名,'替换的数据','替换后的数据') 
- 【SQLite】使用replace替换字段中的字符
		使用replace替换字段中的字符 如:替换production表中的specification字段中的两个空格为一个空格: update production set specification = ... 
- 关于js的replace替换
		关于js的replace替换 msgContent = msgContent.replace("a","b"); 这样的替换只会把第一个a替换成b,不会替换全部 ... 
- 程序员取悦女朋友的正确姿势---Tips(iOS美容篇)
		前言 女孩子都喜欢用美图工具进行图片美容,近来无事时,特意为某人写了个自定义图片滤镜生成器,安装到手机即可完成自定义滤镜渲染照片.app独一无二,虽简亦繁. JH定律:魔镜:最漂亮的女人是你老婆魔镜: ... 
- JAVA insert() 插入字符串 reverse() 颠倒 delete()和deleteCharAt() 删除字符 replace() 替换 substring() 截取子串
		insert() 插入字符串 StringBuffer insert(int index,String str) StringBuffer insert(int index,char ch) Stri ... 
- ios监听ScrollView/TableView滚动的正确姿势
		主要介绍 监测tableView垂直滚动的舒畅姿势 监测scrollView/collectionView横向滚动的正确姿势 1.监测tableView垂直滚动的舒畅姿势 通常我们用KVO或者在scr ... 
随机推荐
- 【故障处理】ORA-30012的解决过程
			[故障处理]ORA-30012的解决过程 1 BLOG文档结构图 2 前言部分 2.1 导读和注意事项 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识,~O ... 
- WCF使用net.tcp寄宿到IIS中(转)
			一.IIS部分 环境:Windows Server 2008 R2 1.安装WAS,如下图所示: 2.网站net.tcp协议绑定,如下图所示: 3.网站启用net.tcp,如下图所示: 二 ... 
- MySQL的诡异同步问题-重复执行一条relay-log
			MySQL的诡异同步问题 近期遇到一个诡异的MySQL同步问题,经过多方分析和定位后发现居然是由于备份引发的,非常的奇葩,特此记录一下整个问题的分析和定位过程. 现象 同事扩容的一台slave死活追不 ... 
- JQ插件
			什么是插件 插件(plugin)是JQuery的扩展(Extension),以JQuery的核心代码为基础,是一种遵循一定规范的应用程序接口编写出来的程序. 插件的引入 引入jquery.js文件 引 ... 
- andriod增、删、改、查
			将数据库的增删改查单独放进一个包 */ package com.itheima28.sqlitedemo.dao; import java.util.ArrayList; import java.ut ... 
- 09_Sum游戏(UVa 10891 Game of Sum)
			问题来源:刘汝佳<算法竞赛入门经典--训练指南> P67 例题28: 问题描述:有一个长度为n的整数序列,两个游戏者A和B轮流取数,A先取,每次可以从左端或者右端取一个或多个数,但不能两端 ... 
- Spring @Transactional ——事务回滚
			工作原理运行配置@Transactional注解的测试类的时候,具体会发生如下步骤1)事务开始时,通过AOP机制,生成一个代理connection对象,并将其放入DataSource实例的某个与Dat ... 
- android使用微软雅黑字体
			android使用微软雅黑字体,需要下载字体 ttf文件 下载地址:http://download.csdn.net/detail/xiaoliu123586/9049815 放在assert,然后引 ... 
- Mongodb--gridfs与分片实验
			1.放置一个大文件到gridfs,查看fs.chunks和fs.files的情况. Step1.开启一台mongod服务. ./mongod --dbpath dbs/master 登录mon ... 
- [转].NET下读取PDF文本
			本文转自:http://blog.csdn.net/wangqiuyun/article/details/8548779 在.NET下读取PDF文本用到的类库主要有两个:PDFBox和iTextSha ... 
