如何仅替换捕获的组?

IT技术 javascript regex
2021-01-21 18:17:50

我在字符串前后都有 HTML 代码:

name="some_text_0_some_text"

我想用以下内容替换0!NEW_ID!

所以我做了一个简单的正则表达式:

.*name="\w+(\d+)\w+".*

但我不知道如何专门替换捕获的块。

有没有办法用其他一些字符串替换像 ($1) 这样的捕获结果?

结果是:

name="some_text_!NEW_ID!_some_text"
6个回答

一种解决方案是为前面和后面的文本添加捕获:

str.replace(/(.*name="\w+)(\d+)(\w+".*)/, "$1!NEW_ID!$3")
来自未来的问候!您的解决方案看起来非常简洁。你能解释一下你的答案吗?
2021-03-15 18:17:50
不错的解决方案。如果我们想使用捕获组作为转换的基础来替换捕获组怎么办?这样做是否有同样优雅的解决方案?目前我将捕获的组存储在一个列表中,循环它们,并在每次迭代时用转换后的值替换捕获组
2021-03-19 18:17:50
话虽如此,虽然我理解它是如何工作的,但我希望有一个更优雅的解决方案 >.< 不过,我现在可以继续我的代码了!
2021-04-04 18:17:50
1)你甚至不需要捕获 \d+ 2)你为什么说它不优雅?捕获是为了保留东西,而不是扔掉它。您想要保留的是 AROUND \d+ 的内容,因此捕获这些周围的部分确实很有意义(并且足够优雅)。
2021-04-06 18:17:50
括号用于创建“组”,然后分配一个基数为 1 的索引,可以用 a 替换访问$,所以第一个单词(\w+)在一个组中,变成$1,中间部分(\d+)是第二组,(但得到在替换中被忽略),第三组是$3. 因此,当您提供替换字符串时"$1!new_ID!$3",$1 和 $3 会自动替换为第一组和第三组,从而允许将第二组替换为新字符串,并保留其周围的文本。
2021-04-09 18:17:50

现在 Javascript 具有后视功能(从ES2018 开始),在较新的环境中,您可以完全避免在此类情况下使用组。相反,回顾后为你捕捉组,先行用于之后的部分,并将其替换之前会发生什么只是 !NEW_ID!

const str = 'name="some_text_0_some_text"';
console.log(
  str.replace(/(?<=name="\w+)\d+(?=\w+")/, '!NEW_ID!')
);

使用这种方法,完全匹配的只是需要更换的部分。

  • (?<=name="\w+)- Lookbehind for name=",后跟单词字符(幸运的是,在 Javascript 中,lookbehinds 不必固定宽度!)
  • \d+ - 匹配一个或多个数字 - 模式的唯一部分不在环视中,字符串的唯一部分将出现在结果匹配中
  • (?=\w+")- 前瞻单词字符后跟" `

请记住,lookbehind 很新。它适用于现代版本的 V8(包括 Chrome、Opera 和 Node),但不适用于大多数其他环境,至少目前还没有。因此,虽然您可以在 Node 和您自己的浏览器中可靠地使用 Lookbehind(如果它在现代版本的 V8 上运行),但它还没有得到随机客户端的充分支持(例如在公共网站上)。

@MoshFeu 使用替换函数并使用整个匹配项,数字:将第二个参数替换为match => match * 2. 数字仍然是整个匹配,所以不需要组
2021-03-17 18:17:50
刚刚进行了一个快速的计时测试,输入的重要性令人印象深刻:jsfiddle.net/60neyop5
2021-03-18 18:17:50
但是,例如,如果我想提取数字、倍数并“放回去”,我还必须分组\d+,对吗?
2021-04-02 18:17:50
感谢分享。浏览器支持率约为 75%,最明显的是 iOS Safari 缺少:caniuse.com/js-regexp-lookbehind
2021-04-11 18:17:50

对马修答案的一点改进可能是前瞻而不是最后一个捕获组:

.replace(/(\w+)(\d+)(?=\w+)/, "$1!NEW_ID!");

或者你可以在小数点上拆分并像这样加入你的新 ID:

.split(/\d+/).join("!NEW_ID!");

示例/基准在这里:https : //codepen.io/jogai/full/oyNXBX

使用两个捕获组也是可能的;我还会在数字之前和之后包含两个破折号,作为额外的左右边界,修改后的表达式看起来像:

(.*name=".+_)\d+(_[^"]+".*)

const regex = /(.*name=".+_)\d+(_[^"]+".*)/g;
const str = `some_data_before name="some_text_0_some_text" and then some_data after`;
const subst = `$1!NEW_ID!$2`;
const result = str.replace(regex, subst);
console.log(result);


如果你想探索/简化/修改表达式,它已在regex101.com 的右上角面板中进行了 解释如果您愿意,您还可以在此链接中观看它如何与某些示例输入匹配。


正则表达式电路

jex.im可视化正则表达式:

在此处输入图片说明

一个更简单的选择是只捕获数字并替换它们。

const name = 'preceding_text_0_following_text';
const matcher = /(\d+)/;

// Replace with whatever you would like
const newName = name.replace(matcher, 'NEW_STUFF');
console.log("Full replace", newName);

// Perform work on the match and replace using a function
// In this case increment it using an arrow function
const incrementedName = name.replace(matcher, (match) => ++match);
console.log("Increment", incrementedName);

资源