JavaScript 自己写一个 replaceAll() 函数

更新日期: 2019-09-07阅读: 2k标签: 函数

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;
}


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

JavaScript 函数式编程

我理解的 JavaScript 函数式编程,都认为属于函数式编程的范畴,只要他们是以函数作为主要载体的。

Js函数式编程,给你的代码增加一点点函数式编程的特性

给你的代码增加一点点函数式编程的特性,最近我对函数式编程非常感兴趣。这个概念让我着迷:应用数学来增强抽象性和强制纯粹性,以避免副作用,并实现代码的良好可复用性。同时,函数式编程非常复杂。

让我们来创建一个JavaScript Wait函数

Async/await以及它底层promises的应用正在猛烈地冲击着JS的世界。在大多数客户端和JS服务端平台的支持下,回调编程已经成为过去的事情。当然,基于回调的编程很丑陋的。

JavaScript函数创建的细节

如果你曾经了解或编写过JavaScript,你可能已经注意到定义函数的方法有两种。即便是对编程语言有更多经验的人也很难理解这些差异。在这篇博客的第一部分,我们将深入探讨函数声明和函数表达式之间的差异。

编写小而美函数的艺术

随着软件应用的复杂度不断上升,为了确保应用稳定且易拓展,代码质量就变的越来越重要。不幸的是,包括我在内的几乎每个开发者在职业生涯中都会面对质量很差的代码。这些代码通常有以下特征:

javascript回调函数的理解和使用方法(callback)

在js开发中,程序代码是从上而下一条线执行的,但有时候我们需要等待一个操作结束后,再进行下一步操作,这个时候就需要用到回调函数。 在js中,函数也是对象,确切地说:函数是用Function()构造函数创建的Function对象。

js调用函数的几种方法_ES5/ES6的函数调用方式

这篇文章主要介绍ES5中函数的4种调用,在ES5中函数内容的this指向和调用方法有关。以及ES6中函数的调用,使用箭头函数,其中箭头函数的this是和定义时有关和调用无关。

JavaScript中函数的三种定义方法

函数的三种定义方法分别是:函数定义语句、函数直接量表达式和Function()构造函数的方法,下面依次介绍这几种方法具体怎么实现,在实际编程中,Function()构造函数很少用到,前两中定义方法使用比较普遍。

js在excel的编写_excel支持使用JavaScript自定义函数编写

微软 称excel就实现面向开发者的功能,也就是说我们不仅可以全新定义的公式,还可以重新定义excel的内置函数,现在Excel自定义函数增加了使用 JavaScript 编写的支持,下面就简单介绍下如何使用js来编写excel自定义函数。

js中的立即执行函数的写法,立即执行函数作用是什么?

这篇文章主要讲解:js立即执行函数是什么?js使用立即执行函数有什么作用呢?js立即执行函数的写法有哪些?

点击更多...

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