R语言正则提取子串:结果含空值及矩阵列表问题排查
R正则提取文献卷期编号问题解决
问题重现
在R中尝试提取文献列表里的卷(Volume)、期(Issue)、编号(Number)内容(支持阿拉伯数字和罗马数字,如Volume II、Issue 2),regex101测试能拿到目标子串,但用str_match_all运行时,会匹配字符串每个字符,返回带大量空值的矩阵列表,仅需有效匹配结果,不需要列表/矩阵格式。当前代码:
string <- 'ABC (2013c), Something Something Text (Volume II): Some more blabla, the usual, end of string' pattern <- "[V|v]ol(?:ume)?\\s*(\\d+|(V?I{0,3}X?L?C{0,3}D?M?))|(?:\\s+(Issue|No|Nr|nr|no|Number)\\s*(\\d+|V?I{0,3}X?L?C{0,3}D?M?))?" matches <- str_match_all(string , pattern)
问题原因
- 可选分支导致空匹配:正则第二个分支末尾的
?让整个Issue/No分支变成可选,当遍历到没有匹配卷/期/编号的位置时,正则会匹配空字符串,str_match_all会捕获这些空匹配,表现为“逐个字符匹配”。 - 罗马数字正则宽泛:原罗马数字规则
V?I{0,3}X?L?C{0,3}D?M?允许匹配空字符串,进一步增加了不必要的空匹配。 - 字符组写法错误:
[V|v]里的|是普通字符,会被当成可匹配的字符之一,正确写法应为[Vv]。
修正方案
1. 修正正则表达式
修复上述问题,同时优化罗马数字匹配规则(匹配1-3999范围内的标准罗马数字):
pattern <- "[Vv]ol(?:ume)?\\s*(\\d+|M{0,4}(?:CM|CD|D?C{0,3})(?:XC|XL|L?X{0,3})(?:IX|IV|V?I{0,3}))|\\s+(Issue|No|Nr|Number)\\s*(\\d+|M{0,4}(?:CM|CD|D?C{0,3})(?:XC|XL|L?X{0,3})(?:IX|IV|V?I{0,3}))"
2. 提取有效结果
- 提取完整匹配项:如果只需要
Volume II这类完整内容,用str_extract_all直接获取:valid_matches <- str_extract_all(string, pattern)[[1]] # 输出结果:"Volume II" - 拆分关键词与编号:如果需要单独获取关键词(如Volume)和对应的编号(如II),处理
str_match_all的结果矩阵,过滤空值:matches_matrix <- str_match_all(string, pattern)[[1]] # 转换为数据框并过滤空行 valid_df <- as.data.frame(matches_matrix)[, c(1,2,3,4)] valid_df <- valid_df[apply(valid_df, 1, function(row) any(!is.na(row) & row != "")), ]
内容的提问来源于stack exchange,提问作者H.Stevens
相关产品推荐
相关产品推荐

