正規表現の一致を抽出する


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

既存の正規表現すべてをラップする新しいストリンガーパッケージを使用して、一貫した構文で動作し、不足しているものをいくつか追加します。

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「参照」で具体的に参照されているヘルプファイル:

「regmatches」、「regexpr」、「gregexpr」、および「regexec」の結果に基づいて一致した部分文字列を抽出します。

したがって、これは機能し、かなり簡単です。

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


15

PERL正規表現の遅延マッチングを使用できます。

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

この場合、数字以外を置換しようとすると、エラーが発生します。


4
あなたは少し醜いを使用して喜んでいる場合は、 "([0-9] +)* [^ 0-9] *。" PERLを必要としないでください
Jyotirmoyバッタチャリヤ

5

1つの方法は次のとおりです。

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は、オブジェクトが(配列ではなく)文字列のベクトルであり、修飾子が(マージンではなく)正規表現であることを除いて、argsがオブジェクト、修飾子、および関数であるという点で、applyに似ています。

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

これは、xの各コンポーネントの1つ以上の数字(\ d +)に一致し、各一致をas.numericに通すことを示しています。コンポーネントがxの各コンポーネントの一致のベクトルであるリストを返します。出力を見ると、xの最初のコンポーネントには13である1つの一致があり、xの2番目のコンポーネントには12と34の2つの一致があります。詳細については、http://gsubfn.googlecode.comを参照してください。


1

別の解決策:

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

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.