diff --git a/NAMESPACE b/NAMESPACE index da483518..f4cb0098 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -12,11 +12,13 @@ S3method(type,stringr_fixed) S3method(type,stringr_regex) export("%>%") export("str_sub<-") +export(StrToPascal) export(boundary) export(coll) export(fixed) export(invert_match) export(regex) +export(strToCamel) export(str_c) export(str_conv) export(str_count) @@ -57,8 +59,12 @@ export(str_starts) export(str_sub) export(str_sub_all) export(str_subset) +export(str_to_camel) +export(str_to_kebab) export(str_to_lower) +export(str_to_pascal) export(str_to_sentence) +export(str_to_snake) export(str_to_title) export(str_to_upper) export(str_trim) diff --git a/R/case.R b/R/case.R index c17b9762..f08be074 100644 --- a/R/case.R +++ b/R/case.R @@ -1,4 +1,5 @@ -#' Convert string to upper case, lower case, title case, or sentence case +#' Convert string to upper case, lower case, title case, sentence case, pascal +#' case, camel case, kebab case, or snake case #' #' * `str_to_upper()` converts to upper case. #' * `str_to_lower()` converts to lower case. @@ -6,9 +7,22 @@ #' each word is capitalized. #' * `str_to_sentence()` convert to sentence case, where only the first letter #' of sentence is capitalized. +#' * `str_to_pascal()` converts to pascal case, where only the first letter of +#' each word is capitalized, with no separation between +#' words. +#' * `str_to_pascal()` and `StrToPascal()` are synonyms +#' * `str_to_camel()` converts to camel case, where only the first letter of +#' each word after the first word is capitalized, with no separation between +#' words. +#' * `str_to_camel()` and `strToCamel()` are synonyms +#' * `str_to_kebab()` converts to kebab case, where words are converted to +#' lower case and separated by dashes (`-`). +#' * `str_to_snake()` converts to snake case, where words are converted to +#' lower case and separated by underscores (`_`). #' #' @inheritParams str_detect #' @inheritParams coll +#' @param separator string. For snake case, can change the `_` #' @return A character vector the same length as `string`. #' @examples #' dog <- "The quick brown dog" @@ -16,6 +30,12 @@ #' str_to_lower(dog) #' str_to_title(dog) #' str_to_sentence("the quick brown dog") +#' str_to_pascal(dog) +#' StrToPascal(dog) +#' str_to_camel(dog) +#' strToCamel(dog) +#' str_to_kebab(dog) +#' str_to_snake(dog) #' #' # Locale matters! #' str_to_upper("i") # English @@ -54,3 +74,50 @@ str_to_sentence <- function(string, locale = "en") { opts_brkiter = stri_opts_brkiter(type = "sentence", locale = locale) ) } +#' @export +#' @rdname case +str_to_pascal <- function(string, locale = "en") { + stopifnot(is.character(string)) + string <- string |> + str_replace_all("([a-z])([A-Z])", "\\1 \\2") |> + str_replace_all("([0-9])([a-zA-Z])", "\\1 \\2") |> + str_replace_all("([A-Z]+)([A-Z][a-z])", "\\1 \\2") |> + str_replace_all(pattern = "[:punct:]", replace = " ") |> + str_to_title(locale = locale) |> + str_remove_all(pattern = "\\s+") + return(string) +} +#' @export +#' @rdname case +StrToPascal <- str_to_pascal +#' @export +#' @rdname case +str_to_camel <- function(string, locale = "en") { + string <- str_to_pascal(string, locale = locale) + string <- str_replace(string, pattern = "^.", replace = str_to_lower(str_sub(string, 1, 1))) + return(string) +} +#' @export +#' @rdname case +strToCamel <- str_to_camel +#' @export +#' @rdname case +str_to_snake <- function(string, separator = "_", locale = "en") { + stopifnot(is.character(string)) + 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(locale = locale) |> + str_replace_all(pattern = "[:punct:]", replace = " ") |> + str_trim() |> + str_replace_all(pattern = "\\s+", replace = separator) + return(string) +} +#' @export +#' @rdname case +str_to_kebab <- function(string, locale = "en") { + string <- str_to_snake(string, separator = "-", locale = locale) + return(string) +} diff --git a/man/case.Rd b/man/case.Rd index b557e192..fc00e418 100644 --- a/man/case.Rd +++ b/man/case.Rd @@ -6,7 +6,14 @@ \alias{str_to_lower} \alias{str_to_title} \alias{str_to_sentence} -\title{Convert string to upper case, lower case, title case, or sentence case} +\alias{str_to_pascal} +\alias{StrToPascal} +\alias{str_to_camel} +\alias{strToCamel} +\alias{str_to_snake} +\alias{str_to_kebab} +\title{Convert string to upper case, lower case, title case, sentence case, pascal +case, camel case, kebab case, or snake case} \usage{ str_to_upper(string, locale = "en") @@ -15,6 +22,18 @@ str_to_lower(string, locale = "en") str_to_title(string, locale = "en") str_to_sentence(string, locale = "en") + +str_to_pascal(string, locale = "en") + +StrToPascal(string, locale = "en") + +str_to_camel(string, locale = "en") + +strToCamel(string, locale = "en") + +str_to_snake(string, separator = "_", locale = "en") + +str_to_kebab(string, locale = "en") } \arguments{ \item{string}{Input vector. Either a character vector, or something @@ -24,6 +43,8 @@ coercible to one.} \code{\link[stringi:stri_locale_list]{stringi::stri_locale_list()}} for all possible options. Defaults to "en" (English) to ensure that default behaviour is consistent across platforms.} + +\item{separator}{string. For snake case, can change the \verb{_}} } \value{ A character vector the same length as \code{string}. @@ -36,6 +57,18 @@ A character vector the same length as \code{string}. each word is capitalized. \item \code{str_to_sentence()} convert to sentence case, where only the first letter of sentence is capitalized. +\item \code{str_to_pascal()} converts to pascal case, where only the first letter of +each word is capitalized, with no separation between +words. +\item \code{str_to_pascal()} and \code{StrToPascal()} are synonyms +\item \code{str_to_camel()} converts to camel case, where only the first letter of +each word after the first word is capitalized, with no separation between +words. +\item \code{str_to_camel()} and \code{strToCamel()} are synonyms +\item \code{str_to_kebab()} converts to kebab case, where words are converted to +lower case and separated by dashes (\code{-}). +\item \code{str_to_snake()} converts to snake case, where words are converted to +lower case and separated by underscores (\verb{_}). } } \examples{ @@ -44,6 +77,12 @@ str_to_upper(dog) str_to_lower(dog) str_to_title(dog) str_to_sentence("the quick brown dog") +str_to_pascal(dog) +StrToPascal(dog) +str_to_camel(dog) +strToCamel(dog) +str_to_kebab(dog) +str_to_snake(dog) # Locale matters! str_to_upper("i") # English diff --git a/tests/testthat/test-case.R b/tests/testthat/test-case.R index b90cd2ef..0d9bcb4f 100644 --- a/tests/testthat/test-case.R +++ b/tests/testthat/test-case.R @@ -10,6 +10,25 @@ test_that("to_title creates one capital letter per word", { }) test_that("to_sentence capitalizes just the first letter", { - x <- "This is a sentence." expect_identical(str_to_sentence("a Test"), "A test") }) + +test_that("to_pascal converts to pascal case", { + expect_identical(str_to_pascal("This is a sentence."), "ThisIsASentence") +}) + +test_that("to_camel converts to camel casee", { + expect_identical(str_to_camel("This is a sentence."), "thisIsASentence") +}) + +test_that("to_kebab converts to kebab case", { + expect_identical(str_to_kebab("This is a sentence."), "this-is-a-sentence") +}) + +test_that("to_snake converts to snake case", { + expect_identical(str_to_snake("This is a sentence."), "this_is_a_sentence") +}) + +test_that("to_snake converts to snake case", { + expect_identical(str_to_snake("This is a sentence.", separator = "!"), "this!is!a!sentence") +}) diff --git a/vignettes/stringr.Rmd b/vignettes/stringr.Rmd index d234ded3..549ef4f9 100644 --- a/vignettes/stringr.Rmd +++ b/vignettes/stringr.Rmd @@ -129,6 +129,7 @@ A handful of stringr functions are locale-sensitive: they will perform different x <- "I like horses." str_to_upper(x) str_to_title(x) +str_to_snake(x) # case transformation for programming str_to_lower(x) # Turkish has two sorts of i: with and without the dot