r grep by regex - 查找一个包含一个子字符串的字符串

时间:2016-07-12 09:57:42

标签: regex r

我在Ubuntu中使用R,并尝试查看文件列表,其中一些是我需要的,其中一些我不需要,

我试图通过在其中找到一个子字符串来获得我需要的那个,它需要恰好出现一次,

我正在使用grep这个函数,我在这里找到了grep function in r

并使用我在此处找到的正则表达式规则regex rules

并采用简单的例子

a <- c("a","aa") 
grep("a{1}", a) 

我希望只获得包含&#34; a&#34;恰好一次,而不是它,我得到了他们两个。

当我使用2代替1时,我确实得到了一个字符串的所需结果(包含&#34; aa&#34;)

我无法使用$,因为这不是我需要的单词的结尾,例如我需要接受这两个单词&#34; germ-pass.tab&#34;,&# 34; germ-pass_germ-pass.tab&#34;并且只返回第一个包含&#34; germ-pass&#34;只有一次

我不能使用^ a因为我不需要像#&#34; aca&#34;

感谢。

6 个答案:

答案 0 :(得分:3)

正如我在评论中所说的那样,grep在你的字符串中查找一个模式,并且确实存在“a”(或“a {1}”,这对于grep来说是相同的) AA”。您需要在模式中添加“a”后面不是:"a[^a]"

grep("a[^a]", c("aa", "ab"), value=TRUE)
#[1] "ab"

修改

考虑到你的具体问题,似乎你可以尝试“反面”:使用模式的“捕获”过滤掉包含多个模式出现的字符串:

!grepl("(ab).+\\1", c("ab.t", "ab-ab.t"))
#[1]  TRUE FALSE

!grepl("(ab).*\\1", c("ab", "ab-ab","ab-cc-ab", "abab"))
#[1]  TRUE FALSE FALSE FALSE

括号允许捕获模式(此处ab但可以是任何正则表达式),.*用于“任何”零​​次或多次,\\1要求重复捕获的模式

答案 1 :(得分:3)

使用a但不是aa

检测字符串

您可以使用以下TRE正则表达式:

^[^a]*a[^a]*$

它匹配字符串的开头(^),除了a[^a]*)以外的0 +字符,a,再次0+非'a'和字符串的结尾($)。见IDEONE demo

a <- c("aca","cac","a", "abab", "ab-ab", "ab-cc-ab")
grep("^[^a]*a[^a]*$", a, value=TRUE)
## => [1] "cac" "a"

查找包含a但不包含aa

的整个单词

如果您需要匹配单词,只有一个a,而不是两个或更多a位于任何位置。

使用此PCRE正则表达式:

\b(?!\w*a\w*a)\w*a\w*\b

请参阅this regex demo

<强>解释

  • \b - 字边界
  • (?!\w*a\w*a) - 如果在字边界之后有0个字母字符,a,0 +字字符和a,则会出现否定前瞻字母
  • \w* - 0+ word chars
  • a - a
  • \w* - 0+ word chars
  • \b - 尾随字边界。

注意:由于\w与字母,数字和下划线匹配,您可能需要将其更改为\p{L}[^\W\d_](仅匹配字母)。< / p>

请参阅this demo

a <- c("aca","cac","a")
grep("\\b(?!\\w*a\\w*a)\\w*a\\w*\\b", a, perl=TRUE, value=TRUE)
## => [1] "cac" "a"  

答案 2 :(得分:3)

看起来你只追求一个a的字符串,而不管字符串中的哪个位置。虽然stringi可以完成任务,但基本解决方案是:

s <- c("a", "aa", "aca", "", "b", "ba", "ab")

m <- gregexpr("a", s)
s[lengths(regmatches(s, m)) == 1]

[1] "a"  "ba" "ab"

或者,正则表达式方法:

s[vapply(strsplit(s, ""), function(x) sum(x == "a") == 1, logical(1))]
[1] "a"  "ba" "ab"

答案 3 :(得分:2)

我们可以使用stringi::stri_count

library(stringi)
library(purrr)

# simulate some data
set.seed(1492)
(map_chr(1:10, function(i) {
  paste0(sample(letters, sample(10:30), replace=TRUE), collapse="")
}) -> strings)

## [1] "jdpcypoizdzvfzs"               "gyvcljnfmrzmdmkufq"           
## [3] "xqwrmnklbixnccwyaiadrsxn"      "bwbenawcwvdevmjfvs"           
## [5] "ytzwnpkuromfbklfsdnbwwnlrw"    "wclxpzftqgwxyetpsuslgohcdenuj"
## [7] "czkhanefss"                    "mxsrqrackxvimcxqcqsditrou"    
## [9] "ysqshvzjjmwes"                 "yzawyoqxqxiasensorlenafcbk" 

# How many "w"s in each string?
stri_count_regex(strings, "w{1}")

## [1] 0 0 2 3 4 2 0 0 1 1

答案 4 :(得分:1)

我们可以尝试使用^$来确保只有一个&#39; a&#39;在字符串中

grep("^a$", a)
#[1] 1

目前尚不清楚OP想要什么。

答案 5 :(得分:0)

base 中,当您用gsub删除子字符串并测试是否剩余的字符串时,您会找到一个仅包含一次子字符串的字符串。长等于搜索到的子字符串:

s <- c("a", "aa", "aca", "", "b", "ba", "ab", "cac", "abab", "ab-ab", NA)
ss  <- "a" #Substring to find exactly once

nchar(s) - nchar(gsub(ss, "", s)) == nchar(ss)
#[1]  TRUE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE FALSE    NA

或者您统计gregexpr的点击次数

sapply(gregexpr(ss, s), function(x) sum(x>0)) == 1
# [1]  TRUE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE FALSE    NA

或已提及@ sebastian-c

lengths(regmatches(s, gregexpr(ss, s))) == 1
# [1]  TRUE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE FALSE FALSE

或带有两个grepl,一个询问子字符串是否存在一次,另一个询问子字符串是否存在两次:

!grepl("(.*a){2}", s) & grepl("a", s)
# [1]  TRUE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE FALSE FALSE

或一个 regex 中解释的内容,其中(?!(.*a){2})是非消耗性(零宽度)否定超前行

grepl("^(?!(.*a){2}).*a.*$", s, perl=TRUE)
# [1]  TRUE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE FALSE FALSE

或更笼统,如果您想对其进行更改以恰好找到n次子字符串

!grepl("(.*a){2}", s) & grepl("(.*a){1}", s)
# [1]  TRUE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE FALSE FALSE

grepl("^(?!(.*a){2})(.*a){1}.*$", s, perl=TRUE)
# [1]  TRUE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE FALSE FALSE

如果只寻找一个字符,则可以使用解决方案表格@wiktor-stribiżew

grepl("^[^a]*a[^a]*$", s)
# [1]  TRUE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE FALSE FALSE