JavaScript 自己写一个 replaceAll() 函数

时间: 2019-09-07阅读: 304标签: 函数

JavaScript 的  replace()  方法可以在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。

但是,只输入字符串的话,仅替换第一个字符,当然也可以用正则表达式来进行全局替换:

// 查找所有 word 替换成 words
string.replace(/word/g,"words");

那么,问题来了,如果我用的是变量呢?百度到可以这么来:

// 随便来一条字符串
let str = "How old are you? Yes, I'm very old!"
let search = "old";
// 使用 new RegExp(pattern,modifiers) 创建正则表达式
let pattern = new RegExp(search, "g");
let str = text.value.replace(pattern, "young");
// 结果:How young are you? Yes, I'm very young!

但是,不用 new RegExp 自己写一个函数,要怎么实现呢(我果然是太闲了)?

首先,摒弃掉 replace() 函数,自己来替换。

替换的话,不就是从前往后找想要替换的文并且一个个换掉嘛。

思路是这样的,用 indexOf() 方法返回指定的字符串在字符串中首次出现的位置,并用 slice(start, end)  方法提取找过但没有匹配项的,匹配的文字和还没找的三个部分,将第一部分和替换文字放入数组中,还没找的部分中再次使用这种办法,直至字符串末尾,将数组连起来成为一条字符串就是我想要的结果啦。

这是仅一次替换,咦,这不就是 replace() 嘛:

// 用于存放文字的数组
let array = [];
let data;
// 查询的文字第一次出现的位置
let start = oldText.indexOf(searchValue);
// 没有找到匹配的字符串则返回 -1 
if (start !== -1) {
    // 查找的字符串结束的位置
    let end = start + searchValue.length;
    // 添加没有匹配项的字符,即从头到查询的文字第一次出现的位置
    array.push(oldText.slice(0, start));
    // 添加替换的文字来代替查询的文字
    array.push(replaceValue);
    // 剩下没有查询的文字
    let remaining = oldText.slice(end, oldText.length);
    // 这是结果
    data = array[0] + array[1] + remaining;
} else {
    // 没找到呀
    data = "No Found" + searchValue + "!";
}
let textNode = document.createTextNode(data);
span.appendChild(textNode);

接下来进行全局替换,使用 while 循环,判定条件就是 indexOf(searchValue) 是否能找到文字,返回 -1 就停止循环。

let array = [];
// 用于存放未查找的文字
let remaining = oldText;
let data;
let start = oldText.indexOf(searchValue);
while (start !== -1) {
    let end = start + searchValue.length;
    array.push(remaining.slice(0, start));
    array.push(replaceValue);
    remaining = remaining.slice(end, remaining.length);
    start = remaining.indexOf(searchValue);
}
14 // 这是结果
data = array.join("") + remaining;

接着,再进一步,实现使用正则表达式来进行全局替换,大致思路是先找到正则匹配项,放入一个数组,在循环遍历每一项,使用上面的方法进行全局替换。

要注意的是,替换的数组不能有重复项,否则有可能出现问题,比如我想把 old 替换成 older,如果有两个 old 在数组中,最后的结果就会变成 olderer 。

/**
 * 字符串的全局替换
 * @param oldText {string} 原始字符串
 * @param searchValue {string} 需要替换的字符串
 * @param replaceValue {string} 替换后的字符串
 * @returns {string} 返回结果
 */
function replaceAll(oldText, searchValue, replaceValue) {
    let result = oldText;
    // 检查是否是正则表达式
    // 如果是正则表达式,则获得匹配内容
    let search;
    if (searchValue) {
        // 首先去掉空格
        search = searchValue.match(/\S+/g)[0];
        // 匹配以 / 符号开头 以 /img 形式结尾的内容
        search = search.search(/^\/[\s\S]*?\/[img]$/g);
    } else {
        search = -1;
    }
    // 为了方便直接创建一个数组用来存放需要替换的值
    let searchArray = [];
    if (search !== -1) {
        let pattern = searchValue.slice(searchValue.indexOf("\/") + 1, searchValue.lastIndexOf("\/"));
        let modifiers = searchValue.slice(searchValue.lastIndexOf("\/") + 1, searchValue.length);
        // 防止正则写的有问题,或者只是写的像正则实际不是而导致的 nothing to repeat 报错。
        try {
            search = oldText.match(new RegExp(pattern, modifiers));
        } catch (e) {
            console.log(e);
            // 报错则默认为是需要替换的文本
            search = null;
            searchArray.push(searchValue);
        }
        if (search !== null) {
            // 匹配成功后去掉重复项
            search.forEach(function (item1) {
                // if(searchArray.includes(item1)){}
                // IE 不支持 array.includes() 所以自己写一个循环吧
                // 数组中有相同元素则为 true
                let alreadyIn = false;
                searchArray.forEach(function (item2) {
                    if (item1 === item2) {
                        alreadyIn = true;
                    }
                });
                if (!alreadyIn) {
                    searchArray.push(item1);
                }
            });
        } else {
            // 匹配失败也默认为是需要替换的文本
            searchArray.push(searchValue);
        }
    } else {
        // 不是正则表达式也需要添加进数组
        searchArray.push(searchValue);
    }
    // 来循环吧,把 search 里的每个元素换一遍,当然首先里面要有元素
    if (searchValue) {
        let remaining = result;
        searchArray.forEach(function (item) {
            // 将上一次替换结束的字符串赋值给未扫描的字符串变量
            remaining = result;
            let array = [];
            let start = remaining.indexOf(item);
            console.log(start);
            // 没有匹配项则返回源字符串
            if (start === -1) {
                result = remaining;
            }
            while (start !== -1) {
                let end = start + item.length;
                array.push(remaining.slice(0, start));
                array.push(replaceValue);
                remaining = remaining.slice(end, remaining.length);
                start = remaining.indexOf(item);
                result = array.join("") + remaining;
            }
        });
    }
    return result;
}


站长推荐

1.阿里云: 本站目前使用的是阿里云主机,安全/可靠/稳定。点击领取2000元代金券、了解最新阿里云产品的各种优惠活动点击进入

2.腾讯云: 提供云服务器、云数据库、云存储、视频与CDN、域名等服务。腾讯云各类产品的最新活动,优惠券领取点击进入

3.广告联盟: 整理了目前主流的广告联盟平台,如果你有流量,可以作为参考选择适合你的平台点击进入

链接: http://www.fly63.com/article/detial/6311

JavaScript中的高阶函数

在 JavaScript 的学习过程中,我们可能或多或少地接触过高阶函数。那么,我们自己对此是否有一个明确的定义,或者说很熟练的掌握这些用法呢

工作中常用的 JavaScript 函数片段

查找数组最小,同上,不明白为什么要分成两个题目。Math.max 换成 Math.min,s>n?s:n 换成 s<n?s:n,(n,m)=>m-n 换成 (n,m)=>n-m,或者直接取最后一个元素

8个CSS函数的小技巧

CSS现在已经能实现比网站开发者预料到的更多的功能,并且随着时间的推移,样式表语言越来越强大,能实现许多原先需要依靠JavaScript才能实现的功能。在这篇文章中我们将会介绍CSS函数中8种有用的小技巧。

你也许不知道的javascript高级函数

高阶函数是对其他函数进行操作的函数,可以将它们作为参数或通过返回它们。简单来说,高阶函数是一个函数,它接收函数作为参数或将函数作为输出返回。例如Array.prototype.map,Array.prototype.filter,Array.prototype.reduce 都是一些高阶函数。

Js中函数式编程

最近和做技术的朋友聊天的时候,发现自己居然不能将函数式编程思想讲清楚,于是做一次复习,常常都能听到这么一句话:在 JavaScript 中,函数是“一等公民”,这句话到底意味着什么?

理解与使用JavaScript中的回调函数

在JavaScript中,函数是第一类对象,这意味着函数可以像对象一样按照第一类管理被使用。既然函数实际上是对象:它们能被“存储”在变量中,能作为函数参数被传递,能在函数中被创建,能从函数中返回。

JavaScript中的构造函数

ECMAScript 中,构造函数与其他函数的唯一区别,就在于调用它们的方式不同。不过,构造函数毕竟也是函数,不存在定义构造函数的特殊语法。任何函数,只要通过 new 操作符来调用

工作中常用的JavaScript函数片段

返回已 size 为长度的数组分割的原数组;检查数组中某元素出现的次数;扁平化数组默认 depth 全部展开;对比两个数组并且返回其中不同的元素

10个非常实用的Js工具函数

生成一周时间new Array 创建的数组只是添加了length属性,并没有实际的内容。通过扩展后,变为可用数组用于循环,类型判断判断核心使用Object.prototype.toString,这种方式可以准确的判断数据类型。

Javascript之尾调用

尾调用是函数式编程的一个重要的概念,本篇文章就来学习下尾调用相关的知识。有说过在一个函数中输出一个函数,则这个函数可以被成为高阶函数。本文的主角尾调用和它类似,如果一个函数返回的是另一个函数的调用结果,那么就被称为尾调用。

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!

文章投稿关于web前端网站点搜索站长推荐网站地图站长QQ:522607023

小程序专栏: 土味情话心理测试脑筋急转弯幽默笑话段子句子语录成语大全运营推广