Skip to content

Commit 1bedafe

Browse files
authored
Refine string case conversion helpers (#593)
Fixes #592
1 parent 23c7d5b commit 1bedafe

File tree

3 files changed

+37
-18
lines changed

3 files changed

+37
-18
lines changed

NEWS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
* New `vignette("locale-sensitive")` about locale sensitive functions (@kylieainslie, #404)
1212
* New `str_ilike()` that follows the conventions of the SQL ILIKE operator (@edward-burn, #543).
13-
* New `str_to_camel()`, `str_to_snake()`, and `str_to_kebab()` for changing "programming" case (@librill, #573).
13+
* New `str_to_camel()`, `str_to_snake()`, and `str_to_kebab()` for changing "programming" case (@librill, #573 + @arnaudgallou, #593).
1414

1515
## Minor bug fies and improvements
1616

R/case.R

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ str_to_camel <- function(string, first_upper = FALSE) {
8585
string <- string |>
8686
to_words() |>
8787
str_to_title() |>
88-
str_remove_all(pattern = "\\s+")
88+
str_remove_all(pattern = fixed(" "))
8989

9090
if (!first_upper) {
9191
str_sub(string, 1, 1) <- str_to_lower(str_sub(string, 1, 1))
@@ -97,26 +97,35 @@ str_to_camel <- function(string, first_upper = FALSE) {
9797
#' @rdname str_to_camel
9898
str_to_snake <- function(string) {
9999
check_character(string)
100-
string |>
101-
to_words() |>
102-
str_replace_all(pattern = "\\s+", replacement = "_")
100+
to_separated_case(string, sep = "_")
103101
}
104102
#' @export
105103
#' @rdname str_to_camel
106104
str_to_kebab <- function(string) {
107105
check_character(string)
108-
string |>
109-
to_words() |>
110-
str_replace_all(pattern = "\\s+", replacement = "-")
106+
to_separated_case(string, sep = "-")
107+
}
108+
109+
to_separated_case <- function(string, sep) {
110+
out <- to_words(string)
111+
str_replace_all(out, fixed(" "), sep)
111112
}
112113

113114
to_words <- function(string) {
114-
string |>
115-
str_replace_all("([a-z])([A-Z])", "\\1 \\2") |>
116-
str_replace_all("([a-zA-Z])([0-9])", "\\1 \\2") |>
117-
str_replace_all("([0-9])([a-zA-Z])", "\\1 \\2") |>
118-
str_replace_all("([A-Z]+)([A-Z][a-z])", "\\1 \\2") |>
119-
str_to_lower() |>
120-
str_replace_all(pattern = "[:punct:]", replacement = " ") |>
121-
str_trim()
115+
breakpoints <- paste(
116+
# non-word characters
117+
"[^\\p{L}\\p{N}]+",
118+
# lowercase followed by uppercase
119+
"(?<=\\p{Ll})(?=\\p{Lu})",
120+
# letter followed by number
121+
"(?<=\\p{L})(?=\\p{N})",
122+
# number followed by letter
123+
"(?<=\\p{N})(?=\\p{L})",
124+
# uppercase followed uppercase then lowercase (i.e. end of acronym)
125+
"(?<=\\p{Lu})(?=\\p{Lu}\\p{Ll})",
126+
sep = "|"
127+
)
128+
out <- str_replace_all(string, breakpoints, " ")
129+
out <- str_to_lower(out)
130+
str_trim(out)
122131
}

tests/testthat/test-case.R

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,29 @@ test_that("case conversions preserve names", {
2424

2525
test_that("to_camel can control case of first argument", {
2626
expect_equal(str_to_camel("my_variable"), "myVariable")
27+
expect_equal(str_to_camel("my$variable"), "myVariable")
28+
expect_equal(str_to_camel(" my variable "), "myVariable")
2729
expect_equal(str_to_camel("my_variable", first_upper = TRUE), "MyVariable")
2830
})
2931

3032
test_that("to_kebab converts to kebab case", {
3133
expect_equal(str_to_kebab("myVariable"), "my-variable")
3234
expect_equal(str_to_kebab("MyVariable"), "my-variable")
33-
expect_equal(str_to_kebab("MyVariable1"), "my-variable-1")
35+
expect_equal(str_to_kebab("1MyVariable1"), "1-my-variable-1")
36+
expect_equal(str_to_kebab("My$Variable"), "my-variable")
37+
expect_equal(str_to_kebab(" My Variable "), "my-variable")
38+
expect_equal(str_to_kebab("testABCTest"), "test-abc-test")
39+
expect_equal(str_to_kebab("IlÉtaitUneFois"), "il-était-une-fois")
3440
})
3541

3642
test_that("to_snake converts to snake case", {
3743
expect_equal(str_to_snake("myVariable"), "my_variable")
3844
expect_equal(str_to_snake("MyVariable"), "my_variable")
39-
expect_equal(str_to_snake("MyVariable1"), "my_variable_1")
45+
expect_equal(str_to_snake("1MyVariable1"), "1_my_variable_1")
46+
expect_equal(str_to_snake("My$Variable"), "my_variable")
47+
expect_equal(str_to_snake(" My Variable "), "my_variable")
48+
expect_equal(str_to_snake("testABCTest"), "test_abc_test")
49+
expect_equal(str_to_snake("IlÉtaitUneFois"), "il_était_une_fois")
4050
})
4151

4252
test_that("to_words handles common compound cases", {

0 commit comments

Comments
 (0)