Skip to content

Commit fec530c

Browse files
jonthegeekhadley
authored andcommitted
Added str_starts and str_ends wrapper functions. (#270)
Fixes #258
1 parent 2dd63d7 commit fec530c

File tree

5 files changed

+128
-0
lines changed

5 files changed

+128
-0
lines changed

NAMESPACE

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export(str_conv)
1212
export(str_count)
1313
export(str_detect)
1414
export(str_dup)
15+
export(str_ends)
1516
export(str_extract)
1617
export(str_extract_all)
1718
export(str_flatten)
@@ -34,6 +35,7 @@ export(str_sort)
3435
export(str_split)
3536
export(str_split_fixed)
3637
export(str_squish)
38+
export(str_starts)
3739
export(str_sub)
3840
export(str_subset)
3941
export(str_to_lower)

NEWS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
* New `str_to_sentence()` function to capitalize with sentence case
1111
(@jonthegeek, #202)
1212

13+
* New `str_starts()` and `str_ends()` functions to detect patterns at the
14+
beginning or end of strings (@jonthegeek, #258)
15+
1316
# stringr 1.3.1
1417

1518
* `str_replace_all()` with a named vector now respects modifier functions (#207)

R/detect.r

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,58 @@ str_detect <- function(string, pattern, negate = FALSE) {
4949
regex = stri_detect_regex(string, pattern, negate = negate, opts_regex = opts(pattern))
5050
)
5151
}
52+
53+
#' Detect the presence or absence of a pattern at the beginning or end of a
54+
#' string.
55+
#'
56+
#' Vectorised over `string` and `pattern`.
57+
#'
58+
#' @inheritParams str_detect
59+
#' @param pattern Pattern with which the string starts or ends.
60+
#'
61+
#' The default interpretation is a regular expression, as described in
62+
#' [stringi::stringi-search-regex]. Control options with [regex()].
63+
#'
64+
#' Match a fixed string (i.e. by comparing only bytes), using [fixed()]. This
65+
#' is fast, but approximate. Generally, for matching human text, you'll want
66+
#' [coll()] which respects character matching rules for the specified locale.
67+
#'
68+
#' @return A logical vector.
69+
#' @seealso [str_detect()] which this function wraps when pattern is regex.
70+
#' @export
71+
#' @examples
72+
#' fruit <- c("apple", "banana", "pear", "pinapple")
73+
#' str_starts(fruit, "p")
74+
#' str_starts(fruit, "p", negate = TRUE)
75+
#' str_ends(fruit, "e")
76+
#' str_ends(fruit, "e", negate = TRUE)
77+
str_starts <- function(string, pattern, negate = FALSE) {
78+
switch(
79+
type(pattern),
80+
empty = ,
81+
bound = stop("boundary() patterns are not supported."),
82+
fixed = stri_startswith_fixed(string, pattern, negate = negate, opts_fixed = opts(pattern)),
83+
coll = stri_startswith_coll(string, pattern, negate = negate, opts_collator = opts(pattern)),
84+
regex = {
85+
pattern2 <- paste0("^", pattern)
86+
attributes(pattern2) <- attributes(pattern)
87+
str_detect(string, pattern2, negate)
88+
}
89+
)
90+
}
91+
92+
#' @rdname str_starts
93+
#' @export
94+
str_ends <- function(string, pattern, negate = FALSE) {
95+
switch(type(pattern),
96+
empty = ,
97+
bound = stop("boundary() patterns are not supported."),
98+
fixed = stri_endswith_fixed(string, pattern, negate = negate, opts_fixed = opts(pattern)),
99+
coll = stri_endswith_coll(string, pattern, negate = negate, opts_collator = opts(pattern)),
100+
regex = {
101+
pattern2 <- paste0(pattern, "$")
102+
attributes(pattern2) <- attributes(pattern)
103+
str_detect(string, pattern2, negate)
104+
}
105+
)
106+
}

man/str_starts.Rd

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

tests/testthat/test-detect.r

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,28 @@ test_that("modifiers work", {
2424

2525
expect_true(str_detect("abc", "(?x)a b c"))
2626
})
27+
28+
test_that("str_starts works", {
29+
expect_true(str_starts("ab", "a"))
30+
expect_false(str_starts("ab", "b"))
31+
32+
# negation
33+
expect_false(str_starts("ab", "a", TRUE))
34+
expect_true(str_starts("ab", "b", TRUE))
35+
36+
# Special typing of patterns.
37+
expect_true(str_starts("ab", fixed("A", ignore_case = TRUE)))
38+
expect_true(str_starts("ab", regex("A", ignore_case = TRUE)))
39+
})
40+
41+
test_that("str_ends works", {
42+
expect_true(str_ends("ab", "b"))
43+
expect_false(str_ends("ab", "a"))
44+
45+
# negation
46+
expect_false(str_ends("ab", "b", TRUE))
47+
expect_true(str_ends("ab", "a", TRUE))
48+
49+
# Special typing of patterns.
50+
expect_true(str_ends("ab", fixed("B", ignore_case = TRUE)))
51+
})

0 commit comments

Comments
 (0)