Skip to content

Commit

Permalink
Make startswith, endswith work with Regex (#29790)
Browse files Browse the repository at this point in the history
  • Loading branch information
dalum authored and StefanKarpinski committed Feb 1, 2019
1 parent 5533f22 commit 2b4f003
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 0 deletions.
1 change: 1 addition & 0 deletions base/pcre.jl
Expand Up @@ -37,6 +37,7 @@ const COMPILE_MASK =
CASELESS |
DOLLAR_ENDONLY |
DOTALL |
ENDANCHORED |
EXTENDED |
FIRSTLINE |
MULTILINE |
Expand Down
62 changes: 62 additions & 0 deletions base/regex.jl
Expand Up @@ -174,6 +174,68 @@ function occursin(r::Regex, s::SubString; offset::Integer=0)
r.match_data)
end

"""
startswith(s::AbstractString, prefix::Regex)
Return `true` if `s` starts with the regex pattern, `prefix`.
!!! note
`startswith` does not compile the anchoring into the regular
expression, but instead passes the anchoring as
`match_option` to PCRE. If compile time is amortized,
`occursin(r"^...", s)` is faster than `startswith(s, r"...")`.
See also [`occursin`](@ref) and [`endswith`](@ref).
# Examples
```jldoctest
julia> startswith("JuliaLang", r"Julia|Romeo")
true
```
"""
function startswith(s::AbstractString, r::Regex)
compile(r)
return PCRE.exec(r.regex, String(s), 0, r.match_options | PCRE.ANCHORED,
r.match_data)
end

function startswith(s::SubString, r::Regex)
compile(r)
return PCRE.exec(r.regex, s, 0, r.match_options | PCRE.ANCHORED,
r.match_data)
end

"""
endswith(s::AbstractString, suffix::Regex)
Return `true` if `s` ends with the regex pattern, `suffix`.
!!! note
`endswith` does not compile the anchoring into the regular
expression, but instead passes the anchoring as
`match_option` to PCRE. If compile time is amortized,
`occursin(r"...\$", s)` is faster than `endswith(s, r"...")`.
See also [`occursin`](@ref) and [`startswith`](@ref).
# Examples
```jldoctest
julia> endswith("JuliaLang", r"Lang|Roberts")
true
```
"""
function endswith(s::AbstractString, r::Regex)
compile(r)
return PCRE.exec(r.regex, String(s), 0, r.match_options | PCRE.ENDANCHORED,
r.match_data)
end

function endswith(s::SubString, r::Regex)
compile(r)
return PCRE.exec(r.regex, s, 0, r.match_options | PCRE.ENDANCHORED,
r.match_data)
end

"""
match(r::Regex, s::AbstractString[, idx::Integer[, addopts]])
Expand Down
12 changes: 12 additions & 0 deletions test/regex.jl
Expand Up @@ -66,6 +66,18 @@
# Regex behaves like a scalar in broadcasting
@test occursin.(r"Hello", ["Hello", "World"]) == [true, false]

@test startswith("abc", r"a")
@test endswith("abc", r"c")
@test !startswith("abc", r"b")
@test !startswith("abc", r"c")
@test !endswith("abc", r"a")
@test !endswith("abc", r"b")

@test !startswith("abc", r"A")
@test startswith("abc", r"A"i)
@test !endswith("abc", r"C")
@test endswith("abc", r"C"i)

# Test that PCRE throws the correct kind of error
# TODO: Uncomment this once the corresponding change has propagated to CI
#@test_throws ErrorException Base.PCRE.info(C_NULL, Base.PCRE.INFO_NAMECOUNT, UInt32)
Expand Down

0 comments on commit 2b4f003

Please sign in to comment.