Skip to content

Commit

Permalink
str_ilike tidyverse#543
Browse files Browse the repository at this point in the history
- add str_ilike function
- remove ignore_case argument from str_like
- add tests of case sensitivity for both
  • Loading branch information
edward-burn committed Apr 10, 2024
1 parent a64b8f1 commit 4e44ac0
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 14 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ Config/testthat/edition: 3
Encoding: UTF-8
LazyData: true
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.3
RoxygenNote: 7.3.1
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export(str_flatten)
export(str_flatten_comma)
export(str_glue)
export(str_glue_data)
export(str_ilike)
export(str_interp)
export(str_length)
export(str_like)
Expand Down
46 changes: 39 additions & 7 deletions R/detect.R
Original file line number Diff line number Diff line change
Expand Up @@ -119,30 +119,62 @@ str_ends <- function(string, pattern, negate = FALSE) {
#' * `_` matches a single character (like `.`).
#' * `%` matches any number of characters (like `.*`).
#' * `\%` and `\_` match literal `%` and `_`.
#' * The match is case insensitive by default.
#' * The match is case sensitive.
#'
#' @inheritParams str_detect
#' @param pattern A character vector containing a SQL "like" pattern.
#' See above for details.
#' @param ignore_case Ignore case of matches? Defaults to `TRUE` to match
#' the SQL `LIKE` operator.
#' @return A logical vector the same length as `string`.
#' @export
#' @examples
#' fruit <- c("apple", "banana", "pear", "pineapple")
#' str_like(fruit, "app")
#' str_like(fruit, "app%")
#' str_like(fruit, "APP%")
#' str_like(fruit, "ba_ana")
#' str_like(fruit, "%APPLE")
str_like <- function(string, pattern, ignore_case = TRUE) {
#' str_like(fruit, "%apple")
str_like <- function(string, pattern) {
check_lengths(string, pattern)
check_character(pattern)
if (inherits(pattern, "stringr_pattern")) {
cli::cli_abort("{.arg pattern} must be a plain string, not a stringr modifier.")
}
check_bool(ignore_case)

pattern <- regex(like_to_regex(pattern), ignore_case = ignore_case)
pattern <- regex(like_to_regex(pattern), ignore_case = FALSE)
stri_detect_regex(string, pattern, opts_regex = opts(pattern))
}

#' Detect a pattern in the same way as `SQL`'s `ILIKE` operator
#'
#' @description
#' `str_ilike()` follows the conventions of the SQL `ILIKE` operator:
#'
#' * Must match the entire string.
#' * `_` matches a single character (like `.`).
#' * `%` matches any number of characters (like `.*`).
#' * `\%` and `\_` match literal `%` and `_`.
#' * The match is case insensitive.
#'
#' @inheritParams str_detect
#' @param pattern A character vector containing a SQL "like" pattern.
#' See above for details.
#' @return A logical vector the same length as `string`.
#' @export
#' @examples
#' fruit <- c("apple", "banana", "pear", "pineapple")
#' str_ilike(fruit, "app")
#' str_ilike(fruit, "app%")
#' str_ilike(fruit, "APP%")
#' str_ilike(fruit, "ba_ana")
#' str_ilike(fruit, "%apple")
str_ilike <- function(string, pattern) {
check_lengths(string, pattern)
check_character(pattern)
if (inherits(pattern, "stringr_pattern")) {
cli::cli_abort("{.arg pattern} must be a plain string, not a stringr modifier.")
}

pattern <- regex(like_to_regex(pattern), ignore_case = TRUE)
stri_detect_regex(string, pattern, opts_regex = opts(pattern))
}

Expand Down
36 changes: 36 additions & 0 deletions man/str_ilike.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 4 additions & 6 deletions man/str_like.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions tests/testthat/test-detect.R
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,16 @@ test_that("functions use tidyverse recycling rules", {

test_that("str_like works", {
expect_true(str_like("abc", "ab%"))
expect_false(str_like("abc", "AB%"))
expect_snapshot(str_like("abc", regex("x")), error = TRUE)
})

test_that("str_ilike works", {
expect_true(str_ilike("abc", "ab%"))
expect_true(str_ilike("abc", "AB%"))
expect_snapshot(str_ilike("abc", regex("x")), error = TRUE)
})

test_that("like_to_regex generates expected regexps",{
expect_equal(like_to_regex("ab%"), "^ab.*$")
expect_equal(like_to_regex("ab_"), "^ab.$")
Expand Down

0 comments on commit 4e44ac0

Please sign in to comment.