Skip to content

Commit 32aaf82

Browse files
authored
Add functions: str_to_camel(), str_to_kebab(), str_to_snake() (#577)
Fixes #573
1 parent c91419f commit 32aaf82

File tree

6 files changed

+135
-1
lines changed

6 files changed

+135
-1
lines changed

NAMESPACE

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,11 @@ export(str_starts)
5757
export(str_sub)
5858
export(str_sub_all)
5959
export(str_subset)
60+
export(str_to_camel)
61+
export(str_to_kebab)
6062
export(str_to_lower)
6163
export(str_to_sentence)
64+
export(str_to_snake)
6265
export(str_to_title)
6366
export(str_to_upper)
6467
export(str_trim)

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# stringr (development version)
22

3+
* New `str_to_camel()`, `str_to_snake()`, and `str_to_kebab()` for changing "programming" case (@librill, #573).
34
* All relevant stringr functions now preserve names (@jonovik, #575).
45
* New `vignette("locale-sensitive")` about locale sensitive functions (@kylieainslie, #404)
56
* New `str_ilike()` that follows the conventions of the SQL ILIKE operator (@edward-burn, #543).

R/case.R

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,68 @@ str_to_sentence <- function(string, locale = "en") {
5555
)
5656
copy_names(string, out)
5757
}
58+
59+
60+
#' Convert between different types of programming case
61+
#'
62+
#' @description
63+
#' * `str_to_camel()` converts to camel case, where the first letter of
64+
#' each word is capitalized, with no separation between words. By default
65+
#' the first letter of the first word is not capitalized.
66+
#'
67+
#' * `str_to_kebab()` converts to kebab case, where words are converted to
68+
#' lower case and separated by dashes (`-`).
69+
#'
70+
#' * `str_to_snake()` converts to snake case, where words are converted to
71+
#' lower case and separated by underscores (`_`).
72+
#' @inheritParams str_to_lower
73+
#' @export
74+
#' @param first_upper Logical. Should the first letter be capitalized?
75+
#' @examples
76+
#' str_to_camel("my-variable")
77+
#' str_to_camel("my-variable", first_upper = TRUE)
78+
#'
79+
#' str_to_snake("MyVariable")
80+
#' str_to_kebab("MyVariable")
81+
str_to_camel <- function(string, first_upper = FALSE) {
82+
check_character(string)
83+
check_bool(first_upper)
84+
85+
string <- string |>
86+
to_words() |>
87+
str_to_title() |>
88+
str_remove_all(pattern = "\\s+")
89+
90+
if (!first_upper) {
91+
str_sub(string, 1, 1) <- str_to_lower(str_sub(string, 1, 1))
92+
}
93+
94+
string
95+
}
96+
#' @export
97+
#' @rdname str_to_camel
98+
str_to_snake <- function(string) {
99+
check_character(string)
100+
string |>
101+
to_words() |>
102+
str_replace_all(pattern = "\\s+", replacement = "_")
103+
}
104+
#' @export
105+
#' @rdname str_to_camel
106+
str_to_kebab <- function(string) {
107+
check_character(string)
108+
string |>
109+
to_words() |>
110+
str_replace_all(pattern = "\\s+", replacement = "-")
111+
}
112+
113+
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()
122+
}

_pkgdown.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ reference:
6969
- str_conv
7070
- str_like
7171
- str_replace_na
72+
- str_to_camel
7273
- str_view
7374
- word
7475

man/str_to_camel.Rd

Lines changed: 38 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/test-case.R

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ test_that("to_title creates one capital letter per word", {
1010
})
1111

1212
test_that("to_sentence capitalizes just the first letter", {
13-
x <- "This is a sentence."
1413
expect_identical(str_to_sentence("a Test"), "A test")
1514
})
1615

@@ -20,3 +19,30 @@ test_that("case conversions preserve names", {
2019
expect_equal(names(str_to_upper(x)), names(x))
2120
expect_equal(names(str_to_title(x)), names(x))
2221
})
22+
23+
# programming cases -----------------------------------------------------------
24+
25+
test_that("to_camel can control case of first argument", {
26+
expect_equal(str_to_camel("my_variable"), "myVariable")
27+
expect_equal(str_to_camel("my_variable", first_upper = TRUE), "MyVariable")
28+
})
29+
30+
test_that("to_kebab converts to kebab case", {
31+
expect_equal(str_to_kebab("myVariable"), "my-variable")
32+
expect_equal(str_to_kebab("MyVariable"), "my-variable")
33+
expect_equal(str_to_kebab("MyVariable1"), "my-variable-1")
34+
})
35+
36+
test_that("to_snake converts to snake case", {
37+
expect_equal(str_to_snake("myVariable"), "my_variable")
38+
expect_equal(str_to_snake("MyVariable"), "my_variable")
39+
expect_equal(str_to_snake("MyVariable1"), "my_variable_1")
40+
})
41+
42+
test_that("to_words handles common compound cases", {
43+
expect_equal(to_words("a_b"), "a b")
44+
expect_equal(to_words("a-b"), "a b")
45+
expect_equal(to_words("aB"), "a b")
46+
expect_equal(to_words("a123b"), "a 123 b")
47+
expect_equal(to_words("HTML"), "html")
48+
})

0 commit comments

Comments
 (0)