R 中的 grepl:匹配受到词内破折号的阻碍
grepl in R: matching impeded by intra-word dashes
我有 3 个词:x、y 和 z,从中可以构建两个复合词:x-y 和 y-z。
在自然出现的文本中,x、y 和 z 可以相互跟随。
在第一种情况下,我有:
text="x-y z"
我想检测:"x-y" 但不是 "y z"。
如果我这样做:
v=c("x-y","y z")
vv=paste("\b",v,"\b",sep="")
sapply(vv,grepl,text,perl=TRUE)
我得到 c(TRUE,TRUE)。换句话说,grepl 没有捕捉到 y 已经通过词内破折号链接到 x 的事实,因此 "y z" 实际上并不存在于文本中。所以我在文本开头添加空格后使用了一个lookbehind:
text=paste("",text,sep=" ")
vv=paste("(?<= )\b",v,"\b",sep="")
sapply(vv,grepl,text,perl=TRUE)
这一次,我得到了我想要的:c(TRUE, FALSE)。
现在,在第二种情况下,我有:
text="x y-z"
我想检测 "y-z" 而不是 "x y"。这次采用前瞻对称的方式,我尝试了:
text=paste(text,"",sep=" ")
v=c("x y","y-z")
vv=paste("(?= )\b",v,"\b",sep="")
sapply(vv,grepl,text,perl=TRUE)
但是这次我得到的是 c(FALSE,FALSE) 而不是我预期的 c(FALSE,TRUE)。
第一个位置的 FALSE 是预期的(前瞻检测到 y 之后存在字内破折号并阻止与 "x y" 匹配)。但我真的不明白是什么阻止了与 "y-z" 的匹配。
非常感谢您的帮助,
我认为这符合您在评论中对您想要完成的目标的描述。
spaceInvader <- function(a, b, text) {
# look ahead of `a` to see if there is a space
hasa <- grepl(paste0(a, '(?= )'), text, perl = TRUE)
# look behind `b` to see if there is a space
hasb <- grepl(paste0('(?<= )', b), text, perl = TRUE)
result <- c(hasa, hasb)
names(result) <- c(a, b)
cat('In: "', text, '"\n', sep = '')
return(result)
}
spaceInvader('x-y', 'y z', 'x-y z')
# In: "x-y z"
# x-y y z
# TRUE FALSE
spaceInvader('x y', 'y-z', 'x y-z')
# In: "x y-z"
# x y y-z
# FALSE TRUE
spaceInvader('x-y', 'y z', 'x y-z')
# In: "x y-z"
# x-y y z
# FALSE FALSE
spaceInvader('x y', 'y-z', 'x-y z')
# In: "x-y z"
# x y y-z
# FALSE FALSE
有问题吗?
spaceInvader('x-y', 'y-z', 'x-y-z')
# In: "x-y-z"
# x-y y-z
# FALSE FALSE
我有 3 个词:x、y 和 z,从中可以构建两个复合词:x-y 和 y-z。
在自然出现的文本中,x、y 和 z 可以相互跟随。 在第一种情况下,我有:
text="x-y z"
我想检测:"x-y" 但不是 "y z"。 如果我这样做:
v=c("x-y","y z")
vv=paste("\b",v,"\b",sep="")
sapply(vv,grepl,text,perl=TRUE)
我得到 c(TRUE,TRUE)。换句话说,grepl 没有捕捉到 y 已经通过词内破折号链接到 x 的事实,因此 "y z" 实际上并不存在于文本中。所以我在文本开头添加空格后使用了一个lookbehind:
text=paste("",text,sep=" ")
vv=paste("(?<= )\b",v,"\b",sep="")
sapply(vv,grepl,text,perl=TRUE)
这一次,我得到了我想要的:c(TRUE, FALSE)。 现在,在第二种情况下,我有:
text="x y-z"
我想检测 "y-z" 而不是 "x y"。这次采用前瞻对称的方式,我尝试了:
text=paste(text,"",sep=" ")
v=c("x y","y-z")
vv=paste("(?= )\b",v,"\b",sep="")
sapply(vv,grepl,text,perl=TRUE)
但是这次我得到的是 c(FALSE,FALSE) 而不是我预期的 c(FALSE,TRUE)。 第一个位置的 FALSE 是预期的(前瞻检测到 y 之后存在字内破折号并阻止与 "x y" 匹配)。但我真的不明白是什么阻止了与 "y-z" 的匹配。
非常感谢您的帮助,
我认为这符合您在评论中对您想要完成的目标的描述。
spaceInvader <- function(a, b, text) {
# look ahead of `a` to see if there is a space
hasa <- grepl(paste0(a, '(?= )'), text, perl = TRUE)
# look behind `b` to see if there is a space
hasb <- grepl(paste0('(?<= )', b), text, perl = TRUE)
result <- c(hasa, hasb)
names(result) <- c(a, b)
cat('In: "', text, '"\n', sep = '')
return(result)
}
spaceInvader('x-y', 'y z', 'x-y z')
# In: "x-y z"
# x-y y z
# TRUE FALSE
spaceInvader('x y', 'y-z', 'x y-z')
# In: "x y-z"
# x y y-z
# FALSE TRUE
spaceInvader('x-y', 'y z', 'x y-z')
# In: "x y-z"
# x-y y z
# FALSE FALSE
spaceInvader('x y', 'y-z', 'x-y z')
# In: "x-y z"
# x y y-z
# FALSE FALSE
有问题吗?
spaceInvader('x-y', 'y-z', 'x-y-z')
# In: "x-y-z"
# x-y y-z
# FALSE FALSE