stringr::str_replace()には置換文字列だけではなく関数も指定できる

stringrパッケージのstr_replace()/str_replace_all()は、バージョン1.2.0からreplacement引数に関数を取ることができます。

これを使うと、「指定した正規表現にマッチした部分だけ大文字にする」みたいなことが簡単にできます。

たとえば、1年前くらいにこれをやろうとすると、以下のように

  1. 正規表現にマッチするインデックスを取得
  2. そのインデックスで文字列を抜き出してtoupper()で大文字に変換
  3. 元のインデックスの場所を置換

というステップを踏む必要がありました。

library(stringr)

hoxo <- "This is hoxo_m"
pattern <- "(hoxo)_(m|w|b|x)"

m <- str_locate(hoxo, pattern)
m
#>      start end
#> [1,]     9  14

# 抜き出す範囲の確認
str_sub(hoxo, start = m[1], end = m[2])
#> [1] "hoxo_m"

# 抜き出した部分を置換
str_sub(hoxo, start = m[1], end = m[2]) <- toupper(str_sub(hoxo, start = m[1], end = m[2]))

hoxo
#> [1] "This is HOXO_M"

(出典:メモ:stringrのstr_locate_allとstr_subを組み合わせて文字列置換 - Technically, technophobic. *1

これがいまや、以下のように一瞬で書けます。

hoxo <- "This is hoxo_m"
pattern <- "(hoxo)_(m|w|b|x)"
str_replace(hoxo, pattern, toupper)
#> [1] "This is HOXO_M"

もうちょっと複雑な例としては、?str_replaceに面白い例が載っているのでそれをそのまま以下にコピペします。 文字列中に出てくる色の名前をRGB値に置き換えるというものです。 色の名前は1つの文字列中に複数回出てくるので、今回はstr_replace()ではなくstr_replace_all()になっています。

colours <- str_c("\\b", colors(), "\\b", collapse="|")
col2hex <- function(col) {
  rgb <- col2rgb(col)
  rgb(rgb["red", ], rgb["green", ], rgb["blue", ], max = 255)
}

x <- c(
  "Roses are red, violets are blue",
  "My favourite colour is green"
)
str_replace_all(x, colours, col2hex)
#> [1] "Roses are #FF0000, violets are #0000FF"
#> [2] "My favourite colour is #00FF00"

便利!

余談

ついでにちょっと貢献アピールをしておくと、前バージョンではメモ:stringrのstr_locate_allとstr_subを組み合わせて文字列置換 - Technically, technophobic.の最後の例にあるように、正規表現がマッチしないとNAになってしまうという問題があったのを、stringiとstringrにPRを送って直しました。 興味ある方は以下のissueをご参照ください:

*1:注:この記事を書いたときにすでにstringr 1.2.0はリリースされてたけどこの機能の存在に気付いてなかった...