From b072cf500a1e97f59446d98b59888f2292f9eb4f Mon Sep 17 00:00:00 2001 From: arnaudgallou Date: Thu, 25 Sep 2025 23:21:01 +0200 Subject: [PATCH] Refine string case conversion helpers --- R/case.R | 34 +++++++++++++++++++--------------- tests/testthat/test-case.R | 14 ++++++++++++-- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/R/case.R b/R/case.R index 9c882010..fc60bc3f 100644 --- a/R/case.R +++ b/R/case.R @@ -85,7 +85,7 @@ str_to_camel <- function(string, first_upper = FALSE) { string <- string |> to_words() |> str_to_title() |> - str_remove_all(pattern = "\\s+") + str_remove_all(pattern = fixed(" ")) if (!first_upper) { str_sub(string, 1, 1) <- str_to_lower(str_sub(string, 1, 1)) @@ -97,26 +97,30 @@ str_to_camel <- function(string, first_upper = FALSE) { #' @rdname str_to_camel str_to_snake <- function(string) { check_character(string) - string |> - to_words() |> - str_replace_all(pattern = "\\s+", replacement = "_") + to_separated_case(string, sep = "_") } #' @export #' @rdname str_to_camel str_to_kebab <- function(string) { check_character(string) - string |> - to_words() |> - str_replace_all(pattern = "\\s+", replacement = "-") + to_separated_case(string, sep = "-") +} + +to_separated_case <- function(string, sep) { + out <- to_words(string) + str_replace_all(out, fixed(" "), sep) } to_words <- function(string) { - string |> - str_replace_all("([a-z])([A-Z])", "\\1 \\2") |> - str_replace_all("([a-zA-Z])([0-9])", "\\1 \\2") |> - str_replace_all("([0-9])([a-zA-Z])", "\\1 \\2") |> - str_replace_all("([A-Z]+)([A-Z][a-z])", "\\1 \\2") |> - str_to_lower() |> - str_replace_all(pattern = "[:punct:]", replacement = " ") |> - str_trim() + pattern <- paste( + "[^\\p{L}\\p{N}]+", + "(?<=\\p{Ll})(?=\\p{Lu})", + "(?<=\\p{L})(?=\\p{N})", + "(?<=\\p{N})(?=\\p{L})", + "(?<=\\p{Lu})(?=\\p{Lu}\\p{Ll})", + sep = "|" + ) + out <- str_replace_all(string, pattern, " ") + out <- str_to_lower(out) + str_trim(out) } diff --git a/tests/testthat/test-case.R b/tests/testthat/test-case.R index 9e29321c..cdc733e0 100644 --- a/tests/testthat/test-case.R +++ b/tests/testthat/test-case.R @@ -24,19 +24,29 @@ test_that("case conversions preserve names", { test_that("to_camel can control case of first argument", { expect_equal(str_to_camel("my_variable"), "myVariable") + expect_equal(str_to_camel("my$variable"), "myVariable") + expect_equal(str_to_camel(" my variable "), "myVariable") expect_equal(str_to_camel("my_variable", first_upper = TRUE), "MyVariable") }) test_that("to_kebab converts to kebab case", { expect_equal(str_to_kebab("myVariable"), "my-variable") expect_equal(str_to_kebab("MyVariable"), "my-variable") - expect_equal(str_to_kebab("MyVariable1"), "my-variable-1") + expect_equal(str_to_kebab("1MyVariable1"), "1-my-variable-1") + expect_equal(str_to_kebab("My$Variable"), "my-variable") + expect_equal(str_to_kebab(" My Variable "), "my-variable") + expect_equal(str_to_kebab("testABCTest"), "test-abc-test") + expect_equal(str_to_kebab("IlÉtaitUneFois"), "il-était-une-fois") }) test_that("to_snake converts to snake case", { expect_equal(str_to_snake("myVariable"), "my_variable") expect_equal(str_to_snake("MyVariable"), "my_variable") - expect_equal(str_to_snake("MyVariable1"), "my_variable_1") + expect_equal(str_to_snake("1MyVariable1"), "1_my_variable_1") + expect_equal(str_to_snake("My$Variable"), "my_variable") + expect_equal(str_to_snake(" My Variable "), "my_variable") + expect_equal(str_to_snake("testABCTest"), "test_abc_test") + expect_equal(str_to_snake("IlÉtaitUneFois"), "il_était_une_fois") }) test_that("to_words handles common compound cases", {