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