是否可以使用单个正则表达式查找并提取两个子字符串?

Is it possible to find and extract two substrings with a single regex?

花了半天时间阅读 SO 和其他地方。

假设我有一个字符串:

"a_b_c_d_e_f_g_1_2_3_4_5"

是否有一个正则表达式可以根据两个匹配项构造一个结果?例如。构造一个字符串,它是两个匹配项的串联:第一个 - 在第 3 和第 5 个之间,第二个在第 8 个和第 10 个下划线之间(不管它们之间有多少其他字符)?

上述示例的结果为:

"d_e_2_3"

谢谢!

Is it possible to find and extract two substrings with a single regex?

不,不是,但是可以使用 captures groups and String.prototype.replace.

的正则表达式组合

OP 用例的正则表达式可能如下所示...

(/^(?:[^_]*_){3}([^_]+_[^_]+)_(?:[^_]+_){3}([^_]+_[^_]+).*/)

... 可以读成如下...

  1. 想要从字符串的开头开始搜索... ^.
  2. 下一个要查找任何不是 _ ... [^_].
  3. 的字符序列
  • 但由于可能无法始终确保字符串不是以 _ 开头,因此可以选择性地查找它……因此它变成了 [^_]*.
  • 当然这样的序列后面应该跟一个_,这样前一项就变成了[^_]*_
  • 因为这个模式应该自己重复 3 次 ({3}) 它需要被分组 ((...)) 但它不应该被捕获 (?:) ...因此部分表达式变成 ^(?:[^_]*_){3} 并且已经匹配 OP 示例 'a_b_c_d_e_f_g_1_2_3_4_5'.
  • 中的 'a_b_c_'
  1. 现在要匹配一个非 _ 字符序列,后跟一个 _,然后是一个非 _ 字符序列,再后跟一个 _.想要捕获除最后一个 _ 之外的所有内容。因此正则表达式的第二部分看起来像这样...... ([^_]+_[^_]+)_.
  2. 第三部分与第一部分类似,只是确定下一个字符(序列)的存在不是 _。因此正则表达式的第三部分看起来像这样...... (?:[^_]+_){3}.
  3. 第 4 部分是第 2 部分的精确副本...([^_]+_[^_]+)
  4. 为了完全匹配字符串,一个人通过贪婪的野车去寻找字符串的其余部分...... . 匹配任何东西...... * 如果还有东西匹配。
  5. 由于可能还支持多行匹配,因此必须同时提供全局 (g) 和多行 (m) 标志。

示例代码...

const regX = (/^(?:[^_]*_){3}([^_]+_[^_]+)_(?:[^_]+_){3}([^_]+_[^_]+).*/gm);


console.log(
  'a_b_c_d_e_f_g_1_2_3_4_5'.replace(regX, '_')
);
console.log(
  '_b_c_d_e_f_g_1_2_3_4_5'.replace(regX, '_')
);
console.log(
  'b_c_d_e_f_g_1_2_3_4_5'.replace(regX, '_')
);
console.log(
  '_c_d_e_f_g_1_2_3_4_5'.replace(regX, '_')
);


console.log([...
`a_b_c_d_e_f_g_1_2_3_4_5
_b_c_dd_ee_f_g_1_222_333_4_5
b_c_dd_ee_f_g_1_222_333_4_5
_c_dd_ee_ff_g_1_222_333_444_5
c_dd_ee_ff_g_1_222_333_444_55_66
_dd_ee_ff_gg_1_222_333_444_55_66`
.matchAll(regX)].map(([match, , ]) => ( + '_' + ))
);
.as-console-wrapper { min-height: 100%!important; top: 0; }