정규식 일치 추출


111

문자열에서 숫자를 추출하려고합니다.

그리고 [0-9]+문자열에서 같은 것을 "aaa12xxx"하고 "12".

나는 그것이 다음과 같을 것이라고 생각했습니다.

> grep("[0-9]+", "aaa12xxx", value=TRUE)
[1] "aaa12xxx"

그리고 나는 생각했다 ...

> sub("[0-9]+", "\\1", "aaa12xxx")
[1] "aaaxxx"

하지만 다음과 같은 응답을 받았습니다.

> sub("[0-9]+", "ARGH!", "aaa12xxx")
[1] "aaaARGH!xxx"

내가 놓친 작은 세부 사항이 있습니다.

답변:


167

기존 정규식을 모두 래핑하는 새 stringr 패키지를 사용하여 일관된 구문으로 작동하고 누락 된 몇 가지를 추가합니다.

library(stringr)
str_locate("aaa12xxx", "[0-9]+")
#      start end
# [1,]     4   5
str_extract("aaa12xxx", "[0-9]+")
# [1] "12"

3
(거의) 정확히 내가 필요로했지만 타이핑을 시작하면서 ?str_extract나는 보았고 str_extract_all인생은 다시 좋았습니다.
dwanderson

94

' 표준 기능 무시 '라고 말하는 것은 조금 서두르다 ?gsub. '참조'에서 특별히 참조 하는 도움말 파일 :

'regexpr', 'gregexpr'및 'regexec'의 결과를 기반으로 일치하는 부분 문자열을 추출하기위한 'regmatches'.

따라서 이것은 작동하고 매우 간단합니다.

txt <- "aaa12xxx"
regmatches(txt,regexpr("[0-9]+",txt))
#[1] "12"

27

아마도

gsub("[^0-9]", "", "aaa12xxxx")
# [1] "12"

15

PERL 정규식의 지연 일치를 사용할 수 있습니다.

> sub(".*?([0-9]+).*", "\\1", "aaa12xx99",perl=TRUE)
[1] "12"

이 경우 숫자가 아닌 것을 대체하려고하면 오류가 발생합니다.


4
당신이 ". [^ 0-9] * ([0-9] +) *"약간 추악한를 사용하고자하는 경우 PERL을 필요로하지 않는다
Jyotirmoy 데브 브 하타 차르

5

한 가지 방법은 다음과 같습니다.

test <- regexpr("[0-9]+","aaa12456xxx")

이제 regexpr이 문자열의 시작 및 끝 인덱스를 제공합니다.

    > test
[1] 4
attr(,"match.length")
[1] 5

따라서 해당 정보를 substr 함수와 함께 사용할 수 있습니다.

substr("aaa12456xxx",test,test+attr(test,"match.length")-1)

이 작업을 수행하는 더 우아한 방법이 있다고 확신하지만 이것이 제가 찾을 수있는 가장 빠른 방법이었습니다. 또는 sub / gsub를 사용하여 원하는 것을 남기고 싶지 않은 것을 제거 할 수 있습니다.


5

정규식에 캡처 링 괄호를 사용하고 대체에 그룹 참조를 사용합니다. 괄호 안의 모든 것이 기억됩니다. 그런 다음 첫 번째 항목 인 \ 2에 의해 액세스됩니다. 첫 번째 백 슬래시는 R에서 백 슬래시의 해석을 이스케이프하여 정규식 파서로 전달됩니다.

gsub('([[:alpha:]]+)([0-9]+)([[:alpha:]]+)', '\\2', "aaa12xxx")

2

gsubfn 패키지에서 strapply 사용. strapply는 객체가 (배열이 아닌) 문자열의 벡터이고 수정자가 (여백이 아닌) 정규 표현식이라는 점을 제외하고는 인수가 객체, 수정 자 및 함수라는 점에서 apply와 같습니다.

library(gsubfn)
x <- c("xy13", "ab 12 cd 34 xy")
strapply(x, "\\d+", as.numeric)
# list(13, c(12, 34))

이것은 as.numeric을 통해 각 일치를 전달하는 x의 각 구성 요소에서 하나 이상의 숫자 (\ d +)를 일치시킵니다. 구성 요소가 x의 각 구성 요소와 일치하는 벡터 인 목록을 반환합니다. at 출력을 보면 x의 첫 번째 구성 요소에는 13 인 일치 항목이 하나 있고 x의 두 번째 구성 요소에는 12와 34 인 일치 항목이 두 개 있음을 알 수 있습니다 . 자세한 내용은 http://gsubfn.googlecode.com 을 참조하세요.


1

또 다른 해결책 :

temp = regexpr('\\d', "aaa12xxx");
substr("aaa12xxx", temp[1], temp[1]+attr(temp,"match.length")[1])

1

이러한 접근 방식 사이의 한 가지 중요한 차이점은 일치하지 않는 동작에 대한 것입니다. 예를 들어 모든 위치에 일치하는 항목이 없으면 regmatches 메서드가 입력과 동일한 길이의 문자열을 반환하지 않을 수 있습니다.

> txt <- c("aaa12xxx","xyz")

> regmatches(txt,regexpr("[0-9]+",txt)) # could cause problems

[1] "12"

> gsub("[^0-9]", "", txt)

[1] "12" ""  

> str_extract(txt, "[0-9]+")

[1] "12" NA  

1

이 질문에 대한 해결책

library(stringr)
str_extract_all("aaa12xxx", regex("[[:digit:]]{1,}"))
# [[1]]
# [1] "12"

[[: digit :]] : 숫자 [0-9]

{1,} : 1 회 이상 일치


0

unglue 패키지를 사용하여 다음을 수행합니다.

# install.packages("unglue")
library(unglue)
unglue_vec(c("aaa12xxx", "aaaARGH!xxx"), "{prefix}{number=\\d+}{suffix}", var = "number")
#> [1] "12" NA

reprex 패키지 (v0.3.0)에 의해 2019-11-06에 생성됨

convert인수를 사용하여 자동으로 숫자로 변환합니다.

unglue_vec(
  c("aaa12xxx", "aaaARGH!xxx"), 
  "{prefix}{number=\\d+}{suffix}", 
  var = "number", 
  convert = TRUE)
#> [1] 12 NA

-2

C ++로 정규식 함수를 작성하고 DLL로 컴파일 한 다음 R에서 호출 할 수 있습니다.

    #include <regex>

    extern "C" {
    __declspec(dllexport)
    void regex_match( const char **first, char **regexStr, int *_bool)
    {
        std::cmatch _cmatch;
        const char *last = *first + strlen(*first);
        std::regex rx(*regexStr);
        bool found = false;
        found = std::regex_match(*first,last,_cmatch, rx);
        *_bool = found;
    }

__declspec(dllexport)
void regex_search_results( const char **str, const char **regexStr, int *N, char **out )
{
    std::string s(*str);
    std::regex rgx(*regexStr);
    std::smatch m;

    int i=0;
    while(std::regex_search(s,m,rgx) && i < *N) {
        strcpy(out[i],m[0].str().c_str());
        i++;
        s = m.suffix().str();
    }
}
    };

R을 다음으로 호출

dyn.load("C:\\YourPath\\RegTest.dll")
regex_match <- function(str,regstr) {
.C("regex_match",x=as.character(str),y=as.character(regstr),z=as.logical(1))$z }

regex_match("abc","a(b)c")

regex_search_results <- function(x,y,n) {
.C("regex_search_results",x=as.character(x),y=as.character(y),i=as.integer(n),z=character(n))$z }

regex_search_results("aaa12aa34xxx", "[0-9]+", 5)

4
이것은 완전히 불필요합니다. R. 내부 쉬운 솔루션 "thelatemail"또는 "로버트"의 답변을 참조하십시오
다니엘 후프
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.