You can use a combination of tidyverse, reshape and stringr to get the desired result. separate_rows from tidyverse separates rows, i.e., breaks a row to multiple rows and similarly, separate from reshape forks new columns from the old ones. Since there are two closing brackets in the end with out any output we get two rows with NA values and warning, so we remove the NA values using na.omit(). If you want to select only first and last column, you can use select from dplyr
library(dplyr)
library(tidyverse) # for separate_rows
library(reshape) #for separate to separate columns
library(stringr) # for string manipulations i.e. remove tralining and leading white spaces
# data frame from your data
df_1 <- data.frame(col1='[[131 22 2 "male"] [123 23 2 "female"] [232 21 2 "male"] [132 21 2 "male"]]' , stringsAsFactors = FALSE)
# separate rows on closing brackets
df_2 <- df_1 %>% separate_rows(col1, sep = "]")
# remove other remaining brackets and leading and triling white space
df_2["col1"] <- gsub("\\[|\\]", "", str_trim(df_2[["col1"]], "both") )
# separate the single column data to multiple columns
df_2 %>% separate(col = col1, into = c("ID", "Num1","Num2", "Gender"), sep = " ") %>% na.omit() %>% select(1,4)
The output will be
A tibble: 4 × 2
ID Gender
<chr> <chr>
1 131 "male"
2 123 "female"
3 232 "male"
4 132 "male"