使用tidyr按自定义分隔符拆分文本:缺失匹配时填充NA维持列结构
解决tidyr拆分文本时缺失分隔符导致列错位的问题
嘿,这个问题我之前也碰到过——用tidyr按自定义分隔符拆分文本时,要是某个分隔符没出现,后面的内容就会往前串,列直接错位,太闹心了!别担心,用tidyr::separate_wider_regex()就能完美解决,它专门处理这种需要匹配特定模式、缺失时自动填充NA的场景。
先看你的示例数据
首先把你的测试数据整理好:
library(tidyr) example <- c( "PatientName is Mr B Goode. Referrer Bilbo Baggins Hospital Number 23434B DOB 13/01/77 Findings All good Diagnosis Normal", "PatientName is Mr A Notgood. Hospital Number 12345C DOB 01/05/88 Findings Needs follow-up" ) df <- data.frame(text = example)
核心解决方案:用separate_wider_regex()精准匹配
关键是给每个目标列定义精确的正则匹配规则,明确每个字段的起始标识和结束边界,这样即使某个字段的起始标识(分隔符)不存在,对应的列就会自动填充NA,不会错位。
这里我们针对你提到的字段(PatientName、Referrer、Hospital Number、DOB、Findings、Diagnosis)写匹配规则:
df_clean <- df %>% separate_wider_regex( col = text, patterns = list( PatientName = "PatientName is (.*?)(?=\\. Referrer|\\. Hospital|\\. Findings|\\. Diagnosis|$)", Referrer = "(?:Referrer )(.*?)(?= Hospital Number| DOB| Findings| Diagnosis|$)", Hospital_Number = "(?:Hospital Number )(.*?)(?= DOB| Findings| Diagnosis|$)", DOB = "(?:DOB )(.*?)(?= Findings| Diagnosis|$)", Findings = "(?:Findings )(.*?)(?= Diagnosis|$)", Diagnosis = "(?:Diagnosis )(.*)" ), too_few = "align_start" # 确保缺失字段填充NA )
看看结果
运行后你会得到这样的输出:
> df_clean # A tibble: 2 × 6 PatientName Referrer Hospital_Number DOB Findings Diagnosis <chr> <chr> <chr> <chr> <chr> <chr> 1 "Mr B Goode" "Bilbo Baggins" "23434B" "13/01/77" "All good" "Normal" 2 "Mr A Notgood" NA "12345C" "01/05/88" "Needs follow-up" NA
你看,第二条数据里没有Referrer和Diagnosis,对应的列就自动填充了NA,完全不会错位!
简单解释下正则逻辑
- 每个字段的正则里,
(.*?)是捕获我们要提取的内容(非贪婪匹配,避免把后面的内容也抓进来) (?=...)是正向预查,用来确定当前字段的结束边界——比如PatientName的结束边界是. Referrer、. Hospital等,或者文本末尾(?:...)是非捕获组,用来匹配字段的起始标识(比如Referrer),但不会把标识本身放进结果里too_few = "align_start"参数确保当某个字段没匹配到时,后续字段不会往前挪,而是填充NA
如果你的分隔符列表有变化,只需要调整正则里的预查条件和起始标识就行,灵活得很!
内容的提问来源于stack exchange,提问作者Sebastian Zeki
相关产品推荐
相关产品推荐

