18369
Rを使った文字列処理に関する質問です．

例えば

```

    "XhogehogeY"
    
```

という文字列があったときに，  
XとYを指定して"hogehoge"を取り出すにはどうしたら良いでしょうか？

教えて下さいお願いします．

追記-----------------------------------------------------------------------------------------  
様々な回答ありがとうございます．  
一旦は解決したのですが，文字列に日本語を含む場合にエラーが出たので改めて質問させてください．

文字列

```

    "pogepoge開始:hogehoge終pogepoge終"
    
```

から"hogehoge"を取り出したいです．  
しかし，

```

    > str_extract("pogepoge開始:hogehoge終pogepoge終","(?<=開始:)(.*?)(?=終)")
    [1] NA
    
```

として切り出そうとするとNAとなるのです．

```

    > str_detect("pogepoge開始:hogehoge終pogepoge終","(?<=開始:)(.*?)(?=終)")
    [1] TRUE
    
```

となっているので確かにマッチしているはずですが．．．

以下のように"始:"としたら切り出せました．

```

    > str_extract("pogepoge開始:hogehoge終pogepoge終","(?<=始:)(.*?)(?=終)")
    [1] "hogehoge"
    
```

しかし"始:"では他の文字列とマッチしてしまうので，"開始:"で切り出したいのです．
CC BY-SA 3.0
2015-11-02T14:31:58.930
18331
2015-11-03T13:34:41.567
2015-11-03T09:42:46.850
13075
13075
question
r
Rの文字列処理： ある文字列で挟まれた部分を取り出したい
これは、正規表現の「肯定的先読み（positive lookahead）」「肯定的後読み（positive
lookbehind）」を使うとうまくマッチさせることができます。  
参考：<http://d.hatena.ne.jp/a_bicky/20100530/1275195072>

例えば、stringrというパッケージだとこの正規表現が使えます。

```

    library(stringr)
    str_extract("XhogehogeY", "(?<=X)(.*)(?=Y)")
    #> [1] "hogehoge"
    
```

（標準の関数でも使えるのかもしれませんが、よくわかりませんでした。すみません...）
CC BY-SA 3.0
2015-11-02T16:26:52.357
18333
2015-11-02T16:26:52.357
2544
18331
answer
同じ
`{stringr}`パッケージの`str_replace()`関数を使った抽出パターンをかんがえてみました。今回の場合、文字列のはじめにX、最後にYということでしたので、それらを空白で置換するという方法です。

```

    library(stringr)
    str_replace_all("XhogehogeY", "^X|Y$", "")
    # [1] "hogehoge"
    
```

コメントのパターンに関しては、つぎのようにすることで対象の文字列を抽出出来ました。

```

    str_replace_all("STARThogehogeENDpogepogeEND", "^START|END.*", "")
    # 文字列の始めのSTART、最初のEND以降を空白で置換
    # [1] "hogehoge"
    
```

外部パッケージを利用しないパターンは、`gsub()`を使って同様につぎのようにします。

```

    gsub("^X|Y$", "", "XhogeY")
    gsub("^START|END.*", "", "STARThogehogeENDpogepogeEND")
    
```
CC BY-SA 3.0
2015-11-02T17:39:37.033
18335
2015-11-02T22:08:25.437
2015-11-02T22:08:25.437
6020
18331
answer
> "STARThogehogeENDpogepogeEND"とあった場合にはどうしたら"hogehoge"を取り出せますか？

既に回答が付いていますが、別の方法で処理してみます。

R の `sub()` や `gsub()` では perl の正規表現(肯定的先読み・後読みなど)を使う事ができます。

```

    > ?sub
    sub(pattern, replacement, x, ignore.case = FALSE, perl = FALSE, ...
    gsub(pattern, replacement, x, ignore.case = FALSE, perl = FALSE, ...
    regexpr(pattern, text, ignore.case = FALSE, perl = FALSE, ...
                     :
    perl: logical. Should perl-compatible regexps be used?
                     :
    
```

ここでは `regexpr()` を使ってみます。

```

    > txt <- "STARThogehogeENDpogepogeEND"
    > m <- regexpr("(?<=START).*?(?=END)", txt, perl=T)
    > substr(txt, m, m + attr(m, "match.length") - 1)
    [1] "hogehoge"
    
```

その他、`strsplit()` を使う方法もあります。

```

    > unlist(strsplit("STARThogehogeENDpogepogeEND", "START|END"))[2]
    [1] "hogehoge"
    
```
CC BY-SA 3.0
2015-11-02T23:35:01.847
18340
2015-11-03T01:46:30.760
2015-11-03T01:46:30.760
18331
answer
`str_detect()` と `str_extract()` をソースコード上で調べてみました。

# stringr 1.0.0 は
[stringi](https://cran.r-project.org/web/packages/stringi/index.html) の
wrapper です。

**str_detect():stringi/src/stri_search_regex_detect.cpp**

```

    StriContainerUTF16 str_cont(str, vectorize_length);
    //   StriContainerUTF8 str_cont(str, vectorize_length); // utext_openUTF8, see below
    StriContainerRegexPattern pattern_cont(pattern, vectorize_length, pattern_flags);
    
```

**str_extract():stringi/src/stri_search_regex_extract.cpp**

```

    StriContainerUTF8 str_cont(str, vectorize_length);
    StriContainerRegexPattern pattern_cont(pattern, vectorize_length, pattern_flags);
    
```

`str_detect()` では処理対象の文字列を格納する変数 `str_cont` の型が `StriContainerUTF8` から
`StriContainerUTF16` に変更されているのですが、`str_extract()` ではそのままです。

近い将来、`str_extract()` も `StriContainerUTF16` に変更されるかも知れません(pull request
を出す方が良いのかも知れませんが…)。

stringr を使わない方法でも良いのであれば、前の回答に書いておいた方法を使ってみてはいかがでしょうか。

```

    > unlist(strsplit("pogepoge開始:hogehoge終pogepoge終", "開始:|終"))[2]
    [1] "hogehoge"
    
```
CC BY-SA 3.0
2015-11-03T13:34:41.567
18369
2015-11-03T13:34:41.567
18331
answer