Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

String.prototype.replace详解 #32

Open
Checkson opened this issue May 5, 2019 · 0 comments
Open

String.prototype.replace详解 #32

Checkson opened this issue May 5, 2019 · 0 comments

Comments

@Checkson
Copy link
Owner

Checkson commented May 5, 2019

前言

曾经的我天真地认为,String.prototype.replace其实没什么好学的,就是一个简单的、通用的字符串替换方法。可是,直到后来我遇到了一个业务问题,调试了足足将近一个小时左右,才把bug锁定在自己当初坚信基本不会用错的 replace 方法上。今天,我不得不花业余的时间,好好聊聊 replace 方法以及常见的坑。

定义

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

语法

stringObject.replace(regexp/substr,replacement)
参数 描述
regexp/substr 必需。规定子字符串或要替换的模式 RegExp 对象。
replacement 必需。一个字符串值。规定了替换文本或生成替换文本的函数。

返回值

一个新的字符串,是用 replacement 替换了 regexp/substr 的第一次匹配或所有匹配之后得到的。

说明

  • String.prototype.replace 该方法并不会改变字符串本身,只会返回替换后一个全新的字符串。
  • 字符串 stringObject 的 replace() 方法执行的是查找并替换的操作。它将在 stringObject 中查找与 regexp 相匹配的子字符串,然后用 replacement 来替换这些子串。如果 regexp 具有全局标志 g,那么 replace() 方法将替换所有匹配的子串。否则,它只替换第一个匹配子串。
  • replacement 可以是字符串,也可以是函数。如果它是字符串,那么每个匹配都将由字符串替换。但是 replacement 中的 $ 字符具有特定的含义(这就是我之前遇到的坑)。如下表所示,它说明从模式匹配得到的字符串将用于替换。
字符 替换文本
$1、$2、...、$9 与 regexp 中的第 1 到第 99 个子表达式相匹配的文本。
$& 与 regexp 相匹配的子串。
$` 位于匹配子串左侧的文本。
$' 位于匹配子串右侧的文本。
$$ 直接量符号,$转义。
  • 若replacement是一个函数,则用法如下:
stringObject.replace(regexp/substr, function (match, p1, p2, ..., offset, string) {
    // 逻辑代码
});
  • replacement函数参数说明如下表:
变量名 代表的值
match 匹配的子串。(对应于上述的$&。)
p1,p2, ... 假如replace()方法的第一个参数是一个RegExp 对象,则代表第n个括号匹配的字符串。(对应于上述的$1,$2等。)例如,如果是用 /(\a+)(\b+)/ 这个来匹配,p1 就是匹配的 \a+,p2 就是匹配的 \b+。
offset 匹配到的子字符串在原字符串中的偏移量。(比如,如果原字符串是 'abcd',匹配到的子字符串是 'bc',那么这个参数将会是 1)
string 被匹配的原字符串。

注意: ECMAScript v3 规定,replace() 方法的参数 replacement 可以是函数而不是字符串。在这种情况下,每个匹配都调用该函数,它返回的字符串将作为替换文本使用。该函数的第一个参数是匹配模式的字符串。接下来的参数是与模式中的子表达式匹配的字符串,可以有 0 个或多个这样的参数。接下来的参数是一个整数,声明了匹配在 stringObject 中出现的位置。最后一个参数是 stringObject 本身。

实例

实例1(字符串模式)

我们要将 str 字符串中的 “apple” 替换成 “checkson”

var str = "Welcome to visit apple website!";
console.log(str.replace("apple", "checkson")); // Welcome to visit checkson website!
console.log(str);  // Welcome to visit apple website!

可见,String.prototype.replace 方法并不改变字符串本身,具有无害性。

实例2 (正则匹配模式)

var str = "Welcome to visit apple website!";
console.log(str.replace(/apple/, "checkson")); // Welcome to visit checkson website!
console.log(str);  // Welcome to visit apple website!

实例3 (正则匹配全局替换)

var str = "Welcome to visit apple website! Do you like apple?";
console.log(str.replace("apple", "checkson")); // Welcome to visit checkson website! Do you like apple?
console.log(str.replace(/apple/g, "checkson"));  // Welcome to visit checkson website! Do you like checkson?

String 原型链上没有 replaceAll 方法,需要我们自己来封装一个类似的方法

String.prototype.replaceAll = function (findText, replacement) {
    var regExp = new RegExp(findText, "g");
    return this.replace(regExp, replacement);
}

实例4(对大小写不敏感的模式)

var str = "Welcome to visit Apple website!";
console.log(str.replace(/apple/i, "checkson")); // Welcome to visit checkson website!
console.log(str);  // Welcome to visit Apple website!

实例5(第二个参数 replacement 中包含$符号用法)

// $1、$2 、...
"good & handsome".replace(/(\w+)\s*&\s*(\w+)/g, "$2 & $1"); //handsome & good

// $&
"bye".replace(/\w+/g, "$& $&"); //bye bye

// $`
"javascript".replace(/script/, "$& is not $`"); //javascript is not java

// $'
"javascript".replace(/java/, "$&$' is "); // javascript is script

PS:我必须承认,以前我并不知道这些 “骚用法” 的(>.<!)。

那么,问题来了,我们替换的字符串中本来就包含 $$, $1, $', $&等字符,那不是炸了?别急,因为 replacement 可以是一个函数,我们可以这样解决:

"xxx replace is ok!".replace(/xxx/, "$1"); // xxx replace is ok!

"xxx replace is ok!".replace(/xxx/, () => "$1"); // $1 replace is ok!

实例6(replacement函数用法)

var _str = 'Just 11 do 22  it';
var str = _str.replace(/(\d)(\d)/g, function (arg1, arg2, arg3, arg4, arg5) {
  console.log(arg1);
  console.log(arg2);
  console.log(arg3);
  console.log(arg4);
  console.log(arg5);
});

输出结果

11
1
1
5
Just 11 do 22  it
22
2
2
11
Just 11 do 22  it

拓展应用

下面介绍一个日常开发中非常实用的 replace 方法应用,来自bootstrap-table中的一个实用方法。

function sprintf (_str) {
    var flag = true,
        args = [].slice.call(arguments, 1),
        i = 0;

    var str = _str.replace(/%s/g, function() {
        var arg = args[i++]
        if (typeof arg === 'undefined') {
            flag = false;
            return '';
        }
        return arg;
    });

    return flag ? str : '';
}

测试

sprintf("%s + %s = %s", 1, 1, 2); // 1 + 1 = 2

这种写法就类似C语言中的 printf 语句,非常优雅。

参考链接

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant