我正在尝试提取:
或;
之后,如果存在第二个标点,则在;
之前提取字符串,然后删除;
之后的所有内容如果存在。目标结果是一个数字。
当前代码可以在:
和;
之间执行,也可以在:
之后执行,但是不能单独处理;
或单独处理:
。
此外,gsub(|(OF 100); SEE NOTE)
无法正常工作,我不确定为什么不排除最初的:
并完全需要gsub的原因。
test<-c("Score (ABC): 2 (of 100); see note","Amount of ABC; 30%","Presence of ABC: negative","ABC not tested")
#works for :/;
toupper((regmatches(toupper(test), gregexpr(":\\s* \\K.*?(?=;)", toupper(test), perl=TRUE))))
#works for :
test<-toupper((regmatches(toupper(test), gregexpr(":\\s* (.*)", toupper(test), perl=TRUE))))
#removes extra characters:
test<-gsub(": |(OF 100); SEE NOTE|%|; ","",test)
#Negative to numeric:
test[grepl("NEGATIVE|<1",test)]<-0
test
预期结果:2 30 0
答案 0 :(得分:2)
以下是一些解决方案。
前两个是基数。第一个仅使用非常简单的正则表达式。第二个更短,正则表达式稍微复杂一点。在这两种情况下,如果没有匹配项,我们都会返回NA,但是如果对您很重要,那么之后您可以将NA替换为0(使用ifelse(is.na(x), 0, x)
,其中x
是NA的答案)。
第三个与第二个几乎相同,但是在gsubfn中使用了捆扎。它返回0而不是NA。
1)read.table 用分号替换所有冒号,并以分号分隔的字段形式读取。选择第二个此类字段,并删除第一个非数字及其后面的所有内容。然后将剩下的转换为数字。
DF <- read.table(text = gsub(":", ";", test),
as.is = TRUE, fill = TRUE, sep = ";", strip.white = TRUE)
as.numeric(sub("\\D.*", "", DF$V2))
##[1] 2 30 NA
2)捕获从开头的非冒号或分号字符开始匹配,然后匹配冒号或分号,然后匹配空格,最后捕获数字。返回捕获的数字转换为数字。
strcapture("^[^:;]+[;:] (\\d+)", test, list(num = numeric(0)))$num
##[1] 2 30 NA
3)紧紧使用与(2)中相同的模式将匹配项转换为数字,如果匹配项为空,则返回0。
library(gsubfn)
strapply(test, "^[^:;]+[;:] (\\d+)", as.numeric, simplify = TRUE, empty = 0)
## [1] 2 30 0
答案 1 :(得分:0)
另一种方法:
out <- gsub('(^.+?[;:][^0-9]+)(\\d+)(.*$)|^.+', '\\2', test)
out[out == ''] <- 0
as.numeric(out)
## [1] 2 30 0
答案 2 :(得分:0)
按照OP的描述(斜体是我的):
在:或;之后提取字符串。并且在之前;如果存在第二个标点符号,请然后删除;之后的所有内容。 (如果存在)。目标结果是一个数字。
我认为其他一些建议可能会忽略该斜体标准。因此,这是OP的测试集,最后带有一个额外条件来测试该测试集:
test<-c( "Score (ABC): 2 (of 100); see note",
"Amount of ABC; 30%",
"Presence of ABC: negative",
"...and before a ; if the second punctuation is present, then remove everything after a ; if present [so 666 should not be returned]")
sub( pattern='.+?[:;]\\D*?[^;](\\d*).*?;*.*',
replacement='\\1',
x=test, perl=TRUE)
[1] "2" "30" "" ""
如果OP确实想要一个没有找到匹配项的零整数,则设置sub()替换= '0\\1'
并用as.integer()
包装,如下所示:
as.integer( gsub( pattern='.+?[:;]\\D*?[^;](\\d*).*?;*.*',
replacement='0\\1',
x=test, perl=TRUE) )
结果:
[1] 2 30 0 0
OP只希望在字符串中找到一个匹配项,因此sub()
函数可以正常工作。
使用sub()
的技术是制作一个匹配所有字符串的模式,但如果满足条件,则使用中间的捕获组捕获零个或多个数字。
模式.+?[:;]\\D*?[^;](\\d*).*?;*.*
的读取方式如下
.+?
在一个和无限次+
之间匹配任意字符(行终止符除外)?
越少越好,并根据需要扩展(惰性)[:;]
在列表中的方括号之间匹配单个字符,在这种情况下为:
或;
\\D
匹配任何非数字字符(等于[^ 0-9])*?
量词*
尽可能在零和无限次数?
之间进行匹配,并根据需要扩展(延迟)[^;]
^
帽子作为方括号之间的第一个字符表示:匹配方括号之间的列表中不存在的单个字符,在这种情况下,匹配不包含任何字符的;
< / li>
(\d*)
尖括号之间的所有内容都是一个捕获组-这是第一个捕获组:\\d*
匹配零到无限次之间的一个数字(等于[0-9]),次数不计其数尽可能(贪婪);*
匹配;
字符*
零次至无限次 [so; 不一定要存在但是否存在:这是在第二个定界符之后按OP请求排除任何内容的关键]]
.*
在零个和无限次之间匹配任意一个字符*
,并尽可能多地匹配(贪婪)[因此将所有内容提取到行尾] 替换= \\1
指的是我们模式中的第一个捕获组。我们用捕获组中找到的替换所有与模式匹配的内容。 \\d*
不能匹配任何数字,因此如果在我们期望的位置找不到数字,则会返回一个空字符串。