如何仅在 R 中的变量中搜索特定字符串
How to search for only a specific string within a variable in R
在我的代码中,我有一个字符串变量 (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
,这将 return 作为 "TRUE",这不是我想要的.
我目前的解决方案是将上面的代码反转,所以它变成:
if (grepl("CVD III", panel_name) == TRUE){
panel_pref = ""
panel = "CVD3"
} else if (grepl("CVD II", panel_name) == TRUE){
panel_pref = ""
panel = "CVD2"
}
但这感觉有点乱,所以我想知道是否有一种方法可以在另一个字符串中专门搜索一个字符串。
我不能使用 if x == y(例如),因为变量有时包含多个我正在搜索的 "names",但 grepl
似乎不允许排除项。
Sabor117,
您应该查看 ?regexp 并扩展您对那里可用的正则表达式的使用。例如,如果只是为了区分"CVD II"和"CVD III",那么就可以直接用$来表示字符串的结尾,如下所示:
a <- "CVD III"
grepl(x=a,pattern="CVD II$")
根据您的情况,可能会有更好的解决方案。
此外,如果您是正则表达式的新手,能够尝试使用通配符和其他正则表达式语法会很有帮助。我也会向您指出那里的正则表达式资源之一。我个人最喜欢的是 https://regex101.com/
在 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"
或者,一个有点奇怪的选项:您的字符串包含罗马数字。提取出现在 CVD
:
之后的 I
字符串
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"
在我的代码中,我有一个字符串变量 (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
,这将 return 作为 "TRUE",这不是我想要的.
我目前的解决方案是将上面的代码反转,所以它变成:
if (grepl("CVD III", panel_name) == TRUE){
panel_pref = ""
panel = "CVD3"
} else if (grepl("CVD II", panel_name) == TRUE){
panel_pref = ""
panel = "CVD2"
}
但这感觉有点乱,所以我想知道是否有一种方法可以在另一个字符串中专门搜索一个字符串。
我不能使用 if x == y(例如),因为变量有时包含多个我正在搜索的 "names",但 grepl
似乎不允许排除项。
Sabor117,
您应该查看 ?regexp 并扩展您对那里可用的正则表达式的使用。例如,如果只是为了区分"CVD II"和"CVD III",那么就可以直接用$来表示字符串的结尾,如下所示:
a <- "CVD III"
grepl(x=a,pattern="CVD II$")
根据您的情况,可能会有更好的解决方案。
此外,如果您是正则表达式的新手,能够尝试使用通配符和其他正则表达式语法会很有帮助。我也会向您指出那里的正则表达式资源之一。我个人最喜欢的是 https://regex101.com/
在 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"
或者,一个有点奇怪的选项:您的字符串包含罗马数字。提取出现在 CVD
:
I
字符串
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"