Files
GeneralUtils/src/util.jl
narawat lamaiin b3e8df7287 update
2025-07-17 11:48:16 +07:00

1125 lines
28 KiB
Julia
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
module util
export timedifference, showstracktrace, findHighestIndexKey, uuid4snakecase, replaceDictKeys,
findMatchingDictKey, randstring, randstrings, timeout,
dataframeToCSV, dfToVectorDict, disintegrate_vectorDict, getDataFrameValue, dfRowtoString,
dfToString, dataframe_to_json_list, dictToString, dictToString_noKey, issomething,
dictToString_numbering, extract_triple_backtick_text,
countGivenWords, remove_french_accents,
extractTextBetweenCharacter, extractTextBetweenString,
convertCamelSnakeKebabCase, fitrange, recentElementsIndex, nonRecentElementsIndex
using JSON3, DataStructures, Distributions, Random, Dates, UUIDs, MQTTClient, DataFrames
# ---------------------------------------------- 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)
# Check the unit and calculate the time difference accordingly
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
""" 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
""" Execute a function with timer.
# Arguments
- `f::Function`
a function to run
- `timeoutwindow::Integer``
timeout in seconds
# Keyword Argument
- `fargs`
arguments for the function
- `timeoutmsg::String`
time out message
# Return
- task result otherwise timeout message
# Example
```jldoctest
julia> function testfunc(x)
sleep(x)
return "task done"
end
julia> result = timeout(testfunc, 10; fargs=20)
"task timed out"
julia> result = timeout(testfunc, 20; fargs=10)
"task done"
```
# Signature
"""
function timeout(f::Function, timeoutwindow::Integer; fargs=nothing, timeoutmsg="task timed out")
tsk = @task f(fargs)
schedule(tsk)
Timer(timeoutwindow) do timer
istaskdone(tsk) || Base.throwto(tsk, InterruptException())
end
try
fetch(tsk)
catch _;
timeoutmsg
end
end
""" Convert a dataframe into CSV.
# Arguments
- `df::DataFrame`
A connection object to Postgres database
# Return
- `result::String`
# Example
```jldoctest
julia> using DataFrames, GeneralUtils
julia> df = DataFrame(A=1:3, B=5:7, fixed=1)
julia> result = GeneralUtils.dataframeToCSV(df)
```
# Signature
"""
function dataframeToCSV(df::DataFrame)
# Create an IOBuffer to capture the output
io = IOBuffer()
CSV.write(io, df)
dfStr = String(take!(io))
return dfStr
end
""" Convert a DataFrame into a list of Dict rows.
# Arguments
- `df::DataFrame`
The input DataFrame to be converted.
# Return
- `rows::Vector{Dict{String, Any}}`
A vector of dictionaries, where each dictionary represents a row in a dataframe.
# Example
```jldoctest
julia> using DataFrames, JSON3, GeneralUtils
julia> df = DataFrame(A = [1, 2, 3], B = ["apple", "banana", "cherry"])
julia> vectorDict = GeneralUtils.dfToVectorDict(df)
[Dict{String, Any}("B" => "apple", "A" => 1),
Dict{String, Any}("B" => "banana", "A" => 2)
Dict{String, Any}("B" => "cherry", "A" => 3)]
```
# Signature
"""
function dfToVectorDict(df::DataFrame)
vec = []
for row in eachrow(df)
d = DataStructures.OrderedDict{String, Any}()
for col in names(df)
d[col] = row[col]
end
push!(vec, d)
end
return vec
end
""" Turn a large vector of dictionaries into smaller one
# Arguments
- `data`
data to be partioning
- `partsize`
how many dicts per part
# Return
- `parts`
a dictionay of parts
# Example
```jldoctest
julia> using GeneralUtils, Dates, JSON3, UUIDs
julia> vecDict = [Dict("a" => i) for i in 1:10]
julia> d = GeneralUtils.disintegrate_vectorDict(vecDict, 3)
julia> println(d[:data])
Dict{Int64, Vector{Dict}} with 4 entries:
1 => [Dict("a"=>1), Dict("a"=>2), Dict("a"=>3)]
2 => [Dict("a"=>4), Dict("a"=>5), Dict("a"=>6)]
3 => [Dict("a"=>7), Dict("a"=>8), Dict("a"=>9)]
4 => [Dict("a"=>10)]
```
# Signature
"""
function disintegrate_vectorDict(data::Vector, partsize::Integer
)
println("--> disintegrate_vectorDict()")
parts = Dict{Int, Vector{Dict}}()
for (i, dict) in enumerate(data)
# println("--> disintegrate_vectorDict ", i)
partkey = (i - 1) ÷ partsize + 1
if !haskey(parts, partkey)
parts[partkey] = Vector{Dict}()
end
push!(parts[partkey], dict)
end
return (datatype="vector{Dict}", totalparts=length(parts), partsize=partsize, dataparts=parts)
end
""" Get a value from a DataFrame row by a given key
# Arguments
- `row::DataFrameRow`
The DataFrame row to retrieve the value from.
- `key::Symbol`
The column name (as a symbol) whose value is to be retrieved.
# Return
- `Any`
The value of the specified column in the given row.
# Example
```jldoctest
julia> using DataFrames
julia> df = DataFrame(name=["Alice", "Bob"], age=[25, 30])
2×2 DataFrame
Row │ name age
│ String Int64
┌─────┼─────────┼───────
│ 1 │ Alice 25
│ 2 │ Bob 30
julia> getDataFrameValue(df[1, :], :name)
"Alice"
```
# Signature
"""
getDataFrameValue(row::DataFrameRow, key::Symbol) = row.:($key)
""" Convert a DataFrame row to a key:value string
# Arguments
- `row::DataFrameRow`
The DataFrame row to convert.
# Return
- `String`
A string containing the formatted representation of the row, with each column prefixed by its name and separated by commas.
# Example
```jldoctest
julia> using DataFrames
julia> df = DataFrame(name=["Alice", "Bob"], age=[25, 30])
2×2 DataFrame
Row │ name age
│ String Int64
┌─────┼─────────┼───────
│ 1 │ Alice 25
│ 2 │ Bob 30
julia> dfRowtoString(df[1, :])
"name: Alice, age: 25"
```
# Signature
"""
function dfRowtoString(row::DataFrameRow)::String
str = ""
for key in keys(row)
value = getDataFrameValue(row, key)
str *= "$key: $value, "
end
result = str[1:end-2] # remove ", " at the end of row
return result
end
""" Convert a DataFrame to a string representation
# Arguments
- `df::DataFrame`
The DataFrame to convert, where each row will be converted to a string.
# Return
- `String`
A string containing the formatted representation of the DataFrame, with each row prefixed by its index and separated by newlines.
# Example
```jldoctest
julia> using DataFrames
julia> df = DataFrame(name=["Alice", "Bob"], age=[25, 30])
2×2 DataFrame
Row │ name age
│ String Int64
┌─────┼─────────┼───────
│ 1 │ Alice 25
│ 2 │ Bob 30
julia> dfToString(df)
"1) name: Alice, age: 25\n2) name: Bob, age: 30"
```
# Signature
"""
function dfToString(df::DataFrame)
dfstr = ""
for (i, row) in enumerate(eachrow(df))
rowstr = dfRowtoString(row)
dfstr *= "$i) $rowstr\n"
end
return dfstr
end
""" Convert a DataFrame to a list of JSON strings
# Arguments
- `df::DataFrame`
The DataFrame to convert, where each row will be converted to a JSON string.
# Return
- `Vector{String}`
A vector containing the JSON representation of each row in the DataFrame.
# Example
```jldoctest
julia> using DataFrames
julia> df = DataFrame(name=["Alice", "Bob"], age=[25, 30])
2×2 DataFrame
Row │ name age
│ String Int64
┌─────┼─────────┼───────
│ 1 │ Alice 25
│ 2 │ Bob 30
julia> dataframe_to_json_list(df)
2-element Vector{String}:
"{\"name\":\"Alice\",\"age\":25}"
"{\"name\":\"Bob\",\"age\":30}"
```
# Signature
"""
function dataframe_to_json_list(df::DataFrame)::Vector{String}
json_list = []
for row in eachrow(df)
json_row = Dict(zip(names(df), row))
push!(json_list, JSON.json(json_row))
end
return json_list
end
""" Convert a dictionary to a string representation.
# Arguments
- `od::OrderedDict`
The OrderedDict to convert, where each key-value pair will be represented as "index) key: value".
# Return
- `String`
A string containing the representation of each key-value pair in the OrderedDict.
# Example
```jldoctest
julia> using DataStructures
julia> od = OrderedDict("name" => "Alice", "age" => 25)
OrderedDict{String,Any} with 2 entries:
"name" => "Alice"
"age" => 25
julia> dict_to_string(od)
"1) name: Alice, 2) age: 25"
```
# Signature
"""
function dictToString(od::T) where {T<:AbstractDict}
items = []
for (i, (key, value)) in enumerate(od)
push!(items, "$key: $value")
end
return join(items, ", ")
end
function dictToString_numbering(od::T) where {T<:AbstractDict}
items = []
for (i, (key, value)) in enumerate(od)
push!(items, "$i) $key: $value")
end
return join(items, ", ")
end
function dictToString_noKey(od::T) where {T<:AbstractDict}
items = []
for (i, (key, value)) in enumerate(od)
push!(items, "$value")
end
return join(items, ", ")
end
"""
extract_triple_backtick_text(text::String) -> Vector{String}
Extracts text enclosed within triple backticks (```) from the given string.
# Arguments:
- `text::String` The input string containing potential triple backtick blocks.
# Returns:
- `Vector{String}` A vector of strings, each representing a block of text enclosed within triple backticks found in the input string.
# Examples:
```jldoctest
julia> extract_triple_backtick_text("Here is some text ```with a code block``` and more text.")
1-element Vector{String}:
"with a code block"
"""
function extract_triple_backtick_text(input::String)::Vector{String}
# Regular expression to match text wrapped by triple backticks
regex = r"```([\s\S]*?)```"
# Find all matches in the input string
matches = collect(eachmatch(regex, input))
# Extract the matched text (excluding the backticks)
extracted_text = [m.captures[1] for m in matches]
return extracted_text
end
wordwindow(word::String, startindex::Integer)::UnitRange = startindex:startindex + length(word) -1
function cuttext(range, text)
# check whether range is outside text boundary
if range.start > length(text) || range.stop > length(text)
return nothing
else
return text[range]
end
end
"""
countGivenWords(text::String, words::Vector{String}) -> Dict{String, Int}
Count the occurrences of each word in the given list within the provided text.
# Arguments
- `text::String`: The input text to search through.
- `words::Vector{String}` A vector of words whose occurrences need to be counted.
# Returns
- `Vector{Int64}` Their respective counts in the `text`.
# Examples
```jldoctest
julia> GeneralUtils.countGivenWords("hello world hello", ["hello", "world"])
2-element Vector{Int64}:
2
1
julia> GeneralUtils.countGivenWords("foo bar baz foo", ["foo", "qux"])
2-element Vector{Int64}:
2
0
```
# Signature
"""
function countGivenWords(text::String, words::Vector{String})::Vector{Int}
count = []
# loop through each word in words
for word in words
# initialize a counter for the current word
splittext = split(text, word)
splittext_length = length(splittext)
thisWordCount = splittext_length - 1
push!(count, thisWordCount)
end
return count
end
"""
remove_french_accents(text::String) -> String
Remove French accents from the given text.
# Arguments
- `text::String` The input string containing French accents.
# Returns
- `String` The input string with all French accents removed.
# Examples
```jldoctest
julia> remove_french_accents("Café")
"Cafe"
julia> remove_french_accents("L'été est beau.")
"L'ete est beau."
```
# Signature
"""
function remove_french_accents(text::AbstractString)::AbstractString
textcharlist = [i for i in text]
# Create a dictionary to map accented characters to their replacements
accented_to_regular = Dict(
'à' => 'a', 'â' => 'a', 'ä' => 'a', 'á' => 'a',
'é' => 'e', 'è' => 'e', 'ê' => 'e', 'ë' => 'e',
'î' => 'i', 'ï' => 'i', 'í' => 'i',
'ñ' => 'n',
'ô' => 'o', 'ö' => 'o', 'ò' => 'o', 'ó' => 'o',
'ù' => 'u', 'û' => 'u', 'ü' => 'u',
'ÿ' => 'y',
'ç' => 'c',
'Ä' => 'A',
'É' => 'E',
'Ö' => 'O',
'Ü' => 'U',
'' => ''',
)
accentedchar = keys(accented_to_regular)
# Replace accented characters in the text using accented_to_regular dictionary above
for (i, char) in enumerate(textcharlist)
if char accentedchar
textcharlist[i] = accented_to_regular[char]
end
end
cleaned_text = join(textcharlist)
return cleaned_text
end
"""
Extracts and returns the text that is enclosed between two specified characters within a given string.
# Arguments
- `text::String` The input string from which to extract the text.
- `startchar::Char` The starting character that marks the beginning of the desired text.
- `endchar::Char` The ending character that marks the end of the desired text.
# Returns
- `String` The substring enclosed between `start_char` and `end_char`.
# Examples
```jldoctest
julia> text = "Hello [World]! [Yay]"
julia> extracted_text = extractTextBetweenCharacter(text, '[', ']')
2-element Vector{Any}:
"World"
"Yay"
```
"""
function extractTextBetweenCharacter(text::String, startchar::Char, endchar::Char)
result = []
start_index = 0
in_braces = false
for (i, c) in enumerate(text)
if c == startchar
start_index = i + 1
in_braces = true
elseif c == endchar
if in_braces
push!(result, text[start_index:i-1])
in_braces = false
end
end
end
return result
end
function extractTextBetweenString(text::String, startstr::String, endstr::String)
# check whether startstr is in the text or not
isStartStr = split(text, startstr)
if length(isStartStr) > 2
return (success=false, error="There are more than one occurrences of the start string '$startstr' in the text. Text must has only one start string", errorcode=2, result=nothing)
elseif length(isStartStr) == 1
return (success=false, error="There are no start string '$startstr' in the text. Text must has only one start string", errorcode=1, result=nothing)
end
# check whether endstr is in the text or not
isEndStr = split(text, endstr)
if length(isEndStr) > 2
return (success=false, error="There are more than one occurrences of the end string '$endstr' in the text. Text must has only one end string", errorcode=3, result=nothing)
elseif length(isStartStr) == 1
return (success=false, error="There are no end string '$endstr' in the text. Text must has only one end string", errorcode=4, result=nothing)
end
s = string(split(isStartStr[2], endstr)[1])
return (success=true, error=nothing, errorcode=0, text=s)
end
"""
Determines if the given string follows camel case naming convention.
# Arguments:
- `text::String` The input string to check for camel case.
# Returns:
- `Bool` True if the string is in camel case, False otherwise.
# Examples:
```jldoctest
julia> isCamelCase("helloWorld")
true
julia> isCamelCase("HelloWorld")
false
julia> isCamelCase("hello_world")
false
```
"""
function isCamelCase(text::String)
# Regular expression to match camel case
pattern = r"^[a-z]+(?:[A-Z][a-z]*)*$"
return occursin(pattern, text)
end
"""
Splits a string at the boundaries of camel case words.
# Arguments
- `text::String` The input string to be split.
# Returns
- `Vector{String}` A vector containing the individual words from the camel case string.
# Examples
```jldoctest
julia> text = "splitCamelCaseFunction"
julia> words = splitCamelCase(text)
println(words) # Output: ["split", "Camel", "Case", "Function"]
```
"""
function splitCamelCase(text::String)
# Regular expression to match the boundaries of camel case words
# split_pattern = r"(?<=.)(?=[A-Z])"
split_pattern = r"(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])"
result = split(text, split_pattern)
return result
end
"""
Converts a string between Camel Case, Snake Case, and Kebab Case.
# Arguments
- `text::String` The input string to be converted.
- `tocase::Symbol` The target case format. Can be one of :camel, :snake, or :kebab.
# Returns
- `String` The converted string in the specified case format.
# Examples
```jldoctest
julia> text = "splitCamelCaseFunction"
julia> converted_text = convertCamelSnakeKebabCase(text, :snake)
println(converted_text) # Output: "split_camel_case_function"
julia> converted_text = convertCamelSnakeKebabCase(text, :kebab)
println(converted_text) # Output: "split-camel-case-function"
julia> converted_text = convertCamelSnakeKebabCase(text, :camel)
println(converted_text) # Output: "splitCamelCaseFunction"
```
"""
function convertCamelSnakeKebabCase(text::T, tocase::Symbol)::String where {T<:AbstractString}
# Check the current case format of the input text
iscamel = isCamelCase(text)
issnake = occursin('_', text) # Check for snake case by looking for underscores
iskebab = occursin('-', text) # Check for kebab case by looking for hyphens
if iscamel
# Handle camel case input
wordlist = splitCamelCase(text)
if tocase == :camel
return text # Already in camel case, return as is
elseif tocase == :snake
wordlist = lowercase.(wordlist) # Convert all words to lowercase
return join(wordlist, '_') # Join with underscores for snake case
elseif tocase == :kebab
wordlist = lowercase.(wordlist) # Convert all words to lowercase
return join(wordlist, '-') # Join with hyphens for kebab case
end
elseif issnake
# Handle snake case input
wordlist = split(text, '_') # Split at underscores
if tocase == :camel
wordlist = lowercase.(wordlist)
wordlist = uppercasefirst.(wordlist) # Capitalize first letter of each word
wordlist[1] = lowercase(wordlist[1]) # First word should start with lowercase
return join(wordlist) # Join without separator for camel case
elseif tocase == :snake
return text # Already in snake case, return as is
elseif tocase == :kebab
wordlist = lowercase.(wordlist) # Convert all words to lowercase
return join(wordlist, '-') # Join with hyphens for kebab case
end
elseif iskebab
# Handle kebab case input
wordlist = split(text, '-') # Split at hyphens
if tocase == :camel
wordlist = lowercase.(wordlist)
wordlist = uppercasefirst.(wordlist) # Capitalize first letter of each word
wordlist[1] = lowercase(wordlist[1]) # First word should start with lowercase
return join(wordlist) # Join without separator for camel case
elseif tocase == :snake
wordlist = lowercase.(wordlist) # Convert all words to lowercase
return join(wordlist, '_') # Join with underscores for snake case
elseif tocase == :kebab
return text # Already in kebab case, return as is
end
else
error("Undefined condition") # Input text format not recognized
end
end
""" Check if a value is not `nothing`.
# Arguments
- `x`: The value to check
# Returns
- `Bool`: `true` if `x` is not `nothing`, `false` otherwise
# Examples
```jldoctest
julia> issomething(1)
true
julia> issomething(nothing)
false
julia> issomething("test")
true
````
"""
function issomething(x)
return x === nothing ? false : true
end
""" Adjust a given range to fit within the bounds of a vector's length.
# Arguments
- `v::T1`
the input vector to check against
- `range::UnitRange`
the original range to be adjusted
# Return
- `adjusted_range::UnitRange`
a range that is constrained to the vector's length, preventing out-of-bounds indexing
# Example
julia> v = [1, 2, 3, 4, 5]
julia> fitrange(v, 3:10)
3:5
"""
function fitrange(v::T1, range::UnitRange) where {T1<:AbstractVector}
totalelements = length(v)
startind =
# check if user put start range greater than total event
if range.start > totalelements
totalelements
else
range.start
end
stopind =
if range.stop > totalelements
totalelements
else
range.stop
end
return startind:stopind
end
""" Find a unit range for a vector given a number of the most recent elements of interest.
# Arguments
- `vectorLength::Integer`
the length of the vector to generate range from
- `n::Integer`
the number of most recent elements to include in range
# Return
- `UnitRange`
a range representing the n most recent elements of a vector with length vectorLength
# Example
```jldoctest
julia> a = [1, 2, 3, 4, 5]
julia> recentElementsIndex(length(a), 3)
3:5
julia> recentElementsIndex(length(a), 0)
5:5
```
"""
function recentElementsIndex(vectorlength::Integer, n::Integer; includelatest::Bool=false)
if n == 0
error("n must be greater than 0")
end
if includelatest
start = max(1, vectorlength - n + 1)
return start:vectorlength
else
startind = max(1, vectorlength - n)
endind = vectorlength -1
return startind:endind
end
end
""" Find a unit range for a vector excluding the most recent elements.
# Arguments
- `vectorlength::Integer`
the length of the vector to generate range from
- `n::Integer`
the number of most recent elements to exclude from range
# Return
- `UnitRange`
a range representing the elements of the vector excluding the last `n` elements
# Example
```jldoctest
julia> a = [1, 2, 3, 4, 5]
julia> nonRecentElementsIndex(length(a), 3)
1:2
julia> nonRecentElementsIndex(length(a), 1)
1:4
julia> nonRecentElementsIndex(length(a), 0)
1:5
```
"""
function nonRecentElementsIndex(vectorlength::Integer, n::Integer)
if n < 0
error("n must be non-negative")
end
if n > vectorlength
return 1:0 # empty range
end
return 1:(vectorlength-n)
end
end # module util