如何在R语言中识别并转换混合文本中的罗马数字为整数?
解决方案
首先加载所需包并处理原始数据中的字符型"NA":
library(stringr) library(gtools) # 原始数据 x <- data.frame(col = c("15", "NA", "0", "Red", "iv", "Logic", "ix. Sweet", "VIII - Apple", "Big XVI", "WeirdVII", "XI: Small")) # 将字符型"NA"转为真正的NA值 x$col[x$col == "NA"] <- NA
问题原因
你之前的代码错误是因为str_extract会提取字符串中单个的罗马数字字母(比如Logic里的i),而roman2int("i")会返回1,导致纯字符被错误转换。我们需要准确识别有效的罗马数字序列,排除单词内部的单个罗马字母。
完整转换代码
编写验证有效罗马数字的辅助函数,再实现转换逻辑:
# 辅助函数:验证字符串是否为有效罗马数字 is_valid_roman <- function(s) { s_upper <- toupper(s) # 仅允许罗马数字字符 if (!str_detect(s_upper, "^[IVXLCDM]+$")) return(FALSE) # 禁止四个连续相同字符 if (str_detect(s_upper, "(.)\\1{3,}")) return(FALSE) # 禁止非法的前置小数字组合(如IL、IC等) invalid_patterns <- c("IL", "IC", "ID", "IM", "VL", "VC", "VD", "VM", "XD", "XM") if (any(str_detect(s_upper, paste(invalid_patterns, collapse = "|")))) return(FALSE) # 尝试转换,无报错则有效 tryCatch({ roman2int(s_upper) TRUE }, error = function(e) FALSE) } # 核心转换函数 convert_roman_col <- function(vec) { sapply(vec, function(s) { # 处理NA值 if (is.na(s)) return(NA) # 优先转换整数型字符串(如"15"、"0") num <- suppressWarnings(as.integer(s)) if (!is.na(num)) return(num) # 检查整个字符串是否为有效罗马数字(如"iv") if (is_valid_roman(s)) { return(roman2int(toupper(s))) } # 提取字符串中长度≥2的罗马数字序列(避免匹配单词内部的单个字母) roman_matches <- str_extract_all(s, "[IVXivx]{2,}")[[1]] # 过滤出有效的罗马数字 valid_matches <- roman_matches[sapply(roman_matches, is_valid_roman)] # 转换第一个有效匹配的罗马数字 if (length(valid_matches) > 0) { return(roman2int(toupper(valid_matches[1]))) } # 无有效罗马数字则返回原字符串 return(s) }) } # 应用转换函数 x$converted_col <- convert_roman_col(x$col)
转换结果
运行后x$converted_col的结果为:
[1] 15 NA 0 "Red" 4 "Logic" 9 8 16 7 11
完全符合你的预期需求。
内容的提问来源于stack exchange,提问作者mr.questions
相关产品推荐
相关产品推荐

