我认为这应该可行:
re <- regexpr(
"(?(?=.*?(\\d+\\.\\d+\\.\\d+\\.\\d+).*?)(\\1|))",
z$x, perl = TRUE)
regmatches(z$x, re)
#[1] "112.68.196.98" "192.41.196.888" "" ""
这使用正则表达式条件,在.*?(\\d+\\.\\d+\\.\\d+\\.\\d+).*? 上的正匹配情况下保留捕获组 (\\1),否则返回空结果。
更新:
关于您的评论,我认为以下更改将允许您在单个字符串中捕获多个 IP 地址。首先,从regexpr 切换到gregexpr 以允许多个结果:
re2 <- gregexpr(
"(?(?=.*?(\\d+\\.\\d+\\.\\d+\\.\\d+).*?)(\\1|))",
z2$x, perl = TRUE
)
由于在gregexpr 输入上调用regmatches 将返回一个列表,因此需要进行一些额外的处理:
res2 <- sapply(regmatches(z2$x, re2), function(x) {
gsub(
"^\\s+|\\s+$", "",
gsub("\\s+", " ", paste0(x, collapse = " "))
)
}
这应该适用于,例如,与您的 data.frame 重新组合为新列:
res2
#[1] "112.68.196.98 192.41.196.888" "192.41.196.888"
# "" "112.68.196.98"
如果您确实想将每个结果分解为自己的字符串,则表达式会更简单一些(与sapply(...)相比):
lapply(regmatches(z2$x, re2), function(x) {
Filter(function(y) y != "", x)
})
#[[1]]
#[1] "112.68.196.98" "192.41.196.888"
#[[2]]
#[1] "192.41.196.888"
#[[3]]
#character(0)
#[[4]]
#[1] "112.68.196.98"
数据:
z2 <- data.frame(
x = c('112.68.196.98 5.32 192.41.196.888',
'192.41.196.888',
'..', '5.32 88 112.68.196.98'),
stringsAsFactors = FALSE
)