R语言grep匹配长短横杠分隔的位置字符串返回NA问题求解
问题描述
我有一个名为df_parse的dataframe,结构如下:
error error_position 1 0 2 0 3 0 4 1 24 - 26 5 1 29 - 30 6 0 7 0 8 0 9 0 10 0 11 0 12 0 13 0 14 0 15 0 16 0 17 0 18 0 19 0 20 0 21 0 22 0 23 1 78 - 78 24 0 25 1 83 - 84 26 0 27 0 28 0 29 1 92 - 92 30 1 95 - 95 31 0 32 0 33 0 34 0 35 0 36 0 37 1 111 - 113
我需要在字符向量格式的原始数据raw中,查找error_position列中的字符串对应的位置,原始数据样例如下:
HUBUSL1 2 ENTER LINE NUMBER 81 - 82 FOR HUBUS = 1 VALID ENTRIES 83 - 84 VALID ENTRIES 1 MIN VALUE 99 MAX VALUE HUBUSL3 2 See BUSL1 85 - 86 VALID ENTRIES 1 MIN VALUE 99 MAX VALUE HUBUSL4 2 See BUSL1 87 - 88 VALID ENTRIES 1 MIN VALUE 99 MAX VALUE A2. GEOGRAPHIC INFORMATION GEREG 2 REGION 89 - 90 EDITED UNIVERSE: ALL HHLD's IN SAMPLE VALID ENTRIES 1 NORTHEAST 2 MIDWEST (FORMERLY NORTH CENTRAL) 3 SOUTH 4 WEST GEDIV 1 DIVISION 91 - 91 EDITED UNIVERSE: ALL HHLD's IN SAMPLE VALID ENTRIES 92 – 92 GESTFIPS 2 FEDERAL INFORMATION 93 - 94 PROCESSING STANDARDS (FIPS) STATE CODE
例如df_parse的error_position列第25行的"83 - 84"匹配原始文件第5行,"92 – 92"匹配样例原始数据末尾的对应行。
我编写了如下for循环,使用grep从raw向量中返回error_position值的匹配位置:
results1<- vector(mode = "character", length = length(df_parse$error)) #empty vector for(i in seq_along(df_parse$error)){ results1[i]<- ifelse(df_parse$error[i] == 1, grep(pattern = paste(df_parse$error_position[i]), x = raw, value = FALSE), "") } results1
返回的样例结果如下:
[1] "" "" "" "37" "95" "" "" "" "" "" "" "" "" "" [15] "" "" "" "" "" "" "" "" "288" "" "298" "" "" "" [29] NA "381" "" "" "" "" "" "" "444" "" "" "" "" "" [43] "" "532" "" "551" "" "" "" "" NA "" "" "677" "" "" [57] "712" "" "" "" "" "" "" "" "838" "" "" "" "" "" [71] "" "" NA "" "" "" "" "991" "" "" "" "" "" "" [85] "" "" NA "1140" "" "1158" "" "" "" "" "" "" "" "" [99] "" "" "" "" "" "1283" "" "" "" NA "" "" "" "" [113] "" "" "" "" "" "" "" "" "" "" "" "" "" "1658" [127] "" "" "" NA "" "" "1749" "" "" "" "" "" "" "" [141] "1824" "" "" "" "" "" "" "" "" "" "" "" "" "" [155] "" "" "2065" "" "" "2109" "" "" "" "" "" "2161" "" "" [169] "" NA "" "" "" "" "" "" "" "" "2344" "" "" ""
这个结果基本符合预期,但我发现其中存在多处NA。排查后发现NA的产生原因是部分数字范围的分隔符不是普通短横杠,而是em长横杠:比如原始数据中的"92 – 92"是长横杠,而df_parse的error_position中存储的是普通短横杠格式的"92 - 92"。
但我尝试直接使用grep匹配长横杠格式的"92 – 92"时,仍然返回integer(0)无匹配结果,尝试过的写法如下:
grep(pattern = "92 – 92", x = raw, value = FALSE) == integer(0) grep(pattern = paste(df_parse$error_position[29]), x = raw, value = FALSE) == integer(0)
解决方案
方案1:统一预处理数据源格式后匹配
先把原始向量和匹配字段的横杠、空格做标准化处理,消除格式差异:
library(stringr) # 预处理raw:替换所有长横杠为短横杠,同时压缩多余空格 raw_clean <- str_squish(gsub("–", "-", raw, fixed = TRUE)) results1 <- vector(mode = "character", length = length(df_parse$error)) for(i in seq_along(df_parse$error)){ if(df_parse$error[i] == 1){ # 预处理匹配字段:同样压缩多余空格 pattern <- str_squish(df_parse$error_position[i]) match_res <- grep(pattern, raw_clean, fixed = TRUE, value = FALSE) # 处理无匹配的情况,避免返回integer(0)导致NA results1[i] <- ifelse(length(match_res) > 0, as.character(match_res[1]), "") } else { results1[i] <- "" } }
方案2:用正则兼容任意横杠格式
不需要修改原始数据,构造匹配模式时兼容长短横杠和任意空格:
results1 <- vector(mode = "character", length = length(df_parse$error)) for(i in seq_along(df_parse$error)){ if(df_parse$error[i] == 1){ # 把pattern里的短横杠替换为兼容长短横杠、任意前后空格的正则 pattern <- gsub("-", "\\s*[–-]\\s*", df_parse$error_position[i], fixed = TRUE) match_res <- grep(pattern, raw, value = FALSE) results1[i] <- ifelse(length(match_res) > 0, as.character(match_res[1]), "") } else { results1[i] <- "" } }
额外排查点
如果修改后仍有匹配失败,可通过stringi::stri_escape_unicode()分别打印匹配字段和raw对应行的编码,检查是否存在其他不可见特殊字符。
内容的提问来源于stack exchange,提问作者richardgasquet
相关产品推荐
相关产品推荐

