diff --git a/base/REPL.jl b/base/REPL.jl index b53592a6467b8..ffa72e7f8c27d 100644 --- a/base/REPL.jl +++ b/base/REPL.jl @@ -338,8 +338,9 @@ function hist_from_file(hp, file) line[1] != '#' && error(invalid_history_message, repr(line[1]), " at line ", countlines) while !isempty(line) - m = match(r"^#\s*(\w+)\s*:\s*(.*?)\s*$", line) - m == nothing && break + maybe_m = match(r"^#\s*(\w+)\s*:\s*(.*?)\s*$", line) + isnull(maybe_m) && break + m = get(maybe_m) if m.captures[1] == "mode" mode = symbol(m.captures[2]) end diff --git a/base/REPLCompletions.jl b/base/REPLCompletions.jl index 2c24a22c600bb..3863252c27882 100644 --- a/base/REPLCompletions.jl +++ b/base/REPLCompletions.jl @@ -296,7 +296,7 @@ function completions(string, pos) Base.incomplete_tag(parse(partial, raise=false)) end if inc_tag in [:cmd, :string] - m = match(r"[\t\n\r\"'`@\$><=;|&\{]| (?!\\)", reverse(partial)) + m = get(match(r"[\t\n\r\"'`@\$><=;|&\{]| (?!\\)", reverse(partial))) startpos = nextind(partial, reverseind(partial, m.offset)) r = startpos:pos paths, r, success = complete_path(replace(string[r], r"\\ ", " "), pos) diff --git a/base/dates/io.jl b/base/dates/io.jl index a7fb3373aabf2..ede4bfa286360 100644 --- a/base/dates/io.jl +++ b/base/dates/io.jl @@ -65,12 +65,12 @@ duplicates(slots) = any(map(x->count(y->x.period==y.period,slots),slots) .> 1) function DateFormat(f::AbstractString,locale::AbstractString="english") slots = Slot[] trans = [] - begtran = match(r"^.*?(?=[ymuUdHMSsEe])",f).match + begtran = get(match(r"^.*?(?=[ymuUdHMSsEe])",f)).match ss = split(f,r"^.*?(?=[ymuUdHMSsEe])") s = split(begtran == "" ? ss[1] : ss[2],r"[^ymuUdHMSsEe]+|(?<=([ymuUdHMSsEe])(?!\1))") for (i,k) in enumerate(s) k == "" && break - tran = i >= endof(s) ? r"$" : match(Regex("(?<=$(s[i])).*(?=$(s[i+1]))"),f).match + tran = i >= endof(s) ? r"$" : get(match(Regex("(?<=$(s[i])).*(?=$(s[i+1]))"),f)).match slot = tran == "" ? FixedWidthSlot : DelimitedSlot width = length(k) typ = 'E' in k ? DayOfWeekSlot : 'e' in k ? DayOfWeekSlot : diff --git a/base/env.jl b/base/env.jl index c82cd267ecbce..27e19eaaa78d0 100644 --- a/base/env.jl +++ b/base/env.jl @@ -122,10 +122,11 @@ function next(::EnvHash, i) throw(BoundsError()) end env::ByteString - m = match(r"^(.*?)=(.*)$"s, env) - if m == nothing + maybe_m = match(r"^(.*?)=(.*)$"s, env) + if isnull(maybe_m) error("malformed environment entry: $env") end + m = get(maybe_m) (ByteString[convert(typeof(env),x) for x in m.captures], i+1) end end @@ -146,10 +147,11 @@ function next(hash::EnvHash, block::Tuple{Ptr{UInt16},Ptr{UInt16}}) buf = Array(UInt16, len) unsafe_copy!(pointer(buf), pos, len) env = utf8(UTF16String(buf)) - m = match(r"^(=?[^=]+)=(.*)$"s, env) - if m == nothing + maybe_m = match(r"^(=?[^=]+)=(.*)$"s, env) + if isnull(maybe_m) error("malformed environment entry: $env") end + m = get(maybe_m) (ByteString[convert(typeof(env),x) for x in m.captures], (pos+len*2, blk)) end end diff --git a/base/interactiveutil.jl b/base/interactiveutil.jl index 3f4e70aeeed54..053ed3e169ad0 100644 --- a/base/interactiveutil.jl +++ b/base/interactiveutil.jl @@ -189,7 +189,7 @@ function versioninfo(io::IO=STDOUT, verbose::Bool=false) if verbose println(io, "Environment:") for (k,v) in ENV - if !is(match(r"JULIA|PATH|FLAG|^TERM$|HOME", bytestring(k)), nothing) + if !isnull(match(r"JULIA|PATH|FLAG|^TERM$|HOME", bytestring(k))) println(io, " $(k) = $(v)") end end diff --git a/base/irrationals.jl b/base/irrationals.jl index 0806d6b703b82..d826a2f3d0277 100644 --- a/base/irrationals.jl +++ b/base/irrationals.jl @@ -131,7 +131,8 @@ log(::Irrational{:e}, x) = log(x) # align along = for nice Array printing function alignment(x::Irrational) - m = match(r"^(.*?)(=.*)$", sprint(showcompact_lim, x)) - m == nothing ? (length(sprint(showcompact_lim, x)), 0) : + maybe_m = match(r"^(.*?)(=.*)$", sprint(showcompact_lim, x)) + isnull(maybe_m) && return (length(sprint(showcompact_lim, x)), 0) + m = get(maybe_m) (length(m.captures[1]), length(m.captures[2])) end diff --git a/base/markdown/Common/block.jl b/base/markdown/Common/block.jl index 0b735f0c7f8fb..5da3ef931a991 100644 --- a/base/markdown/Common/block.jl +++ b/base/markdown/Common/block.jl @@ -57,7 +57,7 @@ function hashheader(stream::IO, md::MD) if c != '\n' # Empty header h = readline(stream) |> strip - h = match(r"(.*?)( +#+)?$", h).captures[1] + h = get(match(r"(.*?)( +#+)?$", h)).captures[1] buffer = IOBuffer() print(buffer, h) push!(md.content, Header(parseinline(seek(buffer, 0), md), level)) diff --git a/base/markdown/parse/util.jl b/base/markdown/parse/util.jl index 398ee28d2f293..6b0a135c71f5e 100644 --- a/base/markdown/parse/util.jl +++ b/base/markdown/parse/util.jl @@ -100,8 +100,9 @@ function startswith(stream::IO, r::Regex; eat = true, padding = false) padding && skipwhitespace(stream) line = chomp(readline(stream)) seek(stream, start) - m = match(r, line) - m == nothing && return "" + maybe_m = match(r, line) + isnull(maybe_m) && return "" + m = get(maybe_m) eat && @dotimes length(m.match) read(stream, Char) return m.match end diff --git a/base/methodshow.jl b/base/methodshow.jl index 935c0593d0ebd..e48d2bd2c86e1 100644 --- a/base/methodshow.jl +++ b/base/methodshow.jl @@ -93,7 +93,7 @@ function url(m::Method) try d = dirname(file) u = Git.readchomp(`config remote.origin.url`, dir=d) - u = match(Git.GITHUB_REGEX,u).captures[1] + u = get(match(Git.GITHUB_REGEX,u)).captures[1] root = cd(d) do # dir=d confuses --show-toplevel, apparently Git.readchomp(`rev-parse --show-toplevel`) end diff --git a/base/multi.jl b/base/multi.jl index bb30ce683d9c7..ae547dd2ebb54 100644 --- a/base/multi.jl +++ b/base/multi.jl @@ -1043,8 +1043,9 @@ function read_worker_host_port(io::IO) end function parse_connection_info(str) - m = match(r"^julia_worker:(\d+)#(.*)", str) - if m != nothing + maybe_m = match(r"^julia_worker:(\d+)#(.*)", str) + if !isnull(maybe_m) + m = get(maybe_m) (m.captures[2], parse(Int16, m.captures[1])) else ("", Int16(-1)) diff --git a/base/path.jl b/base/path.jl index 02649a1f7743c..10130befedc84 100644 --- a/base/path.jl +++ b/base/path.jl @@ -20,7 +20,7 @@ end const path_ext_splitter = r"^((?:.*[/\\])?(?:\.|[^/\\\.])[^/\\]*?)(\.[^/\\\.]*|)$" function splitdrive(path::AbstractString) - m = match(r"^(\w+:|\\\\\w+\\\w+|\\\\\?\\UNC\\\w+\\\w+|\\\\\?\\\w+:|)(.*)$", path) + m = get(match(r"^(\w+:|\\\\\w+\\\w+|\\\\\?\\UNC\\\w+\\\w+|\\\\\?\\\w+:|)(.*)$", path)) bytestring(m.captures[1]), bytestring(m.captures[2]) end homedir() = get(ENV,"HOME",string(ENV["HOMEDRIVE"],ENV["HOMEPATH"])) @@ -31,8 +31,9 @@ isdirpath(path::AbstractString) = ismatch(path_directory_re, splitdrive(path)[2] function splitdir(path::ByteString) a, b = splitdrive(path) - m = match(path_dir_splitter,b) - m == nothing && return (a,b) + maybe_m = match(path_dir_splitter,b) + isnull(maybe_m) && return (a,b) + m = get(maybe_m) a = string(a, isempty(m.captures[1]) ? m.captures[2][1] : m.captures[1]) a, bytestring(m.captures[3]) end @@ -43,15 +44,16 @@ basename(path::AbstractString) = splitdir(path)[2] function splitext(path::AbstractString) a, b = splitdrive(path) - m = match(path_ext_splitter, b) - m == nothing && return (path,"") + maybe_m = match(path_ext_splitter, b) + isnull(maybe_m) && return (path,"") + m = get(maybe_m) a*m.captures[1], bytestring(m.captures[2]) end function pathsep(paths::AbstractString...) for path in paths - m = match(path_separator_re, path) - m != nothing && return m.match[1] + maybe_m = match(path_separator_re, path) + !isnull(maybe_m) && return get(maybe_m).match[1] end return path_separator end diff --git a/base/pkg/entry.jl b/base/pkg/entry.jl index 5b57a98f68001..b96a3e5dd9674 100644 --- a/base/pkg/entry.jl +++ b/base/pkg/entry.jl @@ -172,9 +172,9 @@ function clone(url_or_pkg::AbstractString) # TODO: Cache.prefetch(pkg,url) else url = url_or_pkg - m = match(r"(?:^|[/\\])(\w+?)(?:\.jl)?(?:\.git)?$", url) - m != nothing || error("can't determine package name from URL: $url") - pkg = m.captures[1] + maybe_m = match(r"(?:^|[/\\])(\w+?)(?:\.jl)?(?:\.git)?$", url) + isnull(maybe_m) && error("can't determine package name from URL: $url") + pkg = get(maybe_m).captures[1] end clone(url,pkg) end @@ -312,9 +312,9 @@ function pull_request(dir::AbstractString, commit::AbstractString="", url::Abstr commit = isempty(commit) ? Git.head(dir=dir) : Git.readchomp(`rev-parse --verify $commit`, dir=dir) isempty(url) && (url = Git.readchomp(`config remote.origin.url`, dir=dir)) - m = match(Git.GITHUB_REGEX, url) - m == nothing && error("not a GitHub repo URL, can't make a pull request: $url") - owner, repo = m.captures[2:3] + maybe_m = match(Git.GITHUB_REGEX, url) + isnull(maybe_m) && error("not a GitHub repo URL, can't make a pull request: $url") + owner, repo = get(maybe_m).captures[2:3] user = GitHub.user() info("Forking $owner/$repo to $user") response = GitHub.fork(owner,repo) diff --git a/base/pkg/git.jl b/base/pkg/git.jl index 8be26b94a48dc..d83bc3e16a741 100644 --- a/base/pkg/git.jl +++ b/base/pkg/git.jl @@ -110,9 +110,9 @@ const GITHUB_REGEX = function set_remote_url(url::AbstractString; remote::AbstractString="origin", dir="") run(`config remote.$remote.url $url`, dir=dir) - m = match(GITHUB_REGEX,url) - m == nothing && return - push = "git@github.com:$(m.captures[1]).git" + maybe_m = match(GITHUB_REGEX,url) + isnull(maybe_m) && return + push = "git@github.com:$(get(maybe_m).captures[1]).git" push != url && run(`config remote.$remote.pushurl $push`, dir=dir) end diff --git a/base/pkg/read.jl b/base/pkg/read.jl index eac7e360836cb..051768160d106 100644 --- a/base/pkg/read.jl +++ b/base/pkg/read.jl @@ -168,9 +168,9 @@ end function issue_url(pkg::AbstractString) ispath(pkg,".git") || return "" - m = match(Git.GITHUB_REGEX, url(pkg)) - m == nothing && return "" - return "https://github.com/" * m.captures[1] * "/issues" + maybe_m = match(Git.GITHUB_REGEX, url(pkg)) + isnull(maybe_m) && return + return "https://github.com/" * get(maybe_m).captures[1] * "/issues" end end # module diff --git a/base/regex.jl b/base/regex.jl index 2699c563ec349..465930de759f0 100644 --- a/base/regex.jl +++ b/base/regex.jl @@ -141,7 +141,7 @@ function match(re::Regex, str::UTF8String, idx::Integer, add_opts::UInt32=UInt32 compile(re) opts = re.match_options | add_opts if !PCRE.exec(re.regex, str, idx-1, opts, re.match_data) - return nothing + return Nullable{RegexMatch}() end ovec = re.ovec n = div(length(ovec),2) - 1 @@ -149,7 +149,7 @@ function match(re::Regex, str::UTF8String, idx::Integer, add_opts::UInt32=UInt32 cap = Union{Void,SubString{UTF8String}}[ ovec[2i+1] == PCRE.UNSET ? nothing : SubString(str, ovec[2i+1]+1, ovec[2i+2]) for i=1:n ] off = Int[ ovec[2i+1]+1 for i=1:n ] - RegexMatch(mat, cap, ovec[1]+1, off, re) + Nullable(RegexMatch(mat, cap, ovec[1]+1, off, re)) end match(re::Regex, str::Union{ByteString,SubString}, idx::Integer, add_opts::UInt32=UInt32(0)) = @@ -221,10 +221,11 @@ end compile(itr::RegexMatchIterator) = (compile(itr.regex); itr) eltype(::Type{RegexMatchIterator}) = RegexMatch start(itr::RegexMatchIterator) = match(itr.regex, itr.string, 1, UInt32(0)) -done(itr::RegexMatchIterator, prev_match) = (prev_match == nothing) +done(itr::RegexMatchIterator, prev_match) = isnull(prev_match) # Assumes prev_match is not nothing -function next(itr::RegexMatchIterator, prev_match) +function next(itr::RegexMatchIterator, maybe_prev_match) + prev_match = get(maybe_prev_match) prevempty = isempty(prev_match.match) if itr.overlap @@ -242,7 +243,7 @@ function next(itr::RegexMatchIterator, prev_match) mat = match(itr.regex, itr.string, offset, prevempty ? opts_nonempty : UInt32(0)) - if mat === nothing + if isnull(mat) if prevempty && offset <= length(itr.string.data) offset = nextind(itr.string, offset) prevempty = false @@ -251,10 +252,10 @@ function next(itr::RegexMatchIterator, prev_match) break end else - return (prev_match, mat) + return (get(maybe_prev_match), mat) end end - (prev_match, nothing) + (get(maybe_prev_match), Nullable{RegexMatch}()) end function eachmatch(re::Regex, str::AbstractString, ovr::Bool=false) diff --git a/base/show.jl b/base/show.jl index b560347e37c9a..31e08edb5506c 100644 --- a/base/show.jl +++ b/base/show.jl @@ -929,19 +929,19 @@ alignment(x::Any) = (0, length(sprint(showcompact_lim, x))) alignment(x::Number) = (length(sprint(showcompact_lim, x)), 0) alignment(x::Integer) = (length(sprint(showcompact_lim, x)), 0) function alignment(x::Real) - m = match(r"^(.*?)((?:[\.eE].*)?)$", sprint(showcompact_lim, x)) - m == nothing ? (length(sprint(showcompact_lim, x)), 0) : - (length(m.captures[1]), length(m.captures[2])) + maybe_m = match(r"^(.*?)((?:[\.eE].*)?)$", sprint(showcompact_lim, x)) + isnull(maybe_m) ? (length(sprint(showcompact_lim, x)), 0) : + (length(get(maybe_m).captures[1]), length(get(maybe_m).captures[2])) end function alignment(x::Complex) - m = match(r"^(.*[\+\-])(.*)$", sprint(showcompact_lim, x)) - m == nothing ? (length(sprint(showcompact_lim, x)), 0) : - (length(m.captures[1]), length(m.captures[2])) + maybe_m = match(r"^(.*[\+\-])(.*)$", sprint(showcompact_lim, x)) + isnull(maybe_m) ? (length(sprint(showcompact_lim, x)), 0) : + (length(get(maybe_m).captures[1]), length(get(maybe_m).captures[2])) end function alignment(x::Rational) - m = match(r"^(.*?/)(/.*)$", sprint(showcompact_lim, x)) - m == nothing ? (length(sprint(showcompact_lim, x)), 0) : - (length(m.captures[1]), length(m.captures[2])) + maybe_m = match(r"^(.*?/)(/.*)$", sprint(showcompact_lim, x)) + isnull(maybe_m) ? (length(sprint(showcompact_lim, x)), 0) : + (length(get(maybe_m).captures[1]), length(get(maybe_m).captures[2])) end const undef_ref_str = "#undef" diff --git a/base/version.jl b/base/version.jl index 2471fe5de168c..3dd31f8dc4e6d 100644 --- a/base/version.jl +++ b/base/version.jl @@ -82,8 +82,9 @@ function split_idents(s::AbstractString) end VersionNumber(v::AbstractString) = begin - m = match(VERSION_REGEX, v) - m == nothing && throw(ArgumentError("invalid version string: $v")) + maybe_m = match(VERSION_REGEX, v) + isnull(maybe_m) && throw(ArgumentError("invalid version string: $v")) + m = get(maybe_m) major, minor, patch, minus, prerl, plus, build = m.captures major = parse(Int, major) minor = minor != nothing ? parse(Int, minor) : 0 diff --git a/doc/manual/strings.rst b/doc/manual/strings.rst index b51eef87b0352..6a7a294d81d56 100644 --- a/doc/manual/strings.rst +++ b/doc/manual/strings.rst @@ -595,23 +595,22 @@ however, one wants to know not just whether a string matched, but also .. doctest:: julia> match(r"^\s*(?:#|$)", "not a comment") - + Nullable{RegexMatch}() julia> match(r"^\s*(?:#|$)", "# a comment") - RegexMatch("#") + Nullable(RegexMatch("#")) If the regular expression does not match the given string, :func:`match` -returns ``nothing`` — a special value that does not print anything at -the interactive prompt. Other than not printing, it is a completely -normal value and you can test for it programmatically:: +returns a null-valued ``Nullable`` object, ``Nullable{RegexMatch}()``. +You can test for this with the ``isnull`` function:: - m = match(r"^\s*(?:#|$)", line) - if m == nothing + maybe_m = match(r"^\s*(?:#|$)", line) + if isnull(maybe_m) println("not a comment") else println("blank or comment") end -If a regular expression does match, the value returned by :func:`match` is a +If a regular expression does match, then you can call ``get`` on the value returned by :func:`match` to get a :obj:`RegexMatch` object. These objects record how the expression matches, including the substring that the pattern matches and any captured substrings, if there are any. This example only captures the portion of @@ -620,7 +619,7 @@ text after the comment character. We could do the following: .. doctest:: - julia> m = match(r"^\s*(?:#\s*(.*?)\s*$|$)", "# a comment ") + julia> m = get(match(r"^\s*(?:#\s*(.*?)\s*$|$)", "# a comment ")) RegexMatch("# a comment ", 1="a comment") When calling :func:`match`, you have the option to specify an index at @@ -629,13 +628,13 @@ which to start the search. For example: .. doctest:: julia> m = match(r"[0-9]","aaaa1aaaa2aaaa3",1) - RegexMatch("1") + Nullable(RegexMatch("1")) julia> m = match(r"[0-9]","aaaa1aaaa2aaaa3",6) - RegexMatch("2") + Nullable(RegexMatch("2")) julia> m = match(r"[0-9]","aaaa1aaaa2aaaa3",11) - RegexMatch("3") + Nullable(RegexMatch("3")) You can extract the following info from a :obj:`RegexMatch` object: @@ -649,7 +648,7 @@ contains ``nothing`` in that position, and ``m.offsets`` has a zero offset (recall that indices in Julia are 1-based, so a zero offset into a string is invalid). Here's is a pair of somewhat contrived examples:: - julia> m = match(r"(a|b)(c)?(d)", "acd") + julia> m = get(match(r"(a|b)(c)?(d)", "acd")) RegexMatch("acd", 1="a", 2="c", 3="d") julia> m.match @@ -670,7 +669,7 @@ a string is invalid). Here's is a pair of somewhat contrived examples:: 2 3 - julia> m = match(r"(a|b)(c)?(d)", "ad") + julia> m = get(match(r"(a|b)(c)?(d)", "ad")) RegexMatch("ad", 1="a", 2=nothing, 3="d") julia> m.match @@ -700,7 +699,7 @@ use destructuring syntax to bind them to local variables:: Captures can also be accessed by indexing the :obj:`RegexMatch` object with the number or name of the capture group:: - julia> m=match(r"(?P\d+):(?P\d+)","12:45") + julia> m = get(match(r"(?P\d+):(?P\d+)","12:45")) RegexMatch("12:45", hour="12", minute="45") julia> m[:minute] "45" @@ -749,7 +748,7 @@ For example, the following regex has all three flags turned on: r"a+.*b+.*?d$"ims julia> match(r"a+.*b+.*?d$"ism, "Goodbye,\nOh, angry,\nBad world\n") - RegexMatch("angry,\nBad world") + Nullable(RegexMatch("angry,\nBad world")) Triple-quoted regex strings, of the form ``r"""..."""``, are also supported (and may be convenient for regular expressions containing diff --git a/doc/stdlib/strings.rst b/doc/stdlib/strings.rst index 4cba2c7179790..0fe87e5f13a07 100644 --- a/doc/stdlib/strings.rst +++ b/doc/stdlib/strings.rst @@ -133,7 +133,7 @@ .. function:: match(r::Regex, s::AbstractString[, idx::Integer[, addopts]]) - Search for the first match of the regular expression ``r`` in ``s`` and return a RegexMatch object containing the match, or nothing if the match failed. The matching substring can be retrieved by accessing ``m.match`` and the captured sequences can be retrieved by accessing ``m.captures`` The optional ``idx`` argument specifies an index at which to start the search. + Search for the first match of the regular expression ``r`` in ``s`` and return a Nullable{RegexMatch} object that eihther contains the match or is null if the match failed. The matching substring can be retrieved by accessing ``get(m).match`` and the captured sequences can be retrieved by accessing ``get(m).captures`` The optional ``idx`` argument specifies an index at which to start the search. .. function:: eachmatch(r::Regex, s::AbstractString[, overlap::Bool=false]) diff --git a/test/regex.jl b/test/regex.jl index aaf8eafa72a39..7bf40f16b297b 100644 --- a/test/regex.jl +++ b/test/regex.jl @@ -39,6 +39,6 @@ show(buf, r"") @test_throws ArgumentError search(utf32("this is a test"), r"test") # Named subpatterns -m = match(r"(?.)(.)(?.)", "xyz") +m = get(match(r"(?.)(.)(?.)", "xyz")) @test (m[:a], m[2], m["b"]) == ("x", "y", "z") @test sprint(show, m) == "RegexMatch(\"xyz\", a=\"x\", 2=\"y\", b=\"z\")"