String.prototype.replace()
replace()
是 String
值的一个方法,它返回一个新字符串,其中一个、一些或所有匹配的 pattern
被 replacement
替换。pattern
可以是字符串或 RegExp
,replacement
可以是字符串或为每个匹配调用的函数。如果 pattern
是字符串,则只替换第一个出现的匹配项。原始字符串保持不变。
试一试
语法
replace(pattern, replacement)
参数
pattern
-
可以是字符串或具有
Symbol.replace
方法的对象——典型的例子是 正则表达式。任何没有Symbol.replace
方法的值都将被强制转换为字符串。 replacement
-
可以是字符串或函数。
返回值
一个新字符串,其中一个、一些或所有匹配的模式被指定的替换替换。
描述
此方法不会改变它被调用的字符串值。它返回一个新字符串。
字符串模式将只被替换一次。要执行全局搜索和替换,请使用带有 g
标志的正则表达式,或改用 replaceAll()
。
如果 pattern
是一个具有 Symbol.replace
方法的对象(包括 RegExp
对象),则该方法将以目标字符串和 replacement
作为参数调用。它的返回值成为 replace()
的返回值。在这种情况下,replace()
的行为完全由 [Symbol.replace]()
方法编码——例如,下面描述中任何提到“捕获组”的内容实际上都是由 RegExp.prototype[Symbol.replace]()
提供的功能。
如果 pattern
是一个空字符串,则替换将附加到字符串的开头。
"xxx".replace("", "_"); // "_xxx"
带有 g
标志的正则表达式是 replace()
替换多次的唯一情况。有关正则表达式属性(尤其是 粘性 标志)如何与 replace()
交互的更多信息,请参阅 RegExp.prototype[Symbol.replace]()
。
指定字符串作为替换
替换字符串可以包含以下特殊的替换模式
模式 | 插入 |
---|---|
$$ |
插入一个 "$" 。 |
$& |
插入匹配的子字符串。 |
$` |
插入匹配的子字符串之前的字符串部分。 |
$' |
插入匹配的子字符串之后的字符串部分。 |
$n |
插入第 n 个(从 1 开始索引)捕获组,其中 n 是小于 100 的正整数。 |
$<Name> |
插入命名捕获组,其中 Name 是组名。 |
$n
和 $<Name>
仅在 pattern
参数为 RegExp
对象时可用。如果 pattern
是字符串,或者正则表达式中不存在相应的捕获组,则该模式将被替换为字面量。如果该组存在但未匹配(因为它属于一个并列条件的一部分),则它将被替换为空字符串。
"foo".replace(/(f)/, "$2");
// "$2oo"; the regex doesn't have the second group
"foo".replace("f", "$1");
// "$1oo"; the pattern is a string, so it doesn't have any groups
"foo".replace(/(f)|(g)/, "$2");
// "oo"; the second group exists but isn't matched
将函数指定为替换值
您可以将函数指定为第二个参数。在这种情况下,在执行匹配后将调用该函数。该函数的结果(返回值)将用作替换字符串。
注意:上述特殊替换模式不适用于替换函数返回的字符串。
该函数具有以下签名
function replacer(match, p1, p2, /* …, */ pN, offset, string, groups) {
return replacement;
}
函数的参数如下
match
-
匹配的子字符串。(对应于上面的
$&
。) p1
、p2
、…、pN
-
捕获组找到的第
n
个字符串(包括命名捕获组),前提是replace()
的第一个参数是RegExp
对象。(对应于上面的$1
、$2
等。)例如,如果pattern
是/(\a+)(\b+)/
,则p1
是\a+
的匹配项,p2
是\b+
的匹配项。如果该组是并列条件的一部分(例如"abc".replace(/(a)|(b)/, replacer)
),则未匹配的备选方案将为undefined
。 offset
-
匹配的子字符串在正在检查的整个字符串中的偏移量。例如,如果整个字符串是
'abcd'
,而匹配的子字符串是'bc'
,则此参数将为1
。 string
-
正在检查的整个字符串。
groups
-
一个对象,其键是使用的组名,其值是匹配的部分(如果未匹配则为
undefined
)。仅当pattern
包含至少一个命名捕获组时才存在。
参数的确切数量取决于第一个参数是否为 RegExp
对象——以及如果是,它有多少个捕获组。
以下示例将 newString
设置为 'abc - 12345 - #$*%'
function replacer(match, p1, p2, p3, offset, string) {
// p1 is non-digits, p2 digits, and p3 non-alphanumerics
return [p1, p2, p3].join(" - ");
}
const newString = "abc12345#$*%".replace(/([^\d]*)(\d*)([^\w]*)/, replacer);
console.log(newString); // abc - 12345 - #$*%
如果第一个参数中的正则表达式是全局的,则对于要替换的每个完整匹配,该函数将被多次调用。
示例
在 replace() 中定义正则表达式
在以下示例中,正则表达式是在 replace()
中定义的,并且包含不区分大小写标志。
const str = "Twas the night before Xmas...";
const newstr = str.replace(/xmas/i, "Christmas");
console.log(newstr); // Twas the night before Christmas...
这将输出 'Twas the night before Christmas...'
。
注意:有关正则表达式的更多说明,请参阅 正则表达式指南。
在 replace() 中使用全局和不区分大小写标志
全局替换只能使用正则表达式完成。在以下示例中,正则表达式包含 全局和不区分大小写标志,这允许 replace()
将字符串中每个出现的 'apples'
替换为 'oranges'
。
const re = /apples/gi;
const str = "Apples are round, and apples are juicy.";
const newstr = str.replace(re, "oranges");
console.log(newstr); // oranges are round, and oranges are juicy.
这将输出 'oranges are round, and oranges are juicy'
。
切换字符串中的单词
以下脚本切换字符串中的单词。对于替换文本,脚本使用 捕获组 和 $1
和 $2
替换模式。
const re = /(\w+)\s(\w+)/;
const str = "Maria Cruz";
const newstr = str.replace(re, "$2, $1");
console.log(newstr); // Cruz, Maria
这将输出 'Cruz, Maria'
。
使用修改匹配字符的内联函数
在此示例中,字符串中所有出现的大写字母都转换为小写,并且在匹配位置之前插入一个连字符。这里重要的是,在将匹配项作为替换项返回之前,需要对其进行其他操作。
替换函数接受匹配的片段作为其参数,并使用它来转换大小写并在返回之前连接连字符。
function styleHyphenFormat(propertyName) {
function upperToHyphenLower(match, offset, string) {
return (offset > 0 ? "-" : "") + match.toLowerCase();
}
return propertyName.replace(/[A-Z]/g, upperToHyphenLower);
}
给定 styleHyphenFormat('borderTop')
,这将返回 'border-top'
。
因为我们希望在进行最终替换之前进一步转换匹配的结果,所以必须使用函数。这会强制在 toLowerCase()
方法之前评估匹配项。如果我们尝试使用没有函数的匹配项来执行此操作,则 toLowerCase()
将不起作用。
// Won't work
const newString = propertyName.replace(/[A-Z]/g, "-" + "$&".toLowerCase());
这是因为 '$&'.toLowerCase()
将首先被评估为字符串字面量(导致相同的 '$&'
),然后才使用这些字符作为模式。
将华氏度替换为其摄氏度等值
以下示例将华氏度替换为其等值的摄氏度。华氏度应以 "F"
结尾的数字。该函数返回以 "C"
结尾的摄氏度数。例如,如果输入数字是 "212F"
,则该函数返回 "100C"
。如果数字是 "0F"
,则该函数返回 "-17.77777777777778C"
。
正则表达式 test
检查任何以 F
结尾的数字。华氏度的数量可以通过其第二个参数 p1
访问该函数。该函数根据传递给 f2c()
函数的字符串中的华氏度数设置摄氏度数。f2c()
然后返回摄氏度数。此函数近似于 Perl 的 s///e
标志。
function f2c(x) {
function convert(str, p1, offset, s) {
return `${((p1 - 32) * 5) / 9}C`;
}
const s = String(x);
const test = /(-?\d+(?:\.\d*)?)F\b/g;
return s.replace(test, convert);
}
创建通用替换器
假设我们想要创建一个替换器,它将偏移数据附加到每个匹配的字符串。因为替换函数已经接收了 offset
参数,所以在静态知道正则表达式的情况下,这将非常简单。
"abcd".replace(/(bc)/, (match, p1, offset) => `${match} (${offset}) `);
// "abc (1) d"
但是,如果我们希望它适用于任何正则表达式模式,则此替换器将难以泛化。替换器是可变的——它接收的参数数量取决于存在的捕获组的数量。我们可以使用 剩余参数,但它也会将 offset
、string
等收集到数组中。根据正则表达式的标识,groups
是否传递也会使其难以通用地知道哪个参数对应于 offset
。
function addOffset(match, ...args) {
const offset = args.at(-2);
return `${match} (${offset}) `;
}
console.log("abcd".replace(/(bc)/, addOffset)); // "abc (1) d"
console.log("abcd".replace(/(?<group>bc)/, addOffset)); // "abc (abcd) d"
上面的 addOffset
示例在正则表达式包含命名组时不起作用,因为在这种情况下,args.at(-2)
将是 string
而不是 offset
。
相反,您需要根据类型提取最后几个参数,因为 groups
是一个对象,而 string
是一个字符串。
function addOffset(match, ...args) {
const hasNamedGroups = typeof args.at(-1) === "object";
const offset = hasNamedGroups ? args.at(-3) : args.at(-2);
return `${match} (${offset}) `;
}
console.log("abcd".replace(/(bc)/, addOffset)); // "abc (1) d"
console.log("abcd".replace(/(?<group>bc)/, addOffset)); // "abc (1) d"
规范
规范 |
---|
ECMAScript 语言规范 # sec-string.prototype.replace |
浏览器兼容性
BCD 表格仅在浏览器中加载