Skip to content

Commit bc2212c

Browse files
aplavinDilumAluthgeJeffBezanson
authored
allow convert from RegexMatch to Dict/NamedTuple (JuliaLang#50988)
Added implementation + tests, will add to docs if ok --------- Co-authored-by: Dilum Aluthge <[email protected]> Co-authored-by: Jeff Bezanson <[email protected]>
1 parent 7179050 commit bc2212c

File tree

3 files changed

+58
-3
lines changed

3 files changed

+58
-3
lines changed

NEWS.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,26 @@ New library functions
4141
New library features
4242
--------------------
4343

44+
* `invmod(n, T)` where `T` is a native integer type now computes the modular inverse of `n` in the modular integer ring that `T` defines ([#52180]).
45+
* `invmod(n)` is an abbreviation for `invmod(n, typeof(n))` for native integer types ([#52180]).
46+
* `replace(string, pattern...)` now supports an optional `IO` argument to
47+
write the output to a stream rather than returning a string ([#48625]).
48+
* `sizehint!(s, n)` now supports an optional `shrink` argument to disable shrinking ([#51929]).
49+
* New function `Docs.hasdoc(module, symbol)` tells whether a name has a docstring ([#52139]).
50+
* New function `Docs.undocumented_names(module)` returns a module's undocumented public names ([#52413]).
51+
* Passing an `IOBuffer` as a stdout argument for `Process` spawn now works as
52+
expected, synchronized with `wait` or `success`, so a `Base.BufferStream` is
53+
no longer required there for correctness to avoid data races ([#52461]).
54+
* After a process exits, `closewrite` will no longer be automatically called on
55+
the stream passed to it. Call `wait` on the process instead to ensure the
56+
content is fully written, then call `closewrite` manually to avoid
57+
data-races. Or use the callback form of `open` to have all that handled
58+
automatically.
59+
* `@timed` now additionally returns the elapsed compilation and recompilation time ([#52889])
60+
* `filter` can now act on a `NamedTuple` ([#50795]).
4461
* `tempname` can now take a suffix string to allow the file name to include a suffix and include that suffix in
4562
the uniquing checking ([#53474])
63+
* `RegexMatch` objects can now be used to construct `NamedTuple`s and `Dict`s ([#50988])
4664

4765
Standard library changes
4866
------------------------

base/regex.jl

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,11 @@ Methods that accept a `RegexMatch` object are defined for [`iterate`](@ref),
188188
[`getindex`](@ref), where keys are the names or numbers of a capture group.
189189
See [`keys`](@ref keys(::RegexMatch)) for more information.
190190
191+
`Tuple(m)`, `NamedTuple(m)`, and `Dict(m)` can be used to construct more flexible collection types from `RegexMatch` objects.
192+
193+
!!! compat "Julia 1.11"
194+
Constructing NamedTuples and Dicts from RegexMatches requires Julia 1.11
195+
191196
# Examples
192197
```jldoctest
193198
julia> m = match(r"(?<hour>\\d+):(?<minute>\\d+)(am|pm)?", "11:30 in the morning")
@@ -210,6 +215,12 @@ julia> hr, min, ampm = m; # destructure capture groups by iteration
210215
211216
julia> hr
212217
"11"
218+
219+
julia> Dict(m)
220+
Dict{Any, Union{Nothing, SubString{String}}} with 3 entries:
221+
"hour" => "11"
222+
3 => nothing
223+
"minute" => "30"
213224
```
214225
"""
215226
struct RegexMatch{S<:AbstractString} <: AbstractMatch
@@ -289,6 +300,9 @@ iterate(m::RegexMatch, args...) = iterate(m.captures, args...)
289300
length(m::RegexMatch) = length(m.captures)
290301
eltype(m::RegexMatch) = eltype(m.captures)
291302

303+
NamedTuple(m::RegexMatch) = NamedTuple{Symbol.(Tuple(keys(m)))}(values(m))
304+
Dict(m::RegexMatch) = Dict(pairs(m))
305+
292306
function occursin(r::Regex, s::AbstractString; offset::Integer=0)
293307
compile(r)
294308
return PCRE.exec_r(r.regex, String(s), offset, r.match_options)
@@ -381,9 +395,13 @@ end
381395
match(r::Regex, s::AbstractString[, idx::Integer[, addopts]])
382396
383397
Search for the first match of the regular expression `r` in `s` and return a [`RegexMatch`](@ref)
384-
object containing the match, or nothing if the match failed. The matching substring can be
385-
retrieved by accessing `m.match` and the captured sequences can be retrieved by accessing
386-
`m.captures` The optional `idx` argument specifies an index at which to start the search.
398+
object containing the match, or nothing if the match failed.
399+
The optional `idx` argument specifies an index at which to start the search.
400+
The matching substring can be retrieved by accessing `m.match`, the captured sequences can be retrieved by accessing `m.captures`.
401+
The resulting [`RegexMatch`](@ref) object can be used to construct other collections: e.g. `Tuple(m)`, `NamedTuple(m)`.
402+
403+
!!! compat "Julia 1.11"
404+
Constructing NamedTuples and Dicts requires Julia 1.11
387405
388406
# Examples
389407
```jldoctest

test/regex.jl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,34 @@
101101
@test haskey(m, 3)
102102
@test !haskey(m, 44)
103103
@test (m[1], m[2], m[3]) == ("x", "y", "z")
104+
@test Tuple(m) == ("x", "y", "z")
105+
@test NamedTuple(m) == (var"1"="x", var"2"="y", var"3"="z")
106+
@test Dict(m) == Dict([1=>"x", 2=>"y", 3=>"z"])
104107
@test sprint(show, m) == "RegexMatch(\"xyz\", 1=\"x\", 2=\"y\", 3=\"z\")"
105108
end
106109

107110
# Named subpatterns
111+
let m = match(r"(?<a>.)(?<c>.)(?<b>.)", "xyz")
112+
@test haskey(m, :a)
113+
@test haskey(m, "b")
114+
@test !haskey(m, "foo")
115+
@test (m[:a], m[:c], m["b"]) == ("x", "y", "z")
116+
@test Tuple(m) == ("x", "y", "z")
117+
@test NamedTuple(m) == (a="x", c="y", b="z")
118+
@test Dict(m) == Dict(["a"=>"x", "c"=>"y", "b"=>"z"])
119+
@test sprint(show, m) == "RegexMatch(\"xyz\", a=\"x\", c=\"y\", b=\"z\")"
120+
@test keys(m) == ["a", "c", "b"]
121+
end
122+
123+
# Named and unnamed subpatterns
108124
let m = match(r"(?<a>.)(.)(?<b>.)", "xyz")
109125
@test haskey(m, :a)
110126
@test haskey(m, "b")
111127
@test !haskey(m, "foo")
112128
@test (m[:a], m[2], m["b"]) == ("x", "y", "z")
129+
@test Tuple(m) == ("x", "y", "z")
130+
@test NamedTuple(m) == (a="x", var"2"="y", b="z")
131+
@test Dict(m) == Dict(["a"=>"x", 2=>"y", "b"=>"z"])
113132
@test sprint(show, m) == "RegexMatch(\"xyz\", a=\"x\", 2=\"y\", b=\"z\")"
114133
@test keys(m) == ["a", 2, "b"]
115134
end

0 commit comments

Comments
 (0)