什么是正则表达式中的非捕获组?
让我试着用一个例子来解释这一点。
考虑以下文本:
http://stackoverflow.com/ https://stackoverflow.com/questions/tagged/regex
现在,如果我在它上面应用下面的正则表达式......
(https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?
…我会得到以下结果:
Match "http://stackoverflow.com/" Group 1: "http" Group 2: "stackoverflow.com" Group 3: "/" Match "https://stackoverflow.com/questions/tagged/regex" Group 1: "https" Group 2: "stackoverflow.com" Group 3: "/questions/tagged/regex"
但我不关心协议——我只想要 URL 的主机和路径。因此,我将正则表达式更改为包含非捕获组(?:)。
(?:)
(?:https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?
现在,我的结果如下所示:
Match "http://stackoverflow.com/" Group 1: "stackoverflow.com" Group 2: "/" Match "https://stackoverflow.com/questions/tagged/regex" Group 1: "stackoverflow.com" Group 2: "/questions/tagged/regex"
看?第一组没有被抓获。解析器使用它来匹配文本,但稍后在最终结果中忽略它。
根据要求,让我也尝试解释一下组。
好吧,团体有很多用途。它们可以帮助您从更大的匹配(也可以命名)中提取准确信息,它们可以让您重新匹配之前匹配的组,并且可以用于替换。让我们尝试一些例子,好吗?
想象一下,您有某种 XML 或 HTML(请注意,正则表达式可能不是完成这项工作的最佳工具但作为示例很好)。你想解析标签,所以你可以做这样的事情(我添加了空格以便于理解):
\<(?<TAG>.+?)\> [^<]*? \</\k<TAG>\> or \<(.+?)\> [^<]*? \</\1\>
第一个正则表达式有一个命名组 (TAG),而第二个正则表达式使用一个公共组。两个正则表达式都做同样的事情:它们使用第一组中的值(标签的名称)来匹配结束标签。不同之处在于第一个使用名称来匹配值,第二个使用组索引(从 1 开始)。
现在让我们尝试一些替换。考虑以下文本:
Lorem ipsum dolor sit amet consectetuer feugiat fames malesuada pretium egestas.
现在,让我们使用这个愚蠢的正则表达式:
\b(\S)(\S)(\S)(\S*)\b
此正则表达式匹配至少包含 3 个字符的单词,并使用组来分隔前三个字母。结果是这样的:
Match "Lorem" Group 1: "L" Group 2: "o" Group 3: "r" Group 4: "em" Match "ipsum" Group 1: "i" Group 2: "p" Group 3: "s" Group 4: "um" ... Match "consectetuer" Group 1: "c" Group 2: "o" Group 3: "n" Group 4: "sectetuer" ...
因此,如果我们应用替换字符串:
$1_$3$2_$4
…在它上面,我们尝试使用第一组,添加下划线,使用第三组,然后是第二组,添加另一个下划线,然后是第四组。生成的字符串将如下所示。
L_ro_em i_sp_um d_lo_or s_ti_ a_em_t c_no_sectetuer f_ue_giat f_ma_es m_la_esuada p_er_tium e_eg_stas.
您也可以使用命名组进行替换,使用${name}.
${name}