抽出による文字列分離(1.5).R

要約

・str_extract_all()とstr_subset()の挙動の違い
・「特定の文字列を抽出」or「特定の文字列を含む要素を抽出」

別の抽出方法:str_subset()

 ちょっと本題からは逸れるが、stringr::にはstr_subset()という関数があって、これも特定の文字列を抽出してくれる関数だ。
 一方、str_extract_all()も特定の文字列を抽出してくれる関数だ。
 こうやって表現してみると同じじゃんと思えるのだけれど、同じパッケージに含まれていて関数名が異なるので、当然ながら挙動が異なる。なので、前回同様のマルチアンサー形式のFIが格納されたベクタを与えて、出力の違いを確認してみた。

正規表現を使った抽出のされ方比較

------
str_extract_all()の場合
------
> ary.FI %>%
   str_extract_all("[A-H]\\d{2}[A-Z]\\d{1,4}/\\d{2,5}(,\\d{1,3})?(@[A-Z])?") %>%
   head(3)
[[1]]
[1] "G06Q20/06"
[[2]]
[1] "E04F13/10@A"     "E04F13/08,102@A" "E04F15/04@E"    
[[3]]
[1] "A41D13/00"  "A41D3/00@Z"

------
str_subset()の場合
------
> ary.FI %>%
   str_subset("[A-H]\\d{2}[A-Z]\\d{1,4}/\\d{2,5}(,\\d{1,3})?(@[A-Z])?") %>%
   head(3)
[1] "G06Q20/06"                               "E04F13/10@A,E04F13/08,102@A,E04F15/04@E"
[3] "A41D13/00,A41D3/00@Z

 大きく異なるのは、出力がリスト型かベクタ型だ。いっそstr_subset()の方がベクタで出力されてくれる分だけ使いやすいように見える。もちろん、str_extract_all()と違ってセパレータがコンマのままなのだけど。
 ここで、正規表現を少し変えてみる。例えば、展開記号や分冊識別記号が不要でIPC記号だけが必要な場合を想定する。

------
str_extract_all()の場合
------
> ary.FI %>% str_extract_all("[A-H]\\d{2}[A-Z]\\d{1,4}/\\d{2,5}") %>% head(3)
[[1]]
[1] "G06Q20/06"
[[2]]
[1] "E04F13/10" "E04F13/08" "E04F15/04"
[[3]]
[1] "A41D13/00" "A41D3/00"

------
str_subset()の場合
------
> ary.FI %>% str_subset("[A-H]\\d{2}[A-Z]\\d{1,4}/\\d{2,5}") %>% head(3)
[1] "G06Q20/06"                               "E04F13/10@A,E04F13/08,102@A,E04F15/04@E"
[3] "A41D13/00,A41D3/00@Z"  

> ary.FI %>% str_subset("@[A-Z]") %>% head(3)
[1] "E04F13/10@A,E04F13/08,102@A,E04F15/04@E"                     
[2] "A41D13/00,A41D3/00@Z"                                        
[3] "B60L53/80,E03D9/08@B,B60K1/04@A,B62D63/02,B60S5/06,B60L50/60"

 一目瞭然で、str_extract_all()は狙った挙動をしてくれているが、str_subset()は出力が先ほどと変化していない。というのも、str_subset()は、特定の文字列を抽出してくれるが、正確には「特定の文字列を含む要素を抽出」してくれるものだからだ。
 もっと分かりやすいのがもうひとつの"@[A-Z]"で抽出したパターンだ。
 マルチアンサーにされたFIのひとつずつについて判断しているわけではなく、要素を1つの文字列とみなした上でそこに"@[A-Z]"が一か所でも入っていると判断すれば、その要素全体を返しているということが分かる。

 最初に用いた正規表現では、FI全体がマッチするようにしていたために、結果が類似するように見えていただけであって、FIの一部分であるIPC記号だけをマッチするようにしていた後半の例では、結果が異なったということだ。
 そういうわけで、後半の例として挙げたFIの部分抽出(i.e. 1要素内から特定パターンにマッチする複数の文字列を抽出)という目的であれば、やはりstr_extract_all()を使う必要があることが分かった。

 str_subset()はsubsetという名がまさしく体を表していて、あくまでもベクタや行列から要素単位で抽出してサブセットを作るためのもの、ということなんだろう。

今日はここまで。

 

この記事が気に入ったらサポートをしてみませんか?