一所懸命に手抜きする

デスクワークばかりのスポーツ嫌いで50歳も過ぎ、いよいよ足腰に衰えを感じつつある昨今。

パターンにマッチした部分文字列を返すR標準関数 regmatches()

Rは標準では一致する文字列を一発で抽出できないらしい

 正規表現と言えば grep を思い浮かべるのですが、次の例では、検索パターンに一致する要素番号か、一致する要素そのものを戻り値としています。

grep("太.*?郎",c("山田太郎","鈴木太一郎"))
[1] 1 2
grep("太.*?郎",c("山田太郎","鈴木太一郎"),value=TRUE)
[1] "山田太郎"   "鈴木太一郎"

 上の例では検索パターンに一致した部分文字列「太郎」「太一郎」だけを抽出することはできません。
 stringr というライブラリがあり、文字列を処理する関数が多数用意されています。そこには検索パターンに一致した部分文字列を返す str_extract() や str_match() という関数が用意されています。
 標準では対処できないのでしょうか。

R標準でもあわせ技で部分文字列を抽出できる

検索パターンに一致する部分の開始位置と長さを得る

① regexpr()
 検索パターンに一致する部分の開始位置と長さ等を返す regexpr() を使ってみます。
oSql<-"select b1,b2 from LibA.x where a=( select x1 from LibB.y where v1=2)"
(match<-regexpr("select.?from",oSql))
[1] 1
attr(,"match.length")
[1] 17
attr(,"useBytes")
[1] TRUE
 戻り値として一致した文字列の開始位置等が得られます。  しかし、select b1…の開始位置1はマッチしていますが、select x1の36はマッチしていません。regexprは最初にマッチしたものだけを返します。
注意
match[2]
[1] NA
attr(match,"match.length")
[1] 17
regexpr("select.?from","update tab1 set x where y=12")
[1] -1
attr(,"match.length")
[1] -1
attr(,"useBytes")
[1] TRUE

 一致した文字列の長さなどは一見[2]に格納されるようにも見えますが、そうではないため上の例ではNAとなっています。
 attr(,"match.length")とあるように、要素の属性(attributes)として格納されます。そのため必要ならattr()などで呼び出すことになります。
 またマッチしない場合には、開始位置-1、長さ-1となります。
 ここまでわかれば
 substr(oSql,match,attr(match,"match.length"))
[1] "select b1,b2 from"
 のように抜き出すこともできます。
② gregexpr()
 regexpr が複数マッチに対応していなかったのに対して、gregexpr は複数マッチに対応しています。
(match <- gregexpr("select.*?from",oSql))
[[1]]
[1]  1 36
attr(,"match.length")
[1] 17 14
attr(,"useBytes")
[1] TRUE
 この例では、最初にマッチしたのは開始位置1,長さ17、二つ目にマッチしたのは36文字目から14文字ということになります。

マッチ部分の開始位置・長さ等から文字列を抽出する regmatches()

 regmatches()はgregexpr()やregexpr()で渡される(複数の)抽出開始位置/長さ情報から文字列を抽出します。
 match <- gregexpr("select.*?from",oSql)
(coreSqlText<-regmatches(oSql, match)[[1]])
[1] "select b1,b2 from" "select x1 from"