在我的代码中,我有一个字符串变量(panel_name
),它可以具有以下几种形式:CVD II
或Onc, IR
或CVD II, CVD III
,依此类推-上。我还有一个函数,该函数然后在此变量中搜索特定的字符串,并根据它们的存在输出其他字符串。
例如,我有:
if (grepl("CVD II", panel_name) == TRUE){
panel_pref = ""
panel = "CVD2"
} else if (grepl("CVD III", panel_name) == TRUE){
panel_pref = ""
panel = "CVD3"
}
但是我遇到的问题是在示例输入CVD II
中,如果panel_name == CVD III
会返回“ TRUE”,这不是我想要的。
我当前的解决方案是只反转上面的代码,所以它变成:
if (grepl("CVD III", panel_name) == TRUE){
panel_pref = ""
panel = "CVD3"
} else if (grepl("CVD II", panel_name) == TRUE){
panel_pref = ""
panel = "CVD2"
}
但这感觉有点混乱,所以我想知道是否有一种方法可以在另一个字符串中专门搜索一个字符串。
例如,如果x == y,我将无法使用,因为该变量有时包含多个我正在搜索的“名称”,但是grepl
似乎没有允许的排除项。>
答案 0 :(得分:2)
在您的if
/ else
测试中使用的几个正则表达式选项:
test_cases <- c("CVD II", "CVD III")
在字符串末尾找到II
吗?
grepl("CVD II$", test_cases)
#> [1] TRUE FALSE
II
是否位于单词的边界?
grepl("CVD II\\b", test_cases)
#> [1] TRUE FALSE
是否发现II
之后没有其他I
?需要perl语法。
grepl("CVD II(?!I)", test_cases, perl = T)
#> [1] TRUE FALSE
或者您可以跳过if else
测试,并使用矢量化搜索并粘贴。 stringi
和stringr
包具有几个便捷功能。
如果您不希望I
出现,可以简单地计算I
的出现并将其粘贴到CVD
。
paste0("CVD", stringi::stri_count_regex(test_cases, "I"))
#> [1] "CVD2" "CVD3"
或者,有些奇怪的选择:您的字符串包含罗马数字。提取I
之后出现的CVD
字符串:
stringi::stri_extract_first_regex(test_cases, "(?<=CVD )(I+)")
#> [1] "II" "III"
您可以通过添加诸如([IVX]+)
之类的符号来扩展为更高的罗马数字。然后将其转换为utils::as.roman
的罗马数字对象,再转换为常规数字对象,然后粘贴。
paste0("CVD",
as.numeric(as.roman(stringi::stri_extract_first_regex(test_cases, "(?<=CVD )(I+)"))))
#> [1] "CVD2" "CVD3"
答案 1 :(得分:1)
Sabor117,
您应该签出?regexp并扩展那里使用的正则表达式的使用。例如,如果只是要区分“ CVD II”和“ CVD III”,则可以用$指示字符串的结尾,如下所示:
a <- "CVD III"
grepl(x=a,pattern="CVD II$")
根据您的情况,可能会有更好的解决方案。
此外,如果您不熟悉正则表达式,则可以尝试使用通配符和其他正则表达式语法。我也会指出您其中之一的正则表达式资源。我个人最喜欢的是https://regex101.com/