regex 如何仅替换捕获的组?

z0qdvdin  于 2022-12-14  发布在  其他
关注(0)|答案(7)|浏览(155)

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

name="some_text_0_some_text"

我想将0替换为类似以下内容的内容:!NEW_ID!
所以我做了一个简单的正则表达式:

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

但是我不知道如何专门替换捕获的块。
是否有办法用其他字符串替换捕获的结果(如($1))?
结果将是:

name="some_text_!NEW_ID!_some_text"
xytpbqjk

xytpbqjk1#

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

str.replace(/(.*name="\w+)(\d+)(\w+".*)/, "$1!NEW_ID!$3")

说明

括号用于创建“组”,然后为组分配一个base-1索引,可以在替换$时访问。

  • 第一个字(\w+)在一个组中,并且变成$1
  • 中间部分(\d+)是第二组(但在替换中被忽略)
  • 第三组X1 M4 N1 X变成X1 M5 N1 X,

因此,当您给予替换字符串"$1!new_ID!$3"时,$1$3会自动替换为第一组和第三组,从而允许第二组替换为新字符串,并保留其周围的文本。

w80xi6nr

w80xi6nr2#

现在Javascript有了lookbehind(从ES2018开始),在新的环境中,你可以在类似的情况下完全避免使用组。相反,lookbehind查找在你捕获的组之前的内容,lookahead查找在你捕获的组之后的内容,并替换为 just!NEW_ID!

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

使用此方法,完全匹配 * 仅 * 需要替换的部分。

  • (?<=name="\w+)-name="的Lookbehind,后跟单词字符(幸运的是,在Javascript中lookbehind不必是固定宽度!)
  • \d+-匹配一个或多个数字-模式中唯一不在lookaround中的部分,字符串中唯一将在结果匹配中的部分
  • (?=\w+")-先行查找后跟" '的字字符

请记住,lookbehind是一个相当新的工具。它可以在现代版本的V8(包括Chrome、Opera和Node)中使用,但不能在大多数其他环境中使用,至少现在还不能。因此,尽管你可以在Node和你自己的浏览器(如果它运行在现代版本的V8上)中可靠地使用lookbehind,但它还不能得到随机客户端(比如公共网站)的充分支持。

ndasle7k

ndasle7k3#

对Matthew的答案的一点改进可以是前瞻性的,而不是最后一个捕获组:

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

或者,您也可以在小数点处拆分,然后加入新的id,如下所示:

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

示例/性能指标评测:https://codepen.io/jogai/full/oyNXBX

au9on6nz

au9on6nz4#

用两个捕获组也是可能的;我还会在数字前后加上两个破折号,作为附加的左边界和右边界,修改后的表达式将如下所示:

(.*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的右上角面板上已经解释过了。如果你愿意,你也可以在this link中观察它如何与一些示例输入进行匹配。

RegEx电路

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

1tuwyuhd

1tuwyuhd5#

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

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

资源

fhity93d

fhity93d6#

"some_text_0_some_text".replace(/(?=\w+)\d+(?=\w+)/, '!NEW_ID!')

结果为
一些文本!新ID!一些文本

const regExp = /(?=\w+)\d+(?=\w+)/;
const newID = '!NEW_ID!';
const str = 'some_text_0_some_text';
const result = str.replace(regExp, newID);

console.log(result);

JS正则表达式中的x(?=y)

仅当“x”后跟“y”时才匹配“x”。例如,/Jack(?=Sprat)/仅当“Jack”后跟“Sprat”时才匹配“Jack”。/Jack(?=Sprat|Frost)/仅当“Jack”后跟“Sprat”或“Frost”时才匹配“Jack”。但是,匹配结果中既没有“Sprat”也没有“Frost”。
详细信息

oalqel3c

oalqel3c7#

了解如果需要转换和操作捕获组,可以使用转换器函数作为第二个参数...
API
第一个
捕获的数量与你在正则表达式中使用的数量有关。indexinput_str是最后一个。
请参阅下面的示例及其输出以更好地了解每种方法。
文件参考:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#making_a_generic_replacer

示例:

// To uses example
const propsArgs = args.map((arg) =>
  arg.slice(2).replace(/-(.)/g, (matched, captureGroup, index, input) => {
    return captureGroup.toUpperCase();
  })
);

// To uses example multiple captures groups
const propsArgs = args.map((arg) =>
  arg
    .slice(2)
    .replace(/-(.)(.)/g, (matched, capture1, capture2, index, input) => {
      return capture2.toUpperCase();
    })
);

// To uses example multiple captures groups args destructuring version
// args[0] matched, args[1] capture 1, ....., args[n] capture n, args[n+1] index, args[n+2] total string to replace.
const propsArgs = args.map((arg) =>
  arg.slice(2).replace(/-(.)(.)/g, (...args) => {
    return args[2].toUpperCase(); // capture 2
  })
);

// example for understanding
const propsArgs = args.map((arg) =>
  arg.slice(2).replace(/-(.)/g, (...args) => {
    console.log(args); // [ '-f', 'f', 6, 'config-file' ]
    return args[1].toUpperCase();
  })
);

// multiple capture groups and the args order
/**
 * matched string, then all the captures arg after another, then index, then total input string to replace
 */
const propsArgs = args.map((arg) =>
  arg
    .slice(2)
    .replace(
      /-(.)(.)(.)/g,
      (matched, capture1, capture2, capture3, index, input) => {
        // [ '-wat', 'w', 'a', 't', 3, 'log-watch-compilation' ]
        return capture1.toUpperCase();
      }
    )
);

上面的核心示例是将命令行参数转换为javascript camel大小写等效形式。
转变:

[
  '--filename',
  '--config-file',
  '--env-name',
  '--no-swcrc',
  '--ignore',
  '--only',
  '--watch',
  '--quiet',
  '--source-maps',
  '--source-map-target',
  '--source-file-name',
  '--source-root',
  '--out-file',
  '--out-dir',
  '--copy-files',
  '--include-dotfiles',
  '--config',
  '--sync',
  '--log-watch-compilation',
  '--extensions'
]

[
  'filename',            'configFile',
  'envName',             'noSwcrc',
  'ignore',              'only',
  'watch',               'quiet',
  'sourceMaps',          'sourceMapTarget',
  'sourceFileName',      'sourceRoot',
  'outFile',             'outDir',
  'copyFiles',           'includeDotfiles',
  'config',              'sync',
  'logWatchCompilation', 'extensions'
]

相关问题