문자가 문자열에 있는지 테스트


279

문자열이 다른 문자열의 하위 집합인지 확인하려고합니다. 예를 들면 다음과 같습니다.

chars <- "test"
value <- "es"

"value"가 "chars"문자열의 일부로 나타나면 TRUE를 반환하고 싶습니다. 다음 시나리오에서는 false를 반환하려고합니다.

chars <- "test"
value <- "et"

12
허용 된 답변이 잘못되었으므로 추가해야합니다 fixed=TRUE. 그렇지 않으면 문자열 대신 정규식으로 처리합니다. 2016 년 10 월에서 내 답변을 참조하십시오.
Joshua Cheek

@JoshuaCheek 패턴에 특수 문자가 없으면 정규 표현식은 고정과 동일한 결과를 반환합니다.
user3932000

1
물론, 문자 그대로 전달하면 알 수 있습니다. 그렇지 않으면 패턴에 어떤 문자가 있는지 알 수 없으므로 fixed=TRUE데이터를 조용하고 미묘하게 엉망으로 만드는 버그가 있습니다.
Joshua Cheek

답변:


388

grepl기능을 사용하십시오

grepl(value, chars, fixed = TRUE)
# TRUE

?grepl자세한 내용을 알아 보려면 사용하십시오 .


8
이 간단한 경우 fixed = TRUE를 추가하면 성능이 향상 될 수 있습니다 (이러한 계산을 많이 수행한다고 가정).
Greg Snow

1
@Josh O'brien, 그 게시물은 하나의 긴 문자열에서 모든 일치하는 것을 찾은 (계산) 비교하여 더 짧은 문자열에서 1 개의 일치하는 것을 찾으십시오 vec <- replicate(100000, paste( sample(letters, 10, replace=TRUE), collapse='') ).
Greg Snow

2
시도 - @GregSnow system.time(a <- grepl("abc", vec))하고 system.time(a <- grepl("abc", vec, fixed=TRUE)), 그리고 fixed=TRUE만약 아무것도 약간 느린, 아직도있다. 이 짧은 줄에서는 그 차이가 눈에 띄지 않지만 fixed=TRUE여전히 더 빠르지는 않습니다. 그러나 fixed=TRUE실제 히트 를 취하는 긴 줄에 있다는 것을 지적 해 주셔서 감사합니다 .
Josh O'Brien

2
grepl (pattern, x) 최소 2017 년
JMR

2
값은 정규식 패턴으로 해석되므로 허용되는 답변이 아니어야합니다. 찾고있는 문자열이 정규식 패턴처럼 보이지 않을 것을 알지 않는 한 fixed = TRUE는 항상 사용해야합니다. 아래의 Joshua Creek의 대답은 이에 대한 매우 명확한 설명을 담고 있으며 받아 들여 져야합니다.
bhaller

159

대답

이 간단한 질문에 대한 답을 찾는 데 45 분이 걸렸습니다. 정답은:grepl(needle, haystack, fixed=TRUE)

# Correct
> grepl("1+2", "1+2", fixed=TRUE)
[1] TRUE
> grepl("1+2", "123+456", fixed=TRUE)
[1] FALSE

# Incorrect
> grepl("1+2", "1+2")
[1] FALSE
> grepl("1+2", "123+456")
[1] TRUE

해석

grep의 약어가 자체 인 리눅스 실행 파일의 이름을 따서 명명된다 " G lobal R egular E xpression P RINT"는 입력 라인을 읽고 그들이 당신이 준 인수를 일치하는 경우 다음을 인쇄 할 것이다. "Global"은 입력 행의 어느 곳에서나 일치가 발생할 수 있음을 의미합니다. 아래 "Regular Expression"에 대해 설명하지만 문자열 (R은이 "문자"라고 함 class("abc")) 및 "Print "명령 줄 프로그램이기 때문에 출력을내는 것은 출력 문자열로 인쇄한다는 의미입니다.

이제 grep프로그램은 기본적으로 입력 라인에서 출력 라인에 이르는 필터입니다. 그리고 R의 grep함수도 마찬가지로 입력 배열을 취할 것으로 보입니다 . 나에게 전혀 알려지지 않은 이유 때문에 (약 1 시간 전에 R을 사용하기 시작한 것), 일치하는 목록이 아니라 일치하는 인덱스의 벡터를 반환합니다.

그러나 원래 질문으로 돌아가서, 우리가 정말로 원하는 것은 건초 더미에서 바늘을 찾았는지, 참 / 거짓 값인지 아는 것입니다. 그들은 분명히이 기능의 이름을하기로 결정했다 grepl"GREP"같이하지만, "와, L ogical"반환 값 (그들은, 예를 진실과 거짓 논리 값을 호출 class(TRUE)).

이제 우리는 그 이름이 어디에서 왔으며 무엇을해야하는지 알게되었습니다. 정규식으로 돌아갑니다. 인수는 문자열이지만 정규 표현식을 작성하는 데 사용됩니다 (이후 정규 표현식). 정규 표현식은 문자열을 일치시키는 방법입니다 (이 정의가 자극을 주면 그대로 두십시오). 예를 들어, 정규식 a은 문자와 일치하고 "a"정규식 a*은 문자와 "a"0 번 이상 a+일치하며 정규식 은 문자와 "a"1 번 이상 일치합니다 . 따라서 위의 예에서, 우리가 찾고있는 바늘 1+2은 정규 표현식으로 취급 될 때 "하나 이상 1 뒤에 2"가있는 것을 의미하지만 우리 뒤에는 플러스가 있습니다!

정규식으로 1 + 2

따라서 greplwithout 설정 을 사용 하지 않으면 fixed바늘이 실수로 건초 더미가되어 실수로 자주 작동하는 경우 OP의 예에서도 작동한다는 것을 알 수 있습니다. 그러나 그것은 잠복적인 버그입니다! 우리는 입력이 정규 표현식이 아닌 문자열이라는 것을 분명히해야 fixed합니다. 왜 고정 되었습니까? 실마리는 없습니다.이 답변을 북마크에 추가하십시오. 암기하기 전에 5 번 더 찾아봐야 할 것입니다.

몇 가지 마지막 생각

코드가 좋을수록 코드를 이해하기 위해 알아야 할 이력이 줄어 듭니다. 모든 인수는 적어도 두 가지 흥미로운 값을 가질 수 있습니다 (그렇지 않으면 인수가 될 필요는 없습니다). 문서는 9 개의 인수를 나열합니다.이를 호출하는 데 적어도 2 ^ 9 = 512 가지 방법이 있다는 것을 의미합니다. 쓰기, 테스트 및 기억 ... 이러한 기능을 분리합니다 (분할, 서로 의존성 제거, 문자열 사물이 정규식 사물과 벡터 사물과 다름) 옵션 중 일부는 상호 배타적이며, 코드를 사용하는 잘못된 방법을 사용자에게 제공하지 않습니다. 즉, 문제가있는 호출은 논리적으로 무의미하지 않고 (존재하지 않는 옵션을 전달하는 등) 구조적으로 무의미해야합니다. 설명하기 위해 경고를 보냅니다). 은유 적으로 넣어 : 10 층 측면의 전면 도어를 벽으로 교체하는 것은 사용에 대해 경고하는 표지판을 걸는 것보다 낫지 만 둘 중 하나보다 낫습니다. 인터페이스에서 함수는 호출자가 아닌 인수의 모양을 정의합니다 (호출자는 함수에 의존하기 때문에 모든 사람이 호출하고자하는 모든 것을 유추하여 함수도 호출자에 따라 달라집니다. 주기적 종속성은 시스템을 빠르게 방해하고 기대하는 이점을 제공하지 않습니다). 혼란스러운 유형에 매우주의하십시오. 그것은 디자인 결함입니다. 모든 사람이 호출하고자하는 모든 것을 유추하면 함수도 호출자에게 의존하게 되며이 유형의 주기적 종속성은 시스템을 빠르게 방해하고 기대하는 이점을 제공하지 않습니다). 혼란스러운 유형에 매우주의하십시오. 그것은 디자인 결함입니다. 모든 사람이 호출하고자하는 모든 것을 유추하면 함수도 호출자에게 의존하게 되며이 유형의 주기적 종속성은 시스템을 빠르게 방해하고 기대하는 이점을 제공하지 않습니다). 혼란스러운 유형에 매우주의하십시오. 그것은 디자인 결함입니다.TRUE0"abc"모든 벡터이다.


6
당신의 설명을 위해 건배! R은 오랜 기간 동안 진화 한 것으로 보이며 이상한 디자인 선택에 갇혀 있습니다 (예 : 값 유형에 대한 이 질문에 대한 답변 참조 ). 그러나이 경우 일치 인덱스로 구성된 벡터를 반환하면 grep셀이 아닌 행을 필터링하는 것처럼 적절 합니다.
krevelen

4
"고정"은 "고정"순서와 일치하는 문자를 나타냅니다.
Will Beason

32

당신이 원하는 grepl:

> chars <- "test"
> value <- "es"
> grepl(value, chars)
[1] TRUE
> chars <- "test"
> value <- "et"
> grepl(value, chars)
[1] FALSE

27

stringi패키지 에서이 기능을 사용하십시오 .

> stri_detect_fixed("test",c("et","es"))
[1] FALSE  TRUE

일부 벤치 마크 :

library(stringi)
set.seed(123L)
value <- stri_rand_strings(10000, ceiling(runif(10000, 1, 100))) # 10000 random ASCII strings
head(value)

chars <- "es"
library(microbenchmark)
microbenchmark(
   grepl(chars, value),
   grepl(chars, value, fixed=TRUE),
   grepl(chars, value, perl=TRUE),
   stri_detect_fixed(value, chars),
   stri_detect_regex(value, chars)
)
## Unit: milliseconds
##                               expr       min        lq    median        uq       max neval
##                grepl(chars, value) 13.682876 13.943184 14.057991 14.295423 15.443530   100
##  grepl(chars, value, fixed = TRUE)  5.071617  5.110779  5.281498  5.523421 45.243791   100
##   grepl(chars, value, perl = TRUE)  1.835558  1.873280  1.956974  2.259203  3.506741   100
##    stri_detect_fixed(value, chars)  1.191403  1.233287  1.309720  1.510677  2.821284   100
##    stri_detect_regex(value, chars)  6.043537  6.154198  6.273506  6.447714  7.884380   100

22

또한 "stringr"라이브러리를 사용하여 수행 할 수 있습니다 .

> library(stringr)
> chars <- "test"
> value <- "es"
> str_detect(chars, value)
[1] TRUE

### For multiple value case:
> value <- c("es", "l", "est", "a", "test")
> str_detect(chars, value)
[1]  TRUE FALSE  TRUE FALSE  TRUE

20

문자열 (또는 문자열 집합)에 여러 개의 하위 문자열이 포함되어 있는지 확인하려는 경우에도 '|' 두 개의 하위 문자열 사이

>substring="as|at"
>string_vector=c("ass","ear","eye","heat") 
>grepl(substring,string_vector)

당신은 얻을 것이다

[1]  TRUE FALSE FALSE  TRUE

첫 번째 단어에는 하위 문자열 "as"가 있고 마지막 단어에는 하위 문자열 "at"가 포함되므로


OR 연산자는 내가 필요한 것입니다! +1
Sam

10

사용 grep또는 grepl 그러나 당신이 정규 표현식을 사용할지 여부를 인식 .

기본적으로 grep관련 은 리터럴 하위 문자열이 아닌 일치 하는 정규식을 사용합니다 . 그것을 기대하지 않고 유효하지 않은 정규식과 일치하려고하면 작동하지 않습니다.

> grep("[", "abc[")
Error in grep("[", "abc[") : 
  invalid regular expression '[', reason 'Missing ']''

실제 부분 문자열 테스트를 수행하려면을 사용하십시오 fixed = TRUE.

> grep("[", "abc[", fixed = TRUE)
[1] 1

정규식을 원한다면 훌륭하지만 OP가 묻는 것처럼 보이지는 않습니다.


7

당신이 사용할 수있는 grep

grep("es", "Test")
[1] 1
grep("et", "Test")
integer(0)

0

비슷한 문제가 있습니다 : 문자열과 키워드 목록이 주어지면 문자열에 포함 된 키워드가 있는지 감지하십시오.

이 스레드 추천 제안 stringrstr_detectgrepl. microbenchmark패키지 의 벤치 마크는 다음과 같습니다 .

사용

map_keywords = c("once", "twice", "few")
t = "yes but only a few times"

mapper1 <- function (x) {
  r = str_detect(x, map_keywords)
}

mapper2 <- function (x) {
  r = sapply(map_keywords, function (k) grepl(k, x, fixed = T))
}

그리고

microbenchmark(mapper1(t), mapper2(t), times = 5000)

우리는 찾는다

Unit: microseconds
       expr    min     lq     mean  median      uq      max neval
 mapper1(t) 26.401 27.988 31.32951 28.8430 29.5225 2091.476  5000
 mapper2(t) 19.289 20.767 24.94484 23.7725 24.6220 1011.837  5000

당신이 볼 수 있듯이, 5000 이상 반복 사용하여 검색 키워드 str_detectgrepl키워드의 실제 문자열 및 벡터 이상 grepl꽤보다 더 잘 수행 str_detect.

결과는 r어떤 키워드가 문자열에 포함되어 있는지 식별하는 부울 벡터 입니다.

따라서 grepl키워드가 문자열인지 확인하는 데 사용 하는 것이 좋습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.