String.prototype.replace()
replace() 方法是 String 值的实例方法,它会返回一个新字符串,其中一个、一些或所有匹配项都替换为 replacement。pattern 可以是字符串或 RegExp,replacement 可以是字符串或为每个匹配项调用的函数。如果 pattern 是字符串,则只替换第一个匹配项。原始字符串保持不变。
试一试
const paragraph = "I think Ruth's dog is cuter than your dog!";
console.log(paragraph.replace("Ruth's", "my"));
// Expected output: "I think my dog is cuter than your dog!"
const regex = /dog/i;
console.log(paragraph.replace(regex, "ferret"));
// Expected output: "I think Ruth's ferret is cuter than your dog!"
语法
replace(pattern, replacement)
参数
pattern-
可以是字符串或带有
Symbol.replace方法的对象——典型的例子是正则表达式。任何没有Symbol.replace方法的值都将被强制转换为字符串。 replacement-
可以是字符串或函数。
- 如果它是一个字符串,它将替换
pattern匹配的子字符串。支持一些特殊的替换模式;请参阅下面的将字符串指定为替换项部分。 - 如果它是一个函数,它将为每个匹配项调用,其返回值将用作替换文本。此函数提供的参数在下面的将函数指定为替换项部分中描述。
- 如果它是一个字符串,它将替换
返回值
一个新字符串,其中模式的一个、一些或所有匹配项都被指定的替换项替换。
描述
此方法不会更改调用它的字符串值。它返回一个新字符串。
字符串模式只会被替换一次。要执行全局搜索和替换,请使用带有 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® 2026 语言规范 # sec-string.prototype.replace |
浏览器兼容性
加载中…