Вот функциональный подход к построению логики c, необходимой для анализа строк, с которыми вы можете столкнуться. Я полагаю, что это основано на размышлениях о том, как мы анализируем эти строки, когда мы их читаем, и на попытках имитировать это. последний разделитель десятичный или нет. Если бы мы могли как-то пометить строки как имеющие десятичную часть, тогда было бы легко разобрать строки.
Следующий метод включает разделение строк символов в точках и запятых и попытку пометить их как имеющие терминал десятичный или нет. Разделенные строки будут храниться в виде списка строковых векторов, причем каждый вектор состоит из «кусков» цифр между разделителями.
Сначала мы напишем две вспомогательные функции для создания окончательных чисел из строки векторы, если мы правильно пометили их как имеющие конечную десятичную часть или нет:
last_element_is_decimal <- function(x)
{
as.numeric(paste0(paste(x[-length(x)], collapse = ""), ".", x[length(x)]))
}
last_element_is_whole <- function(x)
{
as.numeric(paste0(x, collapse = ""))
}
Будет легко решить, что делать в случае отсутствия разделителей, поскольку мы предполагаем, что это просто целые числа. Точно так же легко видеть, что любые числа, содержащие как запятую, так и остановку (в любом порядке), должны иметь конечный десятичный компонент.
Однако менее очевидно, что делать, когда есть только один разделитель; в этих случаях мы должны использовать длину фрагментов di git, чтобы решить. Если какой-либо фрагмент длиннее трех цифр, разделитель тысяч не используется, а наличие разделителя указывает на наличие десятичного компонента. Если блок терминала содержит только две цифры, то мы должны иметь десятичную дробь. Во всех других случаях мы принимаем целое число.
Это говорит о том же в коде:
decide_last_element <- function(x)
{
if(max(nchar(x)) > 3)
return(last_element_is_decimal(x))
if(nchar(x[length(x)]) < 3)
return(last_element_is_decimal(x))
return(last_element_is_whole(x))
}
Теперь мы можем написать нашу основную функцию. Он принимает наши строки в качестве входных данных и классифицирует каждую строку на наличие двух типов разделителя, одного типа разделителя или без разделителя. Затем мы можем применить вышеупомянутые функции, используя lapply
соответственно.
parse_money <- function(money_strings)
{
any_comma <- grepl(",", money_strings)
any_point <- grepl("[.]", money_strings)
both <- any_comma & any_point
neither <- !any_comma & !any_point
single <- (any_comma & !any_point) | (any_point & !any_comma)
digit_groups <- strsplit(money_strings, "[.]|,")
values <- rep(0, length(money_strings))
values[neither] <- as.numeric(money_strings[neither])
values[both] <- sapply(digit_groups[both], last_element_is_decimal)
values[single] <- sapply(digit_groups[single], decide_last_element)
return(format(round(values, 2), nsmall = 2))
}
Так что теперь мы можем просто сделать
parse_money(df$Y2019)
#> [1] " 17530000.03" " 28000000.05" " 256000.23" " 23000.00" "256355855.00"
#> [6] " 2565467.57" " 225453.13"
Примечание. У меня есть выходные данные в виде строк, так что неточности округления в консоли вывод не приписывается ошибкам в коде.