From 7f551523c6792acb9ed1087bb99cf6f64df2620b Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Fri, 10 May 2019 12:04:18 +0200 Subject: [PATCH 1/2] add convert(::Type{Regex}, ::Union{AbstractString,AbstractChar}) --- base/regex.jl | 30 +++++++++++++++++++++++++++++- test/regex.jl | 19 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/base/regex.jl b/base/regex.jl index 5c1ba8c37e956..c8cac9fe98f5a 100644 --- a/base/regex.jl +++ b/base/regex.jl @@ -607,7 +607,7 @@ function hash(r::Regex, h::UInt) h = hash(r.match_options, h) end -## String operations ## +## string operations ## """ *(s::Regex, t::Union{Regex,AbstractString,AbstractChar}) -> Regex @@ -710,3 +710,31 @@ RegexMatch("Test Test ") ``` """ ^(r::Regex, i::Integer) = Regex(string("(?:", r.pattern, "){$i}"), r.compile_options, r.match_options) + +## conversion from strings/chars ## + +""" + convert(::Type{Regex}, x::AbstractChar) + convert(::Type{Regex}, x::AbstractString) + +Create a `Regex` which matches `x` exactly. This means that special characters are +not interpreted as having special meaning. +Multiplication can also be used in order to create a regex with specific flags. + +!!! compat "Julia 1.3" + This method requires at least Julia 1.3. + +# Examples +```jldoctest +julia> match(convert(Regex, '('), "(").match +"(" + +julia> match(convert(Regex, ".*"), "abc") == nothing +true + +julia> match(convert(Regex, ".*"), ".*") +RegexMatch(".*") +``` + +""" +convert(::Type{Regex}, s::Union{AbstractString,AbstractChar}) = Regex(wrap_string(s, zero(UInt32))) diff --git a/test/regex.jl b/test/regex.jl index 6a32a49051d13..6f55630adc4ec 100644 --- a/test/regex.jl +++ b/test/regex.jl @@ -136,6 +136,25 @@ @test r"this|that"^2 == r"(?:this|that){2}" end + @testset "convert from strings/chars" begin + r = convert(Regex, 'a') + @test r == r"\Qa\E" # these tests can change if the implementation changes + @test match(r, "a").match == "a" + r = convert(Regex, '\\') + @test r == r"\Q\\E" + @test match(r, "\\").match == "\\" + r = convert(Regex, '(') + @test r == r"\Q(\E" + @test match(r, "(").match == "(" + + r = convert(Regex, "a\\b(c") + @test r == r"\Qa\b(c\E" + @test match(r, "a\\b(c").match == "a\\b(c" + r = convert(Regex, "a\\E\\Qz") + @test r == r"\Qa\\E\QE\Qz\E" + @test match(r, "a\\E\\Qz") != nothing + end + # 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) From 436cac2fefe796d13e51af433e62dd2f7492ed78 Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Tue, 20 Aug 2019 16:58:27 +0200 Subject: [PATCH 2/2] rename function from "convert" to "escape_regex" --- base/exports.jl | 1 + base/regex.jl | 12 ++++++------ doc/src/base/strings.md | 1 + test/regex.jl | 12 ++++++------ 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/base/exports.jl b/base/exports.jl index ebd746392558a..3a9427307947f 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -438,6 +438,7 @@ export # search, find, match and related functions eachmatch, endswith, + escape_regex, findall, findfirst, findlast, diff --git a/base/regex.jl b/base/regex.jl index c8cac9fe98f5a..982be5dd0d4f9 100644 --- a/base/regex.jl +++ b/base/regex.jl @@ -714,8 +714,8 @@ RegexMatch("Test Test ") ## conversion from strings/chars ## """ - convert(::Type{Regex}, x::AbstractChar) - convert(::Type{Regex}, x::AbstractString) + escape_regex(x::AbstractChar) + escape_regex(x::AbstractString) Create a `Regex` which matches `x` exactly. This means that special characters are not interpreted as having special meaning. @@ -726,15 +726,15 @@ Multiplication can also be used in order to create a regex with specific flags. # Examples ```jldoctest -julia> match(convert(Regex, '('), "(").match +julia> match(escape_regex('('), "(").match "(" -julia> match(convert(Regex, ".*"), "abc") == nothing +julia> match(escape_regex(".*"), "abc") == nothing true -julia> match(convert(Regex, ".*"), ".*") +julia> match(escape_regex(".*"), ".*") RegexMatch(".*") ``` """ -convert(::Type{Regex}, s::Union{AbstractString,AbstractChar}) = Regex(wrap_string(s, zero(UInt32))) +escape_regex(s::Union{AbstractString,AbstractChar}) = Regex(wrap_string(s, zero(UInt32))) diff --git a/doc/src/base/strings.md b/doc/src/base/strings.md index 12da6d950abaf..cba14843cd1c7 100644 --- a/doc/src/base/strings.md +++ b/doc/src/base/strings.md @@ -32,6 +32,7 @@ Base.isvalid(::Any, ::Any) Base.isvalid(::AbstractString, ::Integer) Base.match Base.eachmatch +Base.escape_regex Base.isless(::AbstractString, ::AbstractString) Base.:(==)(::AbstractString, ::AbstractString) Base.cmp(::AbstractString, ::AbstractString) diff --git a/test/regex.jl b/test/regex.jl index 6f55630adc4ec..a10a143d3a0c0 100644 --- a/test/regex.jl +++ b/test/regex.jl @@ -136,21 +136,21 @@ @test r"this|that"^2 == r"(?:this|that){2}" end - @testset "convert from strings/chars" begin - r = convert(Regex, 'a') + @testset "escape_regex" begin + r = escape_regex('a') @test r == r"\Qa\E" # these tests can change if the implementation changes @test match(r, "a").match == "a" - r = convert(Regex, '\\') + r = escape_regex('\\') @test r == r"\Q\\E" @test match(r, "\\").match == "\\" - r = convert(Regex, '(') + r = escape_regex('(') @test r == r"\Q(\E" @test match(r, "(").match == "(" - r = convert(Regex, "a\\b(c") + r = escape_regex("a\\b(c") @test r == r"\Qa\b(c\E" @test match(r, "a\\b(c").match == "a\\b(c" - r = convert(Regex, "a\\E\\Qz") + r = escape_regex("a\\E\\Qz") @test r == r"\Qa\\E\QE\Qz\E" @test match(r, "a\\E\\Qz") != nothing end