R の substr と substring は、どの引数がベクトル化されているかで異なる。前者は第一引数(対象の text) 、後者は位置(first, last 引数)がベクトル化されている。両方をベクトル化したものはないので、注意が必要だ。
> substr('ABCDEFG', 1:4, 4:7) [1] "ABCD" > substring('ABCDEFG', 1:4, 4:7) [1] "ABCD" "BCDE" "CDEF" "DEFG" > substr(c('ABCDEFG', '1234567'), 1, 4) [1] "ABCD" "1234" > substring(c('ABCDEFG', '1234567'), 1, 4) [1] "ABCD" "1234" # 両方をベクトル化しようとすると、おかしなことに! > substr(c('ABCDEFG', '1234567'), 1:4, 4:7) [1] "ABCD" "2345" > substring(c('ABCDEFG', '1234567'), 1:4, 4:7) [1] "ABCD" "2345" "CDEF" "4567"
ところで、substring の実装を見ると、
> substring function (text, first, last = 1000000L) { if (!is.character(text)) text <- as.character(text) n <- max(lt <- length(text), length(first), length(last)) if (lt && lt < n) text <- rep_len(text, length.out = n) .Internal(substr(text, as.integer(first), as.integer(last))) }
となっていて、内部的には substr を呼び出している。すなわち、text 引数を明示的にベクトル化しておけば、substr も位置をベクトル化できるということである。実際、
> substr('ABCDEFG', 1:4, 4:7) [1] "ABCD" > substr(rep('ABCDEFG', 4), 1:4, 4:7) [1] "ABCD" "BCDE" "CDEF" "DEFG"
となる。
しかしこの実装、文字列がゲノム配列などですごく長いときに、恐ろしく無駄な気がするのだが…… 普通に引数をリサイクルする仕様にしてほしかったな。