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"