JS Regex,如何仅替换捕获的组?

Nic*_*ume 162 javascript regex

好的问题很简单.我正在寻找像这样的字符串:

name="some_text_0_some_text"
Run Code Online (Sandbox Code Playgroud)

我在上面的字符串之前和之后都有HTML代码.

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

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

.*name="\w+(\d+)\w+".*
Run Code Online (Sandbox Code Playgroud)

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

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

结果将是:

name="some_text_!NEW_ID!_some_text"
Run Code Online (Sandbox Code Playgroud)

谢谢你的帮助 :)

Mat*_*hen 315

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

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

  • 来自未来的问候!你的解决方案看起来很整洁.你能解释一下你的答案吗? (64认同)
  • 括号用于创建"组",然后为其分配一个base-1索引,可以替换为`$`,因此第一个单词`(\ w +)`在一个组中,并变为`$ 1` ,中间部分`(\ d +)`是第二组,(但在替换中被忽略),第三组是'$ 3`.因此,当你给出替换字符串"$ 1!new_ID!$ 3"时,$ 1和$ 3将自动替换为第一组和第三组,允许第二组替换为新字符串,并保留其周围的文本. (18认同)
  • 1)你甚至不需要捕获\ d + 2)为什么你说它不优雅?捕获是为了保留东西,而不是丢弃它.你想要保留的是AROUND\d +,所以它真正有意义(并且足够优雅)来捕捉这些周围的部分. (9认同)
  • 话虽这么说,虽然我理解它是如何工作的,但我希望有一个更优雅的解决方案>.然而,我现在可以继续使用我的代码! (3认同)
  • 好的解决方案 如果我们想要使用捕获组替换捕获组作为转换的基础,该怎么办?这样做有同样优雅的解决方案吗?目前,我将捕获的组存储在列表中,循环它们,并在每次迭代时将捕获组替换为转换后的值 (3认同)
  • 更简单的是 `.replace(/\d+/g, "!NEW_ID!");` (2认同)

Cer*_*nce 6

既然Java语言已经落后了(从ES2018开始),在较新的环境中,您可以完全避免在此类情况下进行分组。相反,向后寻找要捕获的组之前发生的事情,然后向后进行查找,然后用just 代替!NEW_ID!

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

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

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

请记住,向后看是很新的。它可以在V8的现代版本(包括Chrome,Opera和Node)中运行,但在大多数其他环境中(至少目前还不能)使用。因此,尽管您可以在Node中以及在您自己的浏览器中可靠地使用lookbehind(如果在现代版本的V8上运行),但是随机客户端(例如在公共网站上)仍未充分支持它。

  • 感谢分享。浏览器支持率约为 75%,最明显的是 iOS Safari 缺少:https://caniuse.com/js-regexp-lookbehind (4认同)

Moh*_*lal 6

要知道,如果您需要转换和操作捕获组,可以使用转换器函数作为第二个参数......

应用程序编程接口

replace(
    regex,
    (matched, capture1, capture2, /*...,*/ capture_n, index, input_str) => transformed(/*...*/)
)
Run Code Online (Sandbox Code Playgroud)
replace(
    regex: Regex,
    transformer: (matched: string, capture1: string, capture2: string, /*...,*/ capture_n: string, index: number, input_str: string) => string
) => string
Run Code Online (Sandbox Code Playgroud)

捕获的数量与您在正则表达式中使用的数量有关。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();
      }
    )
);
Run Code Online (Sandbox Code Playgroud)

上面的核心示例是将命令行参数转换为 javascript 驼峰式大小写等效项。

对此进行改造:

[
  '--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'
]
Run Code Online (Sandbox Code Playgroud)

[
  'filename',            'configFile',
  'envName',             'noSwcrc',
  'ignore',              'only',
  'watch',               'quiet',
  'sourceMaps',          'sourceMapTarget',
  'sourceFileName',      'sourceRoot',
  'outFile',             'outDir',
  'copyFiles',           'includeDotfiles',
  'config',              'sync',
  'logWatchCompilation', 'extensions'
]
Run Code Online (Sandbox Code Playgroud)


Jog*_*gai 5

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

.replace(/(\w+)(\d+)(?=\w+)/, "$1!NEW_ID!");
Run Code Online (Sandbox Code Playgroud)

或者你可以按小数点拆分并与你的新 id 连接,如下所示:

.split(/\d+/).join("!NEW_ID!");
Run Code Online (Sandbox Code Playgroud)

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