R data.table中正则提取指定捕获组结果异常的解决方案
问题原因
你之前的写法错误核心是:stri_match_all返回的是和输入向量等长的列表,每个列表元素对应一个输入字符串的匹配矩阵。直接对整个列表调用unlist()会把所有匹配结果拍平成一个一维长向量,此时取[3]只是取了这个长向量的第3个值,再自动循环填充到所有行,自然会出现所有行都返回第一行结果的问题。
另外你用的临时方案多余了:stri_match_first本身返回的就是行与输入完全对齐的矩阵,不需要先把整个矩阵存为列再二次取子集,直接索引矩阵列就能拿到对应捕获组的全部结果。
最简实现方法
首先统一存一下正则表达式(注意下划线_不是正则特殊字符,不需要加反斜杠转义,R字符串里的正则转义符要写双反斜杠):
library(data.table) library(stringi) dt.test <- data.table(file_names = c("20200131_20210228_PROD_TEST_MF_delta_20210228_20210107_20210210.csv" , "20200531_20210531_PROD_TEST_MF_delta_20210531_20210523_20210608.csv" )) pattern <- "(?i)(\\d*)_(\\d*)_([A-Z]*_[A-Z]*_[A-Z]*_[A-Z]*)_(\\d*)_(\\d*)_(\\d*)"
你预期输出里的20210228/20210531对应正则的第5个捕获组(匹配结果矩阵第1列是完整匹配内容,捕获组从第2列开始计数),直接取矩阵对应列即可:
dt.test[, Extract.1 := stri_match_first(file_names, regex = pattern)[, 5]][]
运行后输出完全符合预期:
file_names Extract.1 1: 20200131_20210228_PROD_TEST_MF_delta_20210228_20210107_20210210.csv 20210228 2: 20200531_20210531_PROD_TEST_MF_delta_20210531_20210523_20210608.csv 20210531
要取其他捕获组只要改列号就行,比如取第一个起始日期就把列号改成2,取产品标识段就改列号为4。
多匹配场景适配
如果你的文本存在一个字符串对应多个匹配结果的情况(必须用stri_match_all),可以用vapply按行遍历列表提取对应捕获组,避免unlist拍平的问题:
dt.test[, Extract.1 := vapply( stri_match_all(file_names, regex = pattern), FUN = \(match_mat) match_mat[1, 5], # 取每个字符串第一个匹配的第5个捕获组 FUN.VALUE = character(1) )][]
可选简化方案
如果你只需要提取固定位置的特定内容,甚至不需要写全量正则配捕获组,直接用零宽断言匹配目标片段即可,不用数捕获组序号:
# 直接提取PROD_TEST_MF_delta_后面紧跟的8位日期 dt.test[, Extract.1 := stri_extract_first_regex(file_names, "(?i)(?<=PROD_TEST_MF_delta_)\\d{8}")]
内容的提问来源于stack exchange,提问作者hannes101
相关产品推荐
相关产品推荐

