The separate function is superseded by separate_wider_position() and separate_wider_delim().
For your case, you can use separate_wider_position() from the tidyr package. The widths_vec controls the name and width of the newly created columns, and you want a width of 1.
EDIT: my previous separate() doesn't give the correct output, now deleted, please use separate_wider_position().
library(tidyverse)
x <- c(1,2,12,31,123,2341)
df <- data.frame(x)
widths_vec <- setNames(rep(1, max(nchar(x))), letters[1:max(nchar(x))])
df %>% separate_wider_position(cols = x, widths = widths_vec, too_few = "align_start", cols_remove = F)
# A tibble: 6 × 5
a b c d x
<chr> <chr> <chr> <chr> <dbl>
1 1 NA NA NA 1
2 2 NA NA NA 2
3 1 2 NA NA 12
4 3 1 NA NA 31
5 1 2 3 NA 123
6 2 3 4 1 2341