Мы можем использовать регулярные выражения
sub("(?<=[0-9])(?=[A-Z])", "_", x, perl = TRUE)
#[1] "A12_SITE_1234_J_vvv.csv" "A12_SITA_1234_J_vvv.csv"
#[3] "A12_SITE_1678_H_vvv.csv" "A12_SITE_145_C_vvv.csv"
Или с группами захвата ((..)
), чтобы захватить шаблон как группу, а затем при замене использовать обратную ссылку (\\1, \\2
) захваченной группы
sub("([0-9])([A-Z])", "\\1_\\2", x, perl = TRUE)
В коде OP шаблон .*
(любые символы), за которым следуют число ([0-9]
) и алфавит ([A-Z]
), не захватывается, поэтому он теряется при замене. Кроме того, при замене, если мы используем [0-9]
, он будет восприниматься как буквенные строки