update
This commit is contained in:
387
src/util.jl
Normal file
387
src/util.jl
Normal file
@@ -0,0 +1,387 @@
|
||||
module util
|
||||
|
||||
export timedifference, showstracktrace, findHighestIndexKey, uuid4snakecase, replaceDictKeys,
|
||||
findMatchingDictKey, textToDict, randstring, randstrings
|
||||
|
||||
using JSON3, DataStructures, Distributions, Random, Dates, UUIDs, MQTTClient
|
||||
|
||||
# ---------------------------------------------- 100 --------------------------------------------- #
|
||||
|
||||
""" Compute time different between start time and stop time in a given unit.
|
||||
Unit can be "milliseconds", "seconds", "minutes", "hours".
|
||||
|
||||
# Arguments
|
||||
- `starttime::DateTime`
|
||||
start time
|
||||
- `stoptime::DateTime`
|
||||
stop time
|
||||
- `unit::String`
|
||||
unit of time difference
|
||||
|
||||
# Return
|
||||
- time difference in given unit
|
||||
|
||||
# Example
|
||||
```jldoctest
|
||||
julia> using Revise
|
||||
julia> using GeneralUtils, Dates
|
||||
julia> a = Dates.now()
|
||||
julia> b = a + Dates.Day(5) # add 5 days
|
||||
julia> GeneralUtils.timedifference(a, b, "hours")
|
||||
120
|
||||
```
|
||||
|
||||
# Signature
|
||||
"""
|
||||
function timedifference(starttime::DateTime, stoptime::DateTime, unit::String)::Integer
|
||||
diff = stoptime - starttime
|
||||
unit = lowercase(unit)
|
||||
|
||||
if unit == "milliseconds"
|
||||
return diff.value
|
||||
elseif unit == "seconds"
|
||||
return diff.value ÷ 1000
|
||||
elseif unit == "minutes"
|
||||
return diff.value ÷ (1000 * 60)
|
||||
elseif unit == "hours"
|
||||
return diff.value ÷ (1000 * 60 * 60)
|
||||
else
|
||||
error("Invalid unit specified. Please choose from: milliseconds, seconds, minutes, hours")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
""" Capture then show error and stacktrace
|
||||
|
||||
# Arguments
|
||||
- `f::Function`
|
||||
a function that might throws an error
|
||||
- `args` function f arguments
|
||||
|
||||
# Return
|
||||
- `outcome::NamedTuple`
|
||||
(success, result, errormsg, st)
|
||||
|
||||
# Example
|
||||
```jldoctest
|
||||
julia> using Revise
|
||||
julia> using GeneralUtils, PrettyPrinting
|
||||
julia> testf(a, b) = a + b
|
||||
julia> success, result, errormsg, st = GeneralUtils.showstracktrace(testf, 5, "6")
|
||||
julia> pprint(st)
|
||||
16-element Vector{Base.StackTraces.StackFrame}:
|
||||
testf(a::Int64, b::String) at REPL[12]:1
|
||||
showstracktrace(::Function, ::Int64, ::Vararg{Any}) at util.jl:95
|
||||
...
|
||||
```
|
||||
|
||||
# Signature
|
||||
"""
|
||||
function showstracktrace(f::Function, args...)::NamedTuple
|
||||
global st = nothing # stacktrace
|
||||
global errorMsg = nothing
|
||||
global success = false
|
||||
global fResult = nothing
|
||||
|
||||
try
|
||||
success, fResult
|
||||
fResult = f(args...)
|
||||
success = true
|
||||
catch e
|
||||
io = IOBuffer()
|
||||
showerror(io, e)
|
||||
errorMsg = String(take!(io))
|
||||
|
||||
st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace()))
|
||||
@warn "Error occurred: $errorMsg\n$st"
|
||||
end
|
||||
|
||||
return (success=success, result=fResult, errormsg=errorMsg, st=st)
|
||||
end
|
||||
|
||||
""" Find all match key of a dictionary for a given key.
|
||||
|
||||
# Arguments
|
||||
- `d<:AbstractDict`
|
||||
The dictionary to search for keys.
|
||||
- `text<:Symbol`
|
||||
The text to match against the keys.
|
||||
|
||||
# Returns
|
||||
- `result::Vector{Symbol}`
|
||||
A vector of matched key
|
||||
|
||||
|
||||
# Examples
|
||||
```jldoctest
|
||||
julia> using Revise
|
||||
julia> using GeneralUtils
|
||||
julia> d = Dict(:key_1 => "apple", :key_12 => "banana", :key_3 => "cherry")
|
||||
julia> GeneralUtils.findMatchingDictKey(d, "key_1")
|
||||
2-element Vector{Symbol}:
|
||||
:key_1
|
||||
:key_12
|
||||
```
|
||||
|
||||
# Signature
|
||||
"""
|
||||
function findMatchingDictKey(d::T, text::Union{String, Symbol}
|
||||
)::Vector{Symbol} where {T<:AbstractDict}
|
||||
|
||||
_matching_keys = filter(k -> occursin(string(text), string(k)), keys(d))
|
||||
matching_keys = collect(_matching_keys) # convert from Set into Array
|
||||
|
||||
return matching_keys
|
||||
end
|
||||
|
||||
|
||||
"""
|
||||
Find the key in a dictionary `d` with the highest index value that matches a given `text`.
|
||||
|
||||
# Arguments
|
||||
- `d<:AbstractDict`
|
||||
The dictionary to search for keys.
|
||||
- `text<:Union{String, Symbol}`
|
||||
The text to match against the keys.
|
||||
|
||||
# Returns
|
||||
- `NamedTuple{(:result, :maxindice), Tuple{Union{Symbol, Nothing}, Union{Integer, Nothing}}}`
|
||||
The key in `d` with the highest index value that matches `text`, or `nothing` if no matches are found.
|
||||
|
||||
# Examples
|
||||
```jldoctest
|
||||
julia> using Revise
|
||||
julia> using GeneralUtils
|
||||
julia> d = Dict(:key_1 => "apple", :key_2 => "banana", :key_3 => "cherry")
|
||||
julia> GeneralUtils.findHighestIndexKey(d, "key")
|
||||
(:key_3, 3)
|
||||
```
|
||||
|
||||
# Signature
|
||||
"""
|
||||
function findHighestIndexKey(d::T, text::Union{String, Symbol}
|
||||
)::NamedTuple{(:result, :maxindice), Tuple{Union{Symbol, Nothing}, Union{Integer, Nothing}}} where {T<:AbstractDict}
|
||||
|
||||
matching_keys = findMatchingDictKey(d, text)
|
||||
|
||||
if isempty(matching_keys)
|
||||
return (result=nothing, maxindice=nothing)
|
||||
elseif length(matching_keys) == 1 && matching_keys[1] == Symbol(text)
|
||||
return (result=Symbol(text), maxindice=nothing)
|
||||
else
|
||||
indices = parse.(Int, replace.(string.(matching_keys), r"[^\d]" => ""))
|
||||
maxIndexKey = matching_keys[argmax(indices)]
|
||||
return (result=maxIndexKey, maxindice=maximum(indices))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
""" Get uuid4 with snake case
|
||||
|
||||
# Return
|
||||
- `uuid4::String`
|
||||
uuid4 with snake case
|
||||
|
||||
# Example
|
||||
```jldoctest
|
||||
julia> using Revise
|
||||
julia> using GeneralUtils
|
||||
julia> GeneralUtils.uuid4snakecase()
|
||||
"0f6e4f_568c_4df4_8c79_1d7a58072f4a"
|
||||
```
|
||||
|
||||
# Signature
|
||||
"""
|
||||
function uuid4snakecase()::String
|
||||
_id = string(uuid4())
|
||||
id = replace(_id, "-" => "_")
|
||||
return id
|
||||
end
|
||||
|
||||
|
||||
""" Replace a dictionary key with the new key
|
||||
|
||||
# Arguments
|
||||
- `d::Dict`
|
||||
The input dictionary that you want to modify
|
||||
- `replacementMap::Dict`
|
||||
A dictionary that maps old keys to new keys
|
||||
|
||||
# Return
|
||||
- `newDict::Dict`
|
||||
new dictionary with the replaced keys
|
||||
|
||||
# Example
|
||||
```jldoctest
|
||||
julia> using Revise
|
||||
julia> using GeneralUtils
|
||||
julia> d = Dict(:a => 1, :b => 2, :c => 3)
|
||||
julia> replacement_map = Dict(:a => :x, :b => :y)
|
||||
julia> new_dict = GeneralUtils.replaceDictKeys(d, replacement_map)
|
||||
Dict{Any, Any} with 3 entries:
|
||||
:y => 2
|
||||
:c => 3
|
||||
:x => 1
|
||||
```
|
||||
|
||||
# Signature
|
||||
"""
|
||||
function replaceDictKeys(d::Dict, replacementMap::Dict)::Dict
|
||||
newDict = Dict()
|
||||
for (key, value) in d
|
||||
newKey = get(replacementMap, key, key) # Get the replacement key if it exists, otherwise keep the original key
|
||||
newDict[newKey] = value
|
||||
end
|
||||
return newDict
|
||||
end
|
||||
|
||||
|
||||
""" Convert text into a dictionary with a given keywords. This function use keywords to slice
|
||||
a given text into the following format: KW1|kw1_text|KW2|kw2_text|KW3|kw3_text.
|
||||
The left most string which has no keyword will be discarded. WARNING, ordering is important
|
||||
|
||||
# Arguments
|
||||
- `text::String`
|
||||
A text to be converted.
|
||||
- `keywords::Vector{String}`
|
||||
A list of keywords to be used to slice the text.
|
||||
These keywords also be the resulting dict keys.
|
||||
# Keyword Arguments
|
||||
- `rightmarker::String`
|
||||
A maker used to make a word to be unique. Ex, A keyword "plan" with rightmarker ":",
|
||||
the function will search for "plan:" otherwise the function will search for "plan".
|
||||
The marker will not be in the resulting dict keys.
|
||||
- `symbolkey::Bool`
|
||||
If true, resulting dict's key will be Symbols, otherwise string.
|
||||
- `lowercasekey::Bool`
|
||||
set resulting dict's key to be lowercase
|
||||
|
||||
# Return
|
||||
- `d::OrderedDict`
|
||||
|
||||
# Example
|
||||
```jldoctest
|
||||
julia> text = "TODAY thought: what to do plan: wake up and going out action: 1. wake up 2. eat 3. sleep"
|
||||
julia> sample_keywords = ["thought", "plan", "action"]
|
||||
julia> resultdict = GeneralUtils.textToDict(text, sample_keywords; rightmarker=":", symbolkey=true)
|
||||
julia> println(resultdict)
|
||||
OrderedCollections.OrderedDict{Any, Any}(:thought => "what to do",
|
||||
:plan => "wake up and going out",
|
||||
:action => "1. wake up 2. eat 3. sleep")
|
||||
```
|
||||
|
||||
# Signature
|
||||
"""
|
||||
function textToDict(text::String, keywords::Vector{String};
|
||||
rightmarker::Union{String, Nothing}=nothing, symbolkey::Bool=false, lowercasekey::Bool=false
|
||||
)::OrderedDict
|
||||
|
||||
od1, od2 =
|
||||
if symbolkey
|
||||
OrderedDict{Symbol, Any}(), OrderedDict{Symbol, Any}()
|
||||
else
|
||||
OrderedDict{String, Any}(), OrderedDict{String, Any}()
|
||||
end
|
||||
|
||||
remainingtext = text
|
||||
|
||||
for keyword in reverse(keywords)
|
||||
mkeyword = rightmarker !== nothing ? keyword * rightmarker : keyword
|
||||
|
||||
# Find the position of the keyword in the text
|
||||
keywordidx = findlast(mkeyword, remainingtext)
|
||||
|
||||
if keywordidx !== nothing
|
||||
substr = remainingtext[keywordidx[end]+1:end]
|
||||
str = string(strip(substr)) # Removes both leading and trailing whitespace.
|
||||
_key = lowercasekey == true ? lowercase(keyword) : keyword
|
||||
key = symbolkey == true ? Symbol(_key) : _key
|
||||
od1[key] = str
|
||||
remainingtext = remainingtext[1:keywordidx[1]-1]
|
||||
else
|
||||
error("""keyword "$keyword" not found in the provided text""")
|
||||
end
|
||||
end
|
||||
|
||||
keywords = lowercasekey == true ? lowercase.(keywords) : keywords
|
||||
|
||||
# correct the order
|
||||
for keyword in keywords
|
||||
key = symbolkey == true ? Symbol(keyword) : keyword
|
||||
od2[key] = od1[key]
|
||||
end
|
||||
|
||||
return od2
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
""" Generate a random string
|
||||
|
||||
# Arguments
|
||||
- `n::Integer`
|
||||
A number of string to be generated
|
||||
|
||||
# Return
|
||||
- `s::String`
|
||||
|
||||
# Example
|
||||
```jldoctest
|
||||
julia> result = randstring(5)
|
||||
"fysmp"
|
||||
```
|
||||
|
||||
# Signature
|
||||
"""
|
||||
randstring(n::Integer)::String = String(rand('a':'z', n))
|
||||
|
||||
|
||||
""" Generate a random string in group
|
||||
|
||||
# Arguments
|
||||
- `totalgroup::Integer`
|
||||
A number of group of random string to be generated
|
||||
- `stringlength::Integer`
|
||||
A number of string to be generated
|
||||
|
||||
# Return
|
||||
- `s::String`
|
||||
|
||||
# Example
|
||||
```jldoctest
|
||||
julia> result = randstrings(3, 5)
|
||||
"fysmp cmhdk iuytr"
|
||||
```
|
||||
|
||||
# Signature
|
||||
"""
|
||||
function randstrings(totalgroup::Integer, stringlength::Integer)::String
|
||||
str = ""
|
||||
for i in 1:totalgroup
|
||||
str *= randstring(stringlength) * " "
|
||||
end
|
||||
str = strip(str)
|
||||
return str
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
end # module util
|
||||
Reference in New Issue
Block a user