Compare commits
84 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c51dfc549c | |||
| f0ad6a3e48 | |||
| c829bf65f6 | |||
| b09efc9068 | |||
| 6fb2d5f82b | |||
| 55cc0f78c9 | |||
| 73ec3bbb04 | |||
| 1ad46c6e18 | |||
| 95954249ce | |||
| a15630619a | |||
| f28405f3f1 | |||
| d658d9a25b | |||
| edad442242 | |||
| c56fc7366c | |||
| c4eeb99aba | |||
| bd5022c8bc | |||
| db84b1c398 | |||
| f8f8410259 | |||
| 956adf0b93 | |||
| 0f2a33bcdd | |||
| b8f84846bb | |||
| adf6264061 | |||
| 08f19f17a2 | |||
| 8a4e882dc1 | |||
| fb7942a965 | |||
| e54454b099 | |||
| dac98ab38c | |||
| 1e8149aa6f | |||
| 8f12c29a78 | |||
| e3d09e6ebd | |||
| f33f4f0790 | |||
| fcf2044dd9 | |||
| 05d8cb9c02 | |||
| 13de2f90ff | |||
| 22fe810f63 | |||
| abdf6cf3b8 | |||
| f2ba243df0 | |||
| bb2851332a | |||
| 00225f3a06 | |||
| 7cb0bd077f | |||
| 0ba2aa310e | |||
| 1916668c6e | |||
| 919800da42 | |||
| 947580a2ec | |||
| 688b9a22b6 | |||
| 76ce0fc54f | |||
| b8bd06f386 | |||
| e08b6ab54d | |||
| 830e9bcc5f | |||
| 52d991bbf3 | |||
| 35c2b4c211 | |||
| 170b0bad15 | |||
| fbedd507fc | |||
| 0e36b8db90 | |||
| 13fcf06503 | |||
| 066d72553f | |||
| b3e8df7287 | |||
| c5f3fda2ba | |||
| adab61dca8 | |||
| 09615a6909 | |||
| 92c5930e9a | |||
| 5b4c1c1471 | |||
| fc3edd7b8f | |||
| 93aa0ee1ac | |||
| 42378714a0 | |||
| 759f022c98 | |||
| 5af4d481f2 | |||
| 221bb5beb7 | |||
| 5a89e86120 | |||
| e351a92680 | |||
| 83cd0cfea3 | |||
| 9e29f611df | |||
| d8ea4b70a9 | |||
| 150ddac2c0 | |||
| 5108ad1f6b | |||
| 14766ae171 | |||
| ccd91a7b6f | |||
| a894ad85ba | |||
| 1da05f5cae | |||
| 562f528c01 | |||
| 840b0e6205 | |||
| cb4d01c612 | |||
| e6344f1a92 | |||
| 3082c261c7 |
+594
-136
File diff suppressed because it is too large
Load Diff
+17
-3
@@ -1,7 +1,7 @@
|
|||||||
name = "GeneralUtils"
|
name = "GeneralUtils"
|
||||||
uuid = "c6c72f09-b708-4ac8-ac7c-2084d70108fe"
|
uuid = "c6c72f09-b708-4ac8-ac7c-2084d70108fe"
|
||||||
|
version = "0.5.0"
|
||||||
authors = ["tonaerospace <tonaerospace.etc@gmail.com>"]
|
authors = ["tonaerospace <tonaerospace.etc@gmail.com>"]
|
||||||
version = "0.2.2"
|
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
|
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
|
||||||
@@ -9,9 +9,23 @@ DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
|
|||||||
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
|
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
|
||||||
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
|
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
|
||||||
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
|
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
|
||||||
JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
|
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
|
||||||
MQTTClient = "985f35cc-2c3d-4943-b8c1-f0931d5f0959"
|
HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3"
|
||||||
|
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
|
||||||
|
LibPQ = "194296ae-ab2e-5f79-8cd4-7183a0a5a0d1"
|
||||||
|
NATS = "55e73f9c-eeeb-467f-b4cc-a633fde63d2a"
|
||||||
PrettyPrinting = "54e16d92-306c-5ea0-a30b-337be88ac337"
|
PrettyPrinting = "54e16d92-306c-5ea0-a30b-337be88ac337"
|
||||||
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
|
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
|
||||||
|
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
|
||||||
SHA = "ea8e919c-243c-51af-8825-aaa63cd721ce"
|
SHA = "ea8e919c-243c-51af-8825-aaa63cd721ce"
|
||||||
|
StringDistances = "88034a9c-02f8-509d-84a9-84ec65e18404"
|
||||||
UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
|
UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
|
||||||
|
|
||||||
|
[compat]
|
||||||
|
Graphs = "1.14.0"
|
||||||
|
HTTP = "2.5.0 - 2.9.9"
|
||||||
|
JSON = "1.3.0 - 1.9.9"
|
||||||
|
LibPQ = "1.18.0"
|
||||||
|
NATS = "0.1.0"
|
||||||
|
Revise = "3.13.2"
|
||||||
|
StringDistances = "1.0.0"
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
Todo:
|
||||||
|
- [WORKING] update with JSON
|
||||||
|
|
||||||
|
Change from previous version:
|
||||||
|
- replace JSON3 with JSON
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
|
||||||
|
using NATS, JSON3
|
||||||
|
connection = NATS.connect("nats.yiem.cc:4222")
|
||||||
|
sub1 = NATS.reply(connection, "some_subject"; queue_group="group1") do msg
|
||||||
|
payload = copy(JSON3.read(msg.payload))
|
||||||
|
println(payload)
|
||||||
|
println(msg.reply_to)
|
||||||
|
# publish(connection, msg.reply_to, "ACK")
|
||||||
|
return JSON3.write(Dict(:a=>"wassup"))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
using NATS, JSON3, GeneralUtils
|
||||||
|
connection = NATS.connect("nats.yiem.cc:4222")
|
||||||
|
|
||||||
|
msgMeta = GeneralUtils.generate_msgMeta(
|
||||||
|
"text2textinstruct_medium.inference.api.v1";
|
||||||
|
msgPurpose= "inference",
|
||||||
|
senderName= "yiemagent",
|
||||||
|
senderId= GeneralUtils.uuid4snakecase(),
|
||||||
|
receiverName= "text2textinstruct",
|
||||||
|
)
|
||||||
|
|
||||||
|
llmHttpTimeout = 60
|
||||||
|
outgoingMsg = Dict(
|
||||||
|
:msgMeta=> msgMeta,
|
||||||
|
:payload=> Dict(
|
||||||
|
:text=> "Wassup buddy!",
|
||||||
|
:kwargs=> Dict(
|
||||||
|
:max_tokens=> 2048,
|
||||||
|
:stop=> ["<|im_end|>"],
|
||||||
|
:temperature=> 0.2,
|
||||||
|
),
|
||||||
|
:llmHttpTimeout=>llmHttpTimeout,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
r = NATS.request(String, connection, "text2textinstruct_medium.inference.api.v1",
|
||||||
|
JSON3.write(outgoingMsg); timer=Timer(llmHttpTimeout))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
using NATS, JSON3, GeneralUtils
|
||||||
|
connection = NATS.connect("nats.yiem.cc:4222")
|
||||||
|
|
||||||
|
msgMeta = GeneralUtils.generate_msgMeta(
|
||||||
|
"tonpc.containerServices",
|
||||||
|
msgPurpose="reset container",
|
||||||
|
senderName= "",
|
||||||
|
)
|
||||||
|
|
||||||
|
outgoingMsg = Dict(
|
||||||
|
:msgMeta=> msgMeta,
|
||||||
|
:payload=> "docker container restart ollama-instance-2",
|
||||||
|
)
|
||||||
|
|
||||||
|
# may be I can't use NATS request inside NATS reply??
|
||||||
|
r = NATS.request(String, connection, msgMeta[:sendTopic], JSON3.write(outgoingMsg); timer=Timer(10))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+1
-10
@@ -2,7 +2,7 @@ module GeneralUtils
|
|||||||
|
|
||||||
|
|
||||||
export # struct
|
export # struct
|
||||||
mqttClientInstance,
|
# mqttClientInstance,
|
||||||
# function
|
# function
|
||||||
noNegative!, randomWithProb, randomChoiceWithProb, findIndex, limitvalue
|
noNegative!, randomWithProb, randomChoiceWithProb, findIndex, limitvalue
|
||||||
|
|
||||||
@@ -24,16 +24,7 @@ using .interface
|
|||||||
|
|
||||||
#------------------------------------------------------------------------------------------------100
|
#------------------------------------------------------------------------------------------------100
|
||||||
|
|
||||||
""" version 0.0.4
|
|
||||||
Todo:
|
|
||||||
- [*1] cartesianAssign for different matrix dimension
|
|
||||||
|
|
||||||
Change from version: 0.0.3
|
|
||||||
-
|
|
||||||
|
|
||||||
All features
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+743
-707
File diff suppressed because it is too large
Load Diff
+167
-137
@@ -2,13 +2,45 @@ module dbUtil
|
|||||||
|
|
||||||
export dictToPostgresKeyValueString, generateInsertSQL, generateUpdateSQL
|
export dictToPostgresKeyValueString, generateInsertSQL, generateUpdateSQL
|
||||||
|
|
||||||
using JSON3, DataStructures, Distributions, Random, Dates, UUIDs, MQTTClient, DataFrames,
|
using JSON, DataStructures, Distributions, Random, Dates, UUIDs, DataFrames,
|
||||||
SHA
|
SHA
|
||||||
using ..util
|
using ..util
|
||||||
|
#[PENDING] update code to use JSON
|
||||||
# ---------------------------------------------- 100 --------------------------------------------- #
|
# ---------------------------------------------- 100 --------------------------------------------- #
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
dictToPostgresKeyValueString - Convert dictionary to PostgreSQL key-value string format
|
||||||
|
|
||||||
|
This function takes a dictionary and converts it into a PostgreSQL-compatible key-value string
|
||||||
|
format suitable for storage in a TEXT field. The output format uses curly braces with comma-separated
|
||||||
|
key-value pairs, where string values are quoted.
|
||||||
|
|
||||||
|
# Function Workflow:
|
||||||
|
1. Iterates through dictionary key-value pairs
|
||||||
|
2. Handles nested dictionaries by recursively converting them
|
||||||
|
3. Wraps string values in double quotes
|
||||||
|
4. Formats numeric and other values without quotes
|
||||||
|
5. Returns a PostgreSQL-compatible key-value string enclosed in curly braces
|
||||||
|
|
||||||
|
# Arguments:
|
||||||
|
- `dict::Dict` - Dictionary containing key-value pairs to convert
|
||||||
|
|
||||||
|
# Return:
|
||||||
|
- A String in PostgreSQL key-value format: "{key1: value1, key2: \"value2\", ...}"
|
||||||
|
|
||||||
|
# Example
|
||||||
|
```jldoctest
|
||||||
|
julia> data = Dict{String, Any}(
|
||||||
|
"name" => "John",
|
||||||
|
"age" => 30,
|
||||||
|
"city" => "New York"
|
||||||
|
);
|
||||||
|
|
||||||
|
julia> dictToPostgresKeyValueString(data)
|
||||||
|
"{\"name\": \"John\", \"age\": 30, \"city\": \"New York\"}"
|
||||||
|
```
|
||||||
|
"""
|
||||||
function dictToPostgresKeyValueString(dict)
|
function dictToPostgresKeyValueString(dict)
|
||||||
parts = []
|
parts = []
|
||||||
for (k, v) in dict
|
for (k, v) in dict
|
||||||
@@ -26,61 +58,71 @@ end
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
""" Get characters between specified characters.
|
""" generateInsertSQL - Generate SQL INSERT statement from dictionary data
|
||||||
|
|
||||||
# Arguments
|
This function constructs a SQL INSERT statement by extracting values for specified columns
|
||||||
- `text::T`
|
from a dictionary and formatting them into a valid PostgreSQL INSERT query.
|
||||||
a text being searched
|
|
||||||
- `startChar::Char`
|
# Function Workflow:
|
||||||
start character
|
1. Iterates through the dictionary key-value pairs
|
||||||
- `endChar::Char`
|
2. Filters keys to only include those present in `columnToInsert`
|
||||||
end character
|
3. Collects column names and their corresponding values
|
||||||
# Keyword Arguments
|
4. Constructs the final SQL INSERT statement
|
||||||
- `endCharLocation::String`
|
|
||||||
end character position after startChar. Can be "next" or "end". "next" means the closed
|
# Arguments:
|
||||||
endChar just after startChar. "end" means the furthest endChar.
|
- `table_name::String` - Name of the database table to insert into
|
||||||
- `includeChar::Bool`
|
- `columnToInsert::Vector{Symbol}` - List of column names to include in the INSERT statement
|
||||||
whether to include the startChar and endChar. Default is true
|
- `data::Dict{Symbol, Any}` - Dictionary containing column-value pairs for the insert
|
||||||
# Return
|
|
||||||
the characters between specified characters.
|
# Return:
|
||||||
|
- A String containing the SQL INSERT statement
|
||||||
|
|
||||||
# Example
|
# Example
|
||||||
```jldoctest
|
```jldoctest
|
||||||
julia> using Revise
|
julia> using UUIDs
|
||||||
julia> using GeneralUtils
|
|
||||||
julia> insert_data = Dict(
|
|
||||||
:grape => "NA",
|
|
||||||
:acidity => "0",
|
|
||||||
:tannin => "0",
|
|
||||||
:country => "NA",
|
|
||||||
:description => "NA",
|
|
||||||
:region => "NA",
|
|
||||||
:winery => "ccc",
|
|
||||||
:intensity => "0",
|
|
||||||
:sweetness => "0",
|
|
||||||
:tasting_notes => "NA",
|
|
||||||
:wine_name => "new_wine",
|
|
||||||
:wine_id => "9e1deb6a-d57f-4d2c-abbe-da813f4e91ad",
|
|
||||||
:wine_type => "NA",
|
|
||||||
:other_attributes => "{\"attribute3\":{\"attribute5\":666,\"attribute4\":\"text\"},\"attribute1\":\"hello world\",\"attribute2\":555}",
|
|
||||||
:fizziness => "0",
|
|
||||||
:serving_temperature => "0",
|
|
||||||
:additional_search_term => "{NA1,NA2}")
|
|
||||||
```
|
|
||||||
# TODO
|
|
||||||
- [] update docs
|
|
||||||
|
|
||||||
# Signature
|
# Insert a single record with specific columns
|
||||||
|
table_name = "wine"
|
||||||
|
columnToInsert = [:acidity, :tannin, :country, :region, :winery]
|
||||||
|
data = Dict{Symbol, Any}(
|
||||||
|
:grape => "Cabernet Sauvignon",
|
||||||
|
:acidity => "medium", # using descriptive scale (low/medium/full)
|
||||||
|
:tannin => "medium-plus", # common wine descriptor
|
||||||
|
:country => "France",
|
||||||
|
:description => "A rich and structured red wine with notes of blackcurrant, cedar, and subtle oak.",
|
||||||
|
:region => "Bordeaux",
|
||||||
|
:winery => "Château Margaux",
|
||||||
|
:intensity => "medium", # intensity is usually low/medium/full
|
||||||
|
:sweetness => "dry", # dry/medium-dry/medium/medium-sweet/sweet
|
||||||
|
:tasting_notes => "Blackberry, graphite, tobacco, vanilla, and subtle earth.",
|
||||||
|
:wine_name => "Château Margaux Grand Cru",
|
||||||
|
:wine_id => "8f3c7a2e-1b4d-4a9f-9c2e-4a8b3d6e5f7a", # UUID-like (valid hex)
|
||||||
|
:wine_type => "Red",
|
||||||
|
:other_attributes => Dict{String, Any}(
|
||||||
|
"vintage" => 2018,
|
||||||
|
"alcohol_percent" => 13.5,
|
||||||
|
"ph" => 3.6,
|
||||||
|
" aging_years" => 24, # years in barrel
|
||||||
|
" producer_code" => "CM-GRAND"
|
||||||
|
),
|
||||||
|
:fizziness => "still",
|
||||||
|
:serving_temperature => "16–18°C",
|
||||||
|
:additional_search_term => ["Cabernet", "Bordeaux red", "premium wine", "CabSav"]
|
||||||
|
)
|
||||||
|
|
||||||
|
julia> generateInsertSQL(table_name, columnToInsert, data)
|
||||||
|
"INSERT INTO wine (acidity, tannin, country, region, winery) VALUES ('medium', 'medium-plus', 'France', 'Bordeaux', 'Château Margaux');"
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
function generateInsertSQL(table_name::String, columnToInsert::Vector{Symbol},
|
function generateInsertSQL(table_name::String, columnToInsert::Vector{Symbol}, data::Dict{Symbol, Any})
|
||||||
insert_data::Dict{Symbol, Any})
|
|
||||||
columns = String[]
|
columns = String[]
|
||||||
values = String[]
|
values = String[]
|
||||||
|
|
||||||
for (key, value) in insert_data
|
for (key, value) in data
|
||||||
if key ∈ columnToInsert
|
if key ∈ columnToInsert
|
||||||
push!(columns, string(key))
|
push!(columns, string(key))
|
||||||
push!(values, "'$value'") #[] number should not wrapped in ''
|
value_str = isa(value, AbstractString) ? "'$value'" : "$value"
|
||||||
|
push!(values, value_str)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -89,113 +131,101 @@ function generateInsertSQL(table_name::String, columnToInsert::Vector{Symbol},
|
|||||||
|
|
||||||
return "INSERT INTO $table_name ($columns_str) VALUES ($values_str);"
|
return "INSERT INTO $table_name ($columns_str) VALUES ($values_str);"
|
||||||
end
|
end
|
||||||
# function generateInsertSQL(table_name::String, insert_data::Dict{Symbol, Any})
|
|
||||||
# columns = String[]
|
|
||||||
# values = String[]
|
|
||||||
|
|
||||||
# for (key, value) in insert_data
|
function generateInsertSQL(table_name::String, data::AbstractDict{String, Any})
|
||||||
# push!(columns, string(key))
|
columns = String[]
|
||||||
# if key == :other_attributes
|
values = String[]
|
||||||
# push!(values, "'$value'")
|
|
||||||
# else
|
|
||||||
# push!(values, "'$value'")
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
|
|
||||||
# columns_str = join(columns, ", ")
|
for (key, value) in data
|
||||||
# values_str = join(values, ", ")
|
push!(columns, string(key))
|
||||||
|
value_str = isa(value, AbstractString) ? "'$value'" : "$value"
|
||||||
|
push!(values, value_str)
|
||||||
|
end
|
||||||
|
|
||||||
# return "INSERT INTO $table_name ($columns_str) VALUES ($values_str);"
|
columns_str = join(columns, ", ")
|
||||||
# end
|
values_str = join(values, ", ")
|
||||||
|
|
||||||
|
return "INSERT INTO $table_name ($columns_str) VALUES ($values_str);"
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------- 100 --------------------------------------------- #
|
||||||
|
|
||||||
|
""" generateUpdateSQL - Generate SQL UPDATE statement from dictionary data
|
||||||
|
|
||||||
|
This function constructs a SQL UPDATE statement by updating multiple columns
|
||||||
|
based on a primary key condition.
|
||||||
|
|
||||||
|
# Arguments:
|
||||||
|
- `table_name::String` - Name of the database table to update
|
||||||
|
- `pk_column::Symbol` - The primary key column name
|
||||||
|
- `pk_value` - The primary key value (used in WHERE clause)
|
||||||
|
- `data::Dict{Symbol, Any}` - Dictionary containing column-value pairs to update
|
||||||
|
|
||||||
|
# Return:
|
||||||
|
- A String containing the SQL UPDATE statement
|
||||||
|
|
||||||
|
# Example
|
||||||
|
```jldoctest
|
||||||
|
julia> using UUIDs
|
||||||
|
|
||||||
|
# Update multiple columns using a dictionary
|
||||||
|
table_name = "wine"
|
||||||
|
pk_column = :wine_id
|
||||||
|
pk_value = "8f3c7a2e-1b4d-4a9f-9c2e-4a8b3d6e5f7a"
|
||||||
|
data = Dict{Symbol, Any}(
|
||||||
|
:acidity => "full",
|
||||||
|
:tannin => "medium",
|
||||||
|
:country => "Italy"
|
||||||
|
)
|
||||||
|
|
||||||
|
julia> generateUpdateSQL(table_name, pk_column, pk_value, data)
|
||||||
|
"UPDATE wine SET acidity = 'full', tannin = 'medium', country = 'Italy' WHERE wine_id = '8f3c7a2e-1b4d-4a9f-9c2e-4a8b3d6e5f7a';"
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
example:
|
function generateUpdateSQL(table_name::String, pk_column::String, pk_value,
|
||||||
|
data::AbstractDict{String, Any})
|
||||||
insert_data = Dict(
|
# Build SET clause
|
||||||
:grape => "NA",
|
set_parts = String[]
|
||||||
:acidity => "0",
|
for (key, value) in data
|
||||||
:tannin => "0",
|
if key ∉ [pk_column]
|
||||||
:country => "NA",
|
value_str = isa(value, AbstractString) ? "'$value'" : "$value"
|
||||||
:description => "NA",
|
push!(set_parts, "$(string(key)) = $value_str")
|
||||||
:region => "NA",
|
|
||||||
:winery => "ccc",
|
|
||||||
:intensity => "0",
|
|
||||||
:sweetness => "0",
|
|
||||||
:tasting_notes => "NA",
|
|
||||||
:wine_name => "new_wine",
|
|
||||||
:wine_id => "9e1deb6a-d57f-4d2c-abbe-da813f4e91ad",
|
|
||||||
:wine_type => "NA",
|
|
||||||
:other_attributes => "{\"attribute3\":{\"attribute5\":666,\"attribute4\":\"text\"},\"attribute1\":\"hello world\",\"attribute2\":555}",
|
|
||||||
:fizziness => "0",
|
|
||||||
:serving_temperature => "0",
|
|
||||||
:additional_search_term => "{NA1,NA2}")
|
|
||||||
|
|
||||||
id_keys is the primary key columns
|
|
||||||
"""
|
|
||||||
# function generateUpdateSQL(table_name::String, update_data::Dict{Symbol, Any}, id_keys::Vector{Symbol})
|
|
||||||
# set_clauses = String[]
|
|
||||||
# where_clauses = String[]
|
|
||||||
|
|
||||||
# for (key, value) in update_data
|
|
||||||
# if key in id_keys
|
|
||||||
# push!(where_clauses, "$key = '$value'")
|
|
||||||
# else
|
|
||||||
# if key == :other_attributes
|
|
||||||
# push!(set_clauses, "$key = '$value'")
|
|
||||||
# else
|
|
||||||
# push!(set_clauses, "$key = '$value'")
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
|
|
||||||
# set_clause = join(set_clauses, ", ")
|
|
||||||
# where_clause = join(where_clauses, " AND ")
|
|
||||||
|
|
||||||
# return "UPDATE $table_name SET $set_clause WHERE $where_clause;"
|
|
||||||
# end
|
|
||||||
|
|
||||||
function generateUpdateSQL(table_name::String, columnToUpdate::Vector{Symbol},
|
|
||||||
updatedata::Dict{Symbol, Any}, id_keys::Vector{Symbol})
|
|
||||||
|
|
||||||
set_clauses = String[]
|
|
||||||
where_clauses = String[]
|
|
||||||
|
|
||||||
for (key, value) in updatedata
|
|
||||||
if key in id_keys
|
|
||||||
push!(where_clauses, "$key = '$value'")
|
|
||||||
else
|
|
||||||
if key ∈ columnToUpdate # update only specified columns
|
|
||||||
push!(set_clauses, "$key = '$value'")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
set_clause = join(set_parts, ", ")
|
||||||
|
|
||||||
|
# Handle primary key value
|
||||||
|
pk_val_str = isa(pk_value, AbstractString) ? "'$pk_value'" : "$pk_value"
|
||||||
|
|
||||||
|
return "UPDATE $table_name SET $set_clause WHERE $pk_column = $pk_val_str;"
|
||||||
end
|
end
|
||||||
|
|
||||||
set_clause = join(set_clauses, ", ")
|
function generateUpdateSQL(table_name::String, pk_dict::AbstractDict{String, Any},
|
||||||
where_clause = join(where_clauses, " AND ")
|
data::AbstractDict{String, Any})
|
||||||
|
# Build SET clause
|
||||||
|
set_parts = String[]
|
||||||
|
for (key, value) in data
|
||||||
|
if key ∉ keys(pk_dict)
|
||||||
|
value_str = isa(value, AbstractString) ? "'$value'" : "$value"
|
||||||
|
push!(set_parts, "$(string(key)) = $value_str")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
set_clause = join(set_parts, ", ")
|
||||||
|
|
||||||
|
# Build WHERE clause for composite keys
|
||||||
|
where_parts = String[]
|
||||||
|
for (col, val) in pk_dict
|
||||||
|
val_str = isa(val, AbstractString) ? "'$val'" : "$val"
|
||||||
|
push!(where_parts, "$(string(col)) = $val_str")
|
||||||
|
end
|
||||||
|
|
||||||
|
where_clause = join(where_parts, " AND ")
|
||||||
|
|
||||||
return "UPDATE $table_name SET $set_clause WHERE $where_clause;"
|
return "UPDATE $table_name SET $set_clause WHERE $where_clause;"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end # module
|
end # module
|
||||||
+730
-136
@@ -5,10 +5,10 @@ export noNegative!, randomWithProb, randomChoiceWithProb, findIndex, limitvalue,
|
|||||||
replaceLessThan, replaceBetween, cartesianAssign!, sumAlongDim3, matMul3Dto3DmanyTo1batch,
|
replaceLessThan, replaceBetween, cartesianAssign!, sumAlongDim3, matMul3Dto3DmanyTo1batch,
|
||||||
matMul_3Dto4D_batchwise, isNotEqual, linearToCartesian, vectorMax, findMax,
|
matMul_3Dto4D_batchwise, isNotEqual, linearToCartesian, vectorMax, findMax,
|
||||||
multiply_last, multiplyRandomElements, replaceElements, replaceElements!, isBetween,
|
multiply_last, multiplyRandomElements, replaceElements, replaceElements!, isBetween,
|
||||||
isLess, allTrue, getStringBetweenCharacters, JSON3read_stringKey, mkDictPath!,
|
isLess, allTrue, getStringBetweenCharacters, mkDictPath!, dict_to_string_html,
|
||||||
getDictPath
|
getDictPath, detectKeywordVariation, textToDict, dictify, ordereddictify
|
||||||
|
|
||||||
using JSON3, DataStructures, Distributions, Random, Dates, UUIDs, MQTTClient, DataFrames, CSV
|
using JSON, DataStructures, Distributions, Random, Dates, UUIDs, DataFrames, CSV
|
||||||
using ..util, ..communication
|
using ..util, ..communication
|
||||||
|
|
||||||
# ---------------------------------------------- 100 --------------------------------------------- #
|
# ---------------------------------------------- 100 --------------------------------------------- #
|
||||||
@@ -148,16 +148,33 @@ function findMax(collection::AbstractVector)
|
|||||||
return maxValue, maxIndex, matchPosition
|
return maxValue, maxIndex, matchPosition
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# ---------------------------------------------- 100 --------------------------------------------- #
|
||||||
|
|
||||||
|
""" Reads the x-th text file from a folder, where files are listed by the OS
|
||||||
|
without explicit sorting. Returns the file number, filename, and content.
|
||||||
|
|
||||||
""" read_textfile_by_index(folder_path::String, read_file_number::Integer=1)
|
# Arguments
|
||||||
|
- `folder_path::String`
|
||||||
|
Path to the folder containing text files.
|
||||||
|
- `read_file_number::Integer=1`
|
||||||
|
Which file to read (1-based index). Defaults to the first file.
|
||||||
|
|
||||||
with multiple text file in a folder,
|
# Return
|
||||||
this function read x_th text file in a folder (filename is sorted by OS)
|
- A tuple of `(file_number::Integer, filename::String, content)` where:
|
||||||
|
- `file_number` is the index of the file that was read
|
||||||
|
- `filename` is the actual filename string
|
||||||
|
- `content` is a vector of lines from the file (or `nothing` if error)
|
||||||
|
|
||||||
# Example
|
# Notes
|
||||||
utils.read_textfile_by_index(cleaned_data_path, 2)
|
- Errors if `folder_path` is not a valid directory.
|
||||||
read 2nd txt file in a folder
|
- Errors if `read_file_number` exceeds the number of files in the folder.
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
```jldoctest
|
||||||
|
julia> using GeneralUtils
|
||||||
|
julia> result = read_textfile_by_index("/path/to/folder", 2)
|
||||||
|
(2, "sample.txt", ["line1", "line2", ...])
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
function read_textfile_by_index(folder_path::String, read_file_number::Integer=1)
|
function read_textfile_by_index(folder_path::String, read_file_number::Integer=1)
|
||||||
if isdir(folder_path)
|
if isdir(folder_path)
|
||||||
@@ -185,68 +202,238 @@ function read_textfile_by_index(folder_path::String, read_file_number::Integer=1
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# ---------------------------------------------- 100 --------------------------------------------- #
|
|
||||||
|
|
||||||
""" Array_to_JSON3_str(data::AbstractArray)
|
""" Recursively convert dictionary-like variable (e.g. JSON.Object) into an OrderedDict.
|
||||||
|
|
||||||
encode Array to JSON3 String
|
The function walks any nested structure composed of `AbstractDict` (e.g., `JSON.Object`,
|
||||||
|
`Dict`, `OrderedDict`) and `AbstractArray` and produces a new tree where
|
||||||
|
every dictionary-like node is an `OrderedDict` and every array-like node is a `Vector{Any}`.
|
||||||
|
Scalar values (numbers, strings, booleans, `nothing`, etc.) are returned unchanged.
|
||||||
|
Does **not** mutate the input; it always allocates new containers.
|
||||||
|
|
||||||
# Example
|
# Arguments
|
||||||
|
- `x`
|
||||||
|
Any Julia value. If `x` is an `AbstractDict` it will be converted to an `OrderedDict`;
|
||||||
|
if it is an `AbstractArray` its elements will be processed recursively.
|
||||||
|
|
||||||
a = [1.23 4.7889; 9987.1 -123.07; -0.0027 -6.75]
|
# Keyword Arguments
|
||||||
json3_str = Array_to_JSON3_str(a)
|
- `keytype::Type=Any`
|
||||||
|
The key type for the output OrderedDict. Use `String` for `OrderedDict{String,Any}`,
|
||||||
|
`Symbol` for `OrderedDict{Symbol,Any}`, or `Any` to preserve original key types.
|
||||||
|
- `sort_order::Union{Nothing, Vector}=nothing`
|
||||||
|
Vector of keys specifying the desired order. Keys are arranged in the specified order
|
||||||
|
first, followed by any remaining keys.
|
||||||
|
|
||||||
json3_str = {"Array":[1.23,9987.1,-0.0027,4.7889,-123.07,-6.75],"size":[3,2]}
|
# Return
|
||||||
|
- A newly allocated nested structure composed of `OrderedDict{keytype,Any}` and `Vector{Any}`
|
||||||
|
that mirrors the input shape but uses ordered Julia containers.
|
||||||
|
|
||||||
|
# Notes
|
||||||
|
- The function treats any `AbstractDict` as a mapping source, so it works with
|
||||||
|
`JSON.Object`, `Dict`, `OrderedDict`, etc.
|
||||||
|
- Arrays are returned as `Vector{Any}` with their elements processed recursively.
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
```jldoctest
|
||||||
|
julia> using JSON, DataStructures
|
||||||
|
julia> d = Dict(
|
||||||
|
"a" => 4,
|
||||||
|
"b" => 6,
|
||||||
|
"c" => Dict(
|
||||||
|
"d"=>7,
|
||||||
|
:e=>Dict(
|
||||||
|
"f"=>"hey",
|
||||||
|
"g"=>Dict(
|
||||||
|
"world"=>[1, "2", 3, Dict(:dd=>4.7)]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
julia> jsonstring = JSON.json(d)
|
||||||
|
julia> A1 = JSON.parse(jsonstring) # A1 type is JSON.Object
|
||||||
|
julia> A2 = dictify(A1; keytype=String)
|
||||||
|
OrderedDict{String,Any} with 3 entries:
|
||||||
|
"a" => 4
|
||||||
|
"b" => 6
|
||||||
|
"c" => OrderedDict("d"=>7, "e"=>Dict("f"=>"hey", "g"=>Dict("world"=>[1, "2", 3, 4.7])))
|
||||||
|
|
||||||
|
julia> A3 = dictify(A1; keytype=Symbol)
|
||||||
|
OrderedDict{Symbol,Any} with 3 entries:
|
||||||
|
:a => 4
|
||||||
|
:b => 6
|
||||||
|
:c => OrderedDict(:d=>7, :e=>Dict("f"=>"hey", "g"=>Dict("world"=>[1, "2", 3, 4.7])))
|
||||||
|
|
||||||
|
julia> B1 = dictify(d; keytype=String)
|
||||||
|
OrderedDict{String, Any} with 3 entries:
|
||||||
|
```
|
||||||
|
|
||||||
|
**With sort_order:**
|
||||||
|
```jldoctest
|
||||||
|
julia> d = Dict("a"=>1, "b"=>2, "c"=>3)
|
||||||
|
julia> dictify(d; sort_order=["c", "a"])
|
||||||
|
OrderedDict{String,Int} with 3 entries:
|
||||||
|
"c" => 3
|
||||||
|
"a" => 1
|
||||||
|
"b" => 2
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
function Array_to_JSON3_str(data::AbstractArray)
|
function dictify(x::T; keytype::Type=Any, sort_order::Union{Nothing, Vector}=nothing
|
||||||
d = Dict("Array"=> data, "size"=>size(data))
|
)::OrderedDict where {T<:AbstractDict}
|
||||||
json3_str = JSON3.write(d)
|
# Dict-like objects
|
||||||
return json3_str
|
out = OrderedDict{keytype, Any}()
|
||||||
end
|
|
||||||
|
|
||||||
# ---------------------------------------------- 100 --------------------------------------------- #
|
# 1. Process and normalize all keys from the input dictionary
|
||||||
|
processed_dict = OrderedDict{keytype, Any}()
|
||||||
""" JSON3_str_to_Array(json3_str::String)
|
|
||||||
|
|
||||||
decode JSON3 String to Array
|
|
||||||
|
|
||||||
# Example
|
|
||||||
|
|
||||||
json3_str = {"Array":[1.23,9987.1,-0.0027,4.7889,-123.07,-6.75],"size":[3,2]}
|
|
||||||
a = JSON3_str_to_Array(json3_str)
|
|
||||||
|
|
||||||
a = [1.23 4.7889; 9987.1 -123.07; -0.0027 -6.75]
|
|
||||||
"""
|
|
||||||
function JSON3_str_to_Array(json3_str::String)
|
|
||||||
d = JSON3.read(json3_str)
|
|
||||||
array = reshape(Array(d.Array), (d.size[1], d.size[2]))
|
|
||||||
return array
|
|
||||||
end
|
|
||||||
|
|
||||||
# ---------------------------------------------- 100 --------------------------------------------- #
|
|
||||||
|
|
||||||
""" Convert JSON3.read object to OrderedDict
|
|
||||||
|
|
||||||
# Example
|
|
||||||
dict = dictionary(["a"=>4, "b"=>6])
|
|
||||||
OrDict = OrderedDict(dict)
|
|
||||||
jsonString = JSON3.write(OrDict) # use jsonString to exchange. One can save it to file or send it thru pub/sub
|
|
||||||
jsonObject = JSON3.read(jsonString)
|
|
||||||
OrDict2 = JSON3read_to_OrDict(jsonObject) # example here
|
|
||||||
Adict2 = dictionary(OrDict2)
|
|
||||||
|
|
||||||
Andyferris's github https://github.com/andyferris/Dictionaries.jl
|
|
||||||
"""
|
|
||||||
function JSON3read_to_OrDict(x)
|
|
||||||
dict = OrderedDict()
|
|
||||||
for (k, v) in x
|
for (k, v) in x
|
||||||
k = string(k)
|
if keytype === String
|
||||||
dict[k] = v
|
newk = string(k)
|
||||||
|
elseif keytype === Symbol
|
||||||
|
newk = Symbol(string(k))
|
||||||
|
else
|
||||||
|
newk = k
|
||||||
end
|
end
|
||||||
return dict
|
processed_dict[newk] = dictify(v; keytype=keytype, sort_order=sort_order)
|
||||||
end
|
end
|
||||||
|
|
||||||
#------------------------------------------------------------------------------------------------100
|
# 2. If a sort order is specified, apply it
|
||||||
|
if !isnothing(sort_order)
|
||||||
|
# Normalize the sort_order elements to match the requested keytype
|
||||||
|
normalized_order = map(sort_order) do tk
|
||||||
|
if keytype === String
|
||||||
|
return string(tk)
|
||||||
|
elseif keytype === Symbol
|
||||||
|
return Symbol(string(tk))
|
||||||
|
else
|
||||||
|
return tk
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# First, insert keys that match the requested order
|
||||||
|
for target_key in normalized_order
|
||||||
|
if haskey(processed_dict, target_key)
|
||||||
|
out[target_key] = processed_dict[target_key]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Then, append any remaining keys that weren't in the sort_order
|
||||||
|
for (k, v) in processed_dict
|
||||||
|
if !haskey(out, k)
|
||||||
|
out[k] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
# If no sort order is given, just use the processed dict
|
||||||
|
out = processed_dict
|
||||||
|
end
|
||||||
|
|
||||||
|
return out
|
||||||
|
end
|
||||||
|
|
||||||
|
function dictify(x::T; keytype::Type=Any, sort_order::Union{Nothing, Vector}=nothing
|
||||||
|
) where {T<:AbstractArray}
|
||||||
|
return [dictify(element; keytype=keytype, sort_order=sort_order) for element in x]
|
||||||
|
end
|
||||||
|
|
||||||
|
function dictify(x; keytype::Type=Any, sort_order::Union{Nothing, Vector}=nothing
|
||||||
|
)
|
||||||
|
return x
|
||||||
|
end
|
||||||
|
|
||||||
|
# ---------------------------------------------- 100 --------------------------------------------- #
|
||||||
|
|
||||||
|
""" Recursively convert dictionary-like variable (e.g. JSON.Object) into a dictionary.
|
||||||
|
The function walks any nested structure composed of AbstractDict (e.g., JSON.Object,
|
||||||
|
Dict, OrderedDict) and AbstractArray and produces a new tree where
|
||||||
|
every dictionary-like node is an OrderedDict{Any,Any} and every array-like
|
||||||
|
node is a Vector{Any}. Scalar values (numbers, strings, booleans,
|
||||||
|
nothing, etc.) are returned unchanged.
|
||||||
|
Does **not** mutate the input; it always allocates new containers.
|
||||||
|
|
||||||
|
# Arguments
|
||||||
|
- `x`
|
||||||
|
Any Julia value. If x is an AbstractDict it will be converted to an
|
||||||
|
OrderedDict{Any,Any}. if it is an AbstractArray its elements will be
|
||||||
|
processed recursively.
|
||||||
|
|
||||||
|
# Keyword Arguments
|
||||||
|
- `keytype::Type=Any`
|
||||||
|
The key type for the output Dict. Use `String` for `OrderedDict{String,Any}`, `Symbol` for `OrderedDict{Symbol,Any}`, or `Any` to preserve original key types.
|
||||||
|
|
||||||
|
# Return
|
||||||
|
- A newly allocated nested structure composed of `OrderedDict{keytype,Any}` and
|
||||||
|
`Vector{Any}` that mirrors the input shape but uses ordered Julia containers.
|
||||||
|
|
||||||
|
# Notes
|
||||||
|
- The function treats any `AbstractDict` as a mapping source, so it works with
|
||||||
|
`JSON.Object`, `Dict`, `OrderedDict`, etc.
|
||||||
|
- Arrays are returned as `Vector{Any}` with their elements processed recursively.
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
```jldoctest
|
||||||
|
julia> using JSON
|
||||||
|
julia> d = Dict(
|
||||||
|
"a" => 4,
|
||||||
|
"b" => 6,
|
||||||
|
"c" => Dict(
|
||||||
|
"d"=>7,
|
||||||
|
:e=>Dict(
|
||||||
|
"f"=>"hey",
|
||||||
|
"g"=>Dict(
|
||||||
|
"world"=>[1, "2", 3, Dict(:dd=>4.7)]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
julia jsonstring = JSON.json(d)
|
||||||
|
julia> A1 = JSON.parse(jsonstring) # A1 type is JSON.Object
|
||||||
|
julia> A2 = ordereddictify(A1; keytype=String)
|
||||||
|
OrderedDict{String,Any} with 3 entries:
|
||||||
|
"a" => 4
|
||||||
|
"b" => 6
|
||||||
|
"c" => OrderedDict("d"=>7, "e"=>Dict("f"=>"hey", "g"=>Dict("world"=>[1, "2", 3, 4.7])))
|
||||||
|
|
||||||
|
julia> A3 = ordereddictify(A1; keytype=Symbol)
|
||||||
|
OrderedDict{Symbol,Any} with 3 entries:
|
||||||
|
:a => 4
|
||||||
|
:b => 6
|
||||||
|
:c => OrderedDict(:d=>7, :e=>Dict("f"=>"hey", "g"=>Dict("world"=>[1, "2", 3, 4.7])))
|
||||||
|
|
||||||
|
julia> B1 = ordereddictify(d; keytype=String)
|
||||||
|
OrderedDict{String, Any} with 3 entries:
|
||||||
|
"c" => OrderedDict{String, Any}("e"=>OrderedDict{String, Any}("f"=>"hey", "g"=>OrderedDict{String, Any}("world"=>Any[1, "2", 3, OrderedDict{String, Any}("dd"=>4.7)])), "d"=>7)
|
||||||
|
"b" => 6
|
||||||
|
"a" => 4
|
||||||
|
```
|
||||||
|
Ref. https://github.com/andyferris/Dictionaries.jl
|
||||||
|
"""
|
||||||
|
function ordereddictify(x; keytype::Type=Any)
|
||||||
|
# Dict-like objects
|
||||||
|
if x isa AbstractDict
|
||||||
|
# choose output key type container
|
||||||
|
out = OrderedDict{keytype,Any}()
|
||||||
|
for (k,v) in x
|
||||||
|
if keytype === String
|
||||||
|
newk = string(k)
|
||||||
|
elseif keytype === Symbol
|
||||||
|
newk = Symbol(string(k))
|
||||||
|
else
|
||||||
|
newk = k
|
||||||
|
end
|
||||||
|
out[newk] = ordereddictify(v; keytype=keytype)
|
||||||
|
end
|
||||||
|
return out
|
||||||
|
# Arrays / vectors: map elements recursively and return a Vector{Any}
|
||||||
|
elseif x isa AbstractArray
|
||||||
|
return [ordereddictify(element; keytype=keytype) for element in x]
|
||||||
|
# everything else: return as-is (primitives, numbers, strings, etc.)
|
||||||
|
else
|
||||||
|
return x
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#----------------------------------------------100---------------------------------------------
|
||||||
|
|
||||||
"""
|
"""
|
||||||
print time of cpu executtion at the line inwhich this macro is used
|
print time of cpu executtion at the line inwhich this macro is used
|
||||||
@@ -328,6 +515,32 @@ function randomChoiceOnTarget(target::AbstractVector, choiceList::AbstractVector
|
|||||||
return randomChoiceOnTarget.(target, 1, (choiceList,), (probability,))
|
return randomChoiceOnTarget.(target, 1, (choiceList,), (probability,))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
""" Compute the linearly weighted average of an array.
|
||||||
|
The function assigns weights proportional to position indices (1, 2, 3, ...) to array
|
||||||
|
elements and returns the weighted average.
|
||||||
|
|
||||||
|
# Arguments
|
||||||
|
- `a::Array`
|
||||||
|
Array of numeric values. Elements must support multiplication with numbers
|
||||||
|
and summation.
|
||||||
|
|
||||||
|
# Return
|
||||||
|
- The linearly weighted average as a floating-point number.
|
||||||
|
|
||||||
|
# Formula
|
||||||
|
For an array `a` with `n` elements, computes:
|
||||||
|
```
|
||||||
|
sum(i * a[i]) / sum(a) for i = 1 to n
|
||||||
|
```
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
```jldoctest
|
||||||
|
julia> using GeneralUtils
|
||||||
|
julia> a = [10, 20, 30]
|
||||||
|
julia> linearly_weighted_avg(a)
|
||||||
|
23.333333333333332
|
||||||
|
```
|
||||||
|
"""
|
||||||
function linearly_weighted_avg(a::Array)
|
function linearly_weighted_avg(a::Array)
|
||||||
total = 0.0
|
total = 0.0
|
||||||
for (i, v) in enumerate(a)
|
for (i, v) in enumerate(a)
|
||||||
@@ -338,10 +551,34 @@ function linearly_weighted_avg(a::Array)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
""" Convert String that is holded inside a variable to Symbol
|
""" Convert a variable's value (String) into a Symbol.
|
||||||
# Example
|
The function takes a variable containing a String value and converts it to a Symbol
|
||||||
x = "hello" # x is a variable holding String "hello" \n
|
using Julia's expression interpolation mechanism.
|
||||||
y = variable_to_symbol(x) # y holds :hello
|
|
||||||
|
# Arguments
|
||||||
|
- `variable`
|
||||||
|
Any variable whose value is a String. The function uses `string(variable)`
|
||||||
|
internally to obtain the value.
|
||||||
|
|
||||||
|
# Return
|
||||||
|
- A `Symbol` constructed from the string value of the input variable.
|
||||||
|
|
||||||
|
# Notes
|
||||||
|
- This function uses variable interpolation to capture the variable's
|
||||||
|
value as a Symbol. It works with any variable type that can be converted
|
||||||
|
to String.
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
```jldoctest
|
||||||
|
julia> using GeneralUtils
|
||||||
|
julia> x = "hello"
|
||||||
|
julia> variable_str_to_symbol(x)
|
||||||
|
:hello
|
||||||
|
|
||||||
|
julia> y = "world_test"
|
||||||
|
julia> variable_str_to_symbol(y)
|
||||||
|
:world_test
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
function variable_str_to_symbol(variable)
|
function variable_str_to_symbol(variable)
|
||||||
semi = :($variable)
|
semi = :($variable)
|
||||||
@@ -385,6 +622,43 @@ function fieldname_useable_type(somestruct, fieldname::Symbol;
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
""" Draw unique elements from a list without replacement.
|
||||||
|
The function randomly selects a specified number of distinct elements from a collection,
|
||||||
|
optionally excluding certain elements from consideration. Uses in-place
|
||||||
|
shuffling for efficiency.
|
||||||
|
|
||||||
|
# Arguments
|
||||||
|
- `drawOptions::Array`
|
||||||
|
Collection of elements to draw from.
|
||||||
|
- `draw_number::Integer`
|
||||||
|
Number of unique elements to draw.
|
||||||
|
|
||||||
|
# Keyword Arguments
|
||||||
|
- `exclude_list::Union{AbstractArray,Nothing}=nothing`
|
||||||
|
Elements to exclude from the drawing pool. If `nothing`, no elements are
|
||||||
|
excluded.
|
||||||
|
|
||||||
|
# Return
|
||||||
|
- An array of `draw_number` unique elements drawn from `drawOptions`, excluding
|
||||||
|
any elements in `exclude_list`.
|
||||||
|
|
||||||
|
# Notes
|
||||||
|
- The function copies `drawOptions` and shuffles in-place, then pops elements
|
||||||
|
sequentially to ensure uniqueness.
|
||||||
|
- Errors if `draw_number` exceeds the number of available elements after
|
||||||
|
exclusion.
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
```jldoctest
|
||||||
|
julia> using GeneralUtils
|
||||||
|
julia> options = [1, 2, 3, 4, 5]
|
||||||
|
julia> randomNoRepeat(options, 3)
|
||||||
|
[3, 1, 5]
|
||||||
|
|
||||||
|
julia> randomNoRepeat(options, 2; exclude_list=[1, 5])
|
||||||
|
[4, 2]
|
||||||
|
```
|
||||||
|
"""
|
||||||
function randomNoRepeat(drawOptions::Array, draw_number::Integer;
|
function randomNoRepeat(drawOptions::Array, draw_number::Integer;
|
||||||
exclude_list::Union{AbstractArray,Nothing}=nothing)
|
exclude_list::Union{AbstractArray,Nothing}=nothing)
|
||||||
draw_option = copy(drawOptions)
|
draw_option = copy(drawOptions)
|
||||||
@@ -551,10 +825,33 @@ function selectRange(d::Dict{Symbol, <:AbstractVector}, range)
|
|||||||
return newDict
|
return newDict
|
||||||
end
|
end
|
||||||
|
|
||||||
""" Assign value to a given Dict by array of keys
|
""" Recursively traverses a nested dictionary structure using a vector of keys
|
||||||
|
and assigns a value to the final key. Creates intermediate dictionaries
|
||||||
|
if they don't exist.
|
||||||
|
|
||||||
# Example
|
# Arguments
|
||||||
d = Dict(
|
- `dict::Dict`
|
||||||
|
The root dictionary to traverse and modify.
|
||||||
|
- `accessArray::Array{Symbol}`
|
||||||
|
A vector of symbols representing the key path to traverse.
|
||||||
|
- `valueToAssign`
|
||||||
|
The value to assign at the final key in the path.
|
||||||
|
|
||||||
|
# Return
|
||||||
|
- `0` on success (value assigned)
|
||||||
|
- `1` if the path cannot be traversed (missing intermediate keys)
|
||||||
|
|
||||||
|
# Notes
|
||||||
|
- The function walks through each key in `accessArray` except the last one,
|
||||||
|
expecting intermediate keys to already exist in the dictionary.
|
||||||
|
- If any intermediate key is missing, the function returns `1` without
|
||||||
|
modifying the dictionary.
|
||||||
|
- The final key in `accessArray` receives the `valueToAssign`.
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
```jldoctest
|
||||||
|
julia> using GeneralUtils
|
||||||
|
julia> d = Dict(
|
||||||
:a1=> Dict(:c=> 5),
|
:a1=> Dict(:c=> 5),
|
||||||
:a2=> Dict(
|
:a2=> Dict(
|
||||||
:k=> 10,
|
:k=> 10,
|
||||||
@@ -563,10 +860,11 @@ end
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
index = [:a2, :b, :s] \n
|
julia> assignDict!(d, [:a2, :b, :s], "wow")
|
||||||
assignDict!(d, [:a2, :b, :s], "wow")
|
0
|
||||||
|
julia> d[:a2][:b][:s]
|
||||||
return 1 if no target key in a given dict.
|
"wow"
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
function assignDict!(dict::Dict, accessArray::Array{Symbol}, valueToAssign)
|
function assignDict!(dict::Dict, accessArray::Array{Symbol}, valueToAssign)
|
||||||
wd = nothing
|
wd = nothing
|
||||||
@@ -587,9 +885,39 @@ function assignDict!(dict::Dict, accessArray::Array{Symbol}, valueToAssign)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
""" convert hour(0-23), minute(0-59) into julia time object
|
""" Converts hour (0-23) and minute (0-59) into a Julia `Time` object using
|
||||||
# Example
|
12-hour format with AM/PM indicator.
|
||||||
time
|
|
||||||
|
# Arguments
|
||||||
|
- `h::Integer`
|
||||||
|
Hour in 24-hour format (0 to 23).
|
||||||
|
- `m::Integer`
|
||||||
|
Minute (0 to 59).
|
||||||
|
|
||||||
|
# Return
|
||||||
|
- A `Time` object representing the time in 12-hour format with AM/PM.
|
||||||
|
|
||||||
|
# Notes
|
||||||
|
- Hours 0 and 12 are special cases: 0 becomes 12 AM, 12 becomes 12 PM.
|
||||||
|
- Hours 1-11 remain the same with "am" suffix.
|
||||||
|
- Hours 13-23 are converted to 1-11 with "pm" suffix.
|
||||||
|
- Minutes less than 10 are zero-padded.
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
```jldoctest
|
||||||
|
julia> using GeneralUtils
|
||||||
|
julia> iTime(0, 30)
|
||||||
|
12:30 AM
|
||||||
|
|
||||||
|
julia> iTime(9, 15)
|
||||||
|
9:15 AM
|
||||||
|
|
||||||
|
julia> iTime(12, 0)
|
||||||
|
12:00 PM
|
||||||
|
|
||||||
|
julia> iTime(14, 5)
|
||||||
|
2:05 PM
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
function iTime(h::Integer, m::Integer)
|
function iTime(h::Integer, m::Integer)
|
||||||
if h == 0
|
if h == 0
|
||||||
@@ -633,18 +961,36 @@ function limitvalue(v::Number, lowerbound::Pair, upperbound::Pair)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
""" Assign matrix b to matrix a according to matrix b's CartesianIndex.
|
""" Assigns elements from matrix `b` to matrix `a` using the Cartesian indices
|
||||||
|
of `b`. Elements are copied in the order they appear when iterating over `b`,
|
||||||
|
and placed into `a` at the corresponding Cartesian positions of `b`.
|
||||||
|
|
||||||
Arguments:\n
|
# Arguments
|
||||||
a : target matrix.
|
- `a`
|
||||||
b : source matrix.
|
Target matrix where values from `b` will be assigned.
|
||||||
|
- `b`
|
||||||
|
Source matrix whose Cartesian indices determine where values are placed in `a`.
|
||||||
|
|
||||||
Return:\n
|
# Return
|
||||||
Resulting matrix a.
|
- `nothing`
|
||||||
|
|
||||||
Example:\n
|
# Notes
|
||||||
|
- The function iterates through `b` in column-major order (Julia's default),
|
||||||
|
retrieving each element's Cartesian index and assigning it to the same
|
||||||
|
position in `a`.
|
||||||
|
- Matrix `a` must have sufficient size to accommodate all Cartesian indices
|
||||||
|
from `b`; otherwise, an `BoundsError` may occur.
|
||||||
|
|
||||||
|
# Examples
|
||||||
```jldoctest
|
```jldoctest
|
||||||
julia> not done yet
|
julia> using GeneralUtils
|
||||||
|
julia> a = zeros(4, 4);
|
||||||
|
julia> b = [1 2; 3 4];
|
||||||
|
julia> cartesianAssign!(a, b);
|
||||||
|
julia> a[1:2, 1:2]
|
||||||
|
2×2 Matrix{Float64}:
|
||||||
|
1.0 3.0
|
||||||
|
2.0 4.0
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
function cartesianAssign!(a, b)
|
function cartesianAssign!(a, b)
|
||||||
@@ -1000,7 +1346,6 @@ julia> text = "{\"ask\": {\"text\": \"Could you please tell me about the special
|
|||||||
julia> GeneralUtils.getStringBetweenCharacters(text, '{', '}', endCharLocation="end")
|
julia> GeneralUtils.getStringBetweenCharacters(text, '{', '}', endCharLocation="end")
|
||||||
"{\"ask\": {\"text\": \"Could you please tell me about the special event?\"\n}}"
|
"{\"ask\": {\"text\": \"Could you please tell me about the special event?\"\n}}"
|
||||||
```
|
```
|
||||||
# Signature
|
|
||||||
"""
|
"""
|
||||||
function getStringBetweenCharacters(text::T, startChar::Char, endChar::Char;
|
function getStringBetweenCharacters(text::T, startChar::Char, endChar::Char;
|
||||||
endCharLocation::String="next", includeChar::Bool=true)::String where {T<:AbstractString}
|
endCharLocation::String="next", includeChar::Bool=true)::String where {T<:AbstractString}
|
||||||
@@ -1032,59 +1377,40 @@ function getStringBetweenCharacters(text::T, startChar::Char, endChar::Char;
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
""" Recursively creates nested dictionary paths if they do not exist and assigns
|
||||||
""" Read JSON string and return a dictionary with string key. (JSON3 defaults to symbol key)
|
a value to the final key. Similar to `mkpath()` but for dictionaries.
|
||||||
This function solve the problem of reading JSON with string key.
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
jsonString::String
|
|
||||||
|
|
||||||
Return:
|
|
||||||
a dictionary with string key
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```jldoctest
|
|
||||||
julia> jsonString = {\"wine type\": \"Red\", \"intensity level\": \"medium-bodied\"}
|
|
||||||
julia> JSON3read_stringKey(jsonString)
|
|
||||||
Dict{String, Any} with 2 entries:
|
|
||||||
"intensity level" => "medium-bodied"
|
|
||||||
"wine type" => "Red"
|
|
||||||
```
|
|
||||||
"""
|
|
||||||
function JSON3read_stringKey(jsonString::AbstractString)
|
|
||||||
jsonobj = JSON3.read(jsonString)
|
|
||||||
newDict = OrderedDict{String,Any}()
|
|
||||||
for (k,v) in jsonobj
|
|
||||||
newDict[string(k)] = v
|
|
||||||
end
|
|
||||||
return newDict
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
""" Create nested dict path if it does not already exist. The same concept as Julia's mkpath()
|
|
||||||
|
|
||||||
# Arguments
|
# Arguments
|
||||||
- `dict::Dict`
|
- `dict::Union{Dict{Symbol, Any}, Dict{String, Any}}`
|
||||||
target dict
|
The target dictionary to traverse and modify. Must use consistent key types
|
||||||
|
(either all `String` or all `Symbol`).
|
||||||
- `addkeys::Union{Vector{String}, Vector{Symbol}}`
|
- `addkeys::Union{Vector{String}, Vector{Symbol}}`
|
||||||
keys to be added to dict
|
A vector of keys representing the path to traverse. Intermediate dictionaries
|
||||||
|
are created if they don't exist.
|
||||||
- `value`
|
- `value`
|
||||||
value to be added to dict at final key in keypath
|
The value to assign at the final key in the path.
|
||||||
|
|
||||||
# Return
|
# Return
|
||||||
- dict with added keypath
|
- The assigned `value`.
|
||||||
|
|
||||||
# Example
|
# Notes
|
||||||
|
- The function ensures key type consistency: the type of keys being added must
|
||||||
|
match the type of existing keys in the dictionary.
|
||||||
|
- Intermediate dictionaries are automatically created with the appropriate key
|
||||||
|
type when they don't exist.
|
||||||
|
- The function walks through each key in `addkeys` except the last one,
|
||||||
|
creating intermediate dictionaries as needed, and assigns `value` to the final
|
||||||
|
key.
|
||||||
|
|
||||||
|
# Examples
|
||||||
```jldoctest
|
```jldoctest
|
||||||
julia> using Revise
|
|
||||||
julia> using GeneralUtils
|
julia> using GeneralUtils
|
||||||
julia> d = Dict{String, Any}("a" => Dict{String, Any}("b" => 10))
|
julia> d = Dict("a" => Dict("b" => 10))
|
||||||
julia> GeneralUtils.mkDictPath!(d, ["a", "v", "x", "y", "z"], 42)
|
julia> mkDictPath!(d, ["a", "v", "x", "y", "z"], 42)
|
||||||
Dict{String, Any} with 1 entry:
|
42
|
||||||
"path" => Dict{Any, Any}("to"=>Dict{Any, Any}("nested"=>Dict{Any, Any}("value"=>42)))
|
julia> d["a"]["v"]["x"]["y"]["z"]
|
||||||
|
42
|
||||||
```
|
```
|
||||||
|
|
||||||
# Signature
|
|
||||||
"""
|
"""
|
||||||
function mkDictPath!(dict::Union{Dict{Symbol, Any}, Dict{String, Any}},
|
function mkDictPath!(dict::Union{Dict{Symbol, Any}, Dict{String, Any}},
|
||||||
addkeys::Union{Vector{String}, Vector{Symbol}}, value)
|
addkeys::Union{Vector{String}, Vector{Symbol}}, value)
|
||||||
@@ -1108,27 +1434,33 @@ function mkDictPath!(dict::Union{Dict{Symbol, Any}, Dict{String, Any}},
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
""" Get nested dict value using a vector of keys
|
""" Retrieves a value from a nested dictionary by traversing a vector of keys.
|
||||||
|
Creates intermediate dictionaries if they don't exist.
|
||||||
|
|
||||||
# Arguments
|
# Arguments
|
||||||
- `dict::Dict`
|
- `dict::Dict`
|
||||||
target dict
|
The root dictionary to traverse.
|
||||||
- `keys::Vector`
|
- `keys::Vector`
|
||||||
keys vector
|
A vector of keys representing the path to traverse. Each key in the vector
|
||||||
|
is used to access the next level of nesting.
|
||||||
|
|
||||||
# Return
|
# Return
|
||||||
- dict with added keypath
|
- The value at the final key in the path.
|
||||||
|
|
||||||
# Example
|
# Notes
|
||||||
|
- Errors with `ArgumentError` if any intermediate key is missing from the
|
||||||
|
dictionary path.
|
||||||
|
- The function walks through each key in `keys` except the last one,
|
||||||
|
expecting intermediate keys to exist in the dictionary.
|
||||||
|
- The final key in `keys` is used to retrieve the value.
|
||||||
|
|
||||||
|
# Examples
|
||||||
```jldoctest
|
```jldoctest
|
||||||
julia> using Revise
|
|
||||||
julia> using GeneralUtils
|
julia> using GeneralUtils
|
||||||
julia> d = Dict{Symbol, Any}(:a => Dict{Symbol, Any}(:b => 10))
|
julia> d = Dict(:a => Dict(:b => 10))
|
||||||
julia> GeneralUtils.getDictPath(d, [:a, :b])
|
julia> getDictPath(d, [:a, :b])
|
||||||
10
|
10
|
||||||
```
|
```
|
||||||
|
|
||||||
# Signature
|
|
||||||
"""
|
"""
|
||||||
function getDictPath(dict::Dict, keys::Vector)
|
function getDictPath(dict::Dict, keys::Vector)
|
||||||
current_dict = dict
|
current_dict = dict
|
||||||
@@ -1150,6 +1482,268 @@ end
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
detectKeywordVariation(keywords::AbstractVector{String}, text::String) -> Dict{String, Union{Array, Nothing}}
|
||||||
|
|
||||||
|
Detects and collects all case-variant occurrences of multiple keywords in the text.
|
||||||
|
This function processes each keyword individually and returns an array of matched variations for each keyword.
|
||||||
|
|
||||||
|
# Arguments
|
||||||
|
- `keywords::AbstractVector{String}` Vector of keywords to search for
|
||||||
|
- `text::String` The text to search in
|
||||||
|
|
||||||
|
# Returns
|
||||||
|
- `Dict{String, Array}` Returns a dictionary mapping each keyword to an array of matched variations found in the text
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
```jldoctest
|
||||||
|
julia> detectKeywordVariation(["test", "example", "cat"], "This is a Test EXAMPLE")
|
||||||
|
Dict{String, Array}("test" => ["Test"], "example" => ["EXAMPLE"], "cat" => nothing)
|
||||||
|
"""
|
||||||
|
function detectKeywordVariation(keywords::T, text::String)::Dict{String, Union{Array, Nothing}} where {T<:AbstractVector}
|
||||||
|
kw = Dict{String, Union{Array, Nothing}}()
|
||||||
|
|
||||||
|
# use for loop and detect_keyword function to get the exact variation of each keyword in the text then push to kw list
|
||||||
|
for keyword in keywords
|
||||||
|
ws = detectKeywordVariation.(keyword, text)
|
||||||
|
total = sum(issomething.(ws))
|
||||||
|
if total != 0
|
||||||
|
kw[keyword] = ws
|
||||||
|
else
|
||||||
|
kw[keyword] = nothing
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return kw
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
detectKeywordVariation(keyword::String, text::String) -> Union{Nothing, Array{String}}
|
||||||
|
|
||||||
|
Detects if a keyword exists in the text in different case variations (lowercase, uppercase first letter, or all uppercase).
|
||||||
|
|
||||||
|
# Arguments:
|
||||||
|
- `keyword::String` The keyword to search for
|
||||||
|
- `text::String` The text to search in
|
||||||
|
|
||||||
|
# Returns:
|
||||||
|
- `Union{Nothing, Array{String}}` Returns an array of matched keyword variations if found, otherwise returns nothing
|
||||||
|
|
||||||
|
# Examples:
|
||||||
|
```jldoctest
|
||||||
|
julia> detectKeywordVariation("test", "This is a Test case")
|
||||||
|
["Test"]
|
||||||
|
|
||||||
|
julia> detectKeywordVariation("error", "NO ERRORS FOUND")
|
||||||
|
["ERRORS"]
|
||||||
|
|
||||||
|
julia> detectKeywordVariation("missing", "complete data")
|
||||||
|
nothing
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
function detectKeywordVariation(keyword::String, text::String)::Union{Nothing, Array{String}}
|
||||||
|
# Define the keyword variations to search for
|
||||||
|
wordVariations = [uppercasefirst(keyword), uppercase(keyword), lowercase(keyword)]
|
||||||
|
# wordVariations may duplicate keyword
|
||||||
|
keyword_variations = [keyword]
|
||||||
|
for i in wordVariations
|
||||||
|
i != keyword ? push!(keyword_variations, i) : nothing
|
||||||
|
end
|
||||||
|
|
||||||
|
_splittext = string.(strip.(split(text, " ")))
|
||||||
|
splittext = String[]
|
||||||
|
# remove . after a word
|
||||||
|
for i in _splittext
|
||||||
|
if length(i) != 0 && i[end] ∈ ['.']
|
||||||
|
word = string(i[1:end-1])
|
||||||
|
push!(splittext, word)
|
||||||
|
else
|
||||||
|
push!(splittext, i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = String[]
|
||||||
|
for variation in keyword_variations
|
||||||
|
# if length of both word is equals then it is a whole word otherwise it is part of part of other word
|
||||||
|
r = findIndex(splittext, variation)
|
||||||
|
|
||||||
|
if isempty(r[2])
|
||||||
|
# skip
|
||||||
|
else
|
||||||
|
# if variation > 1 add them all so this function detect duplicate keyword
|
||||||
|
variations = [variation for i in eachindex(r[2])]
|
||||||
|
result = vcat(result, variations)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
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")
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
function textToDict(text::String, detectKeywords::Vector{String};
|
||||||
|
dictKey::Union{Vector{String}, Nothing}=nothing,
|
||||||
|
symbolkey::Bool=false, lowercasekey::Bool=false
|
||||||
|
)::OrderedDict
|
||||||
|
|
||||||
|
# make sure this function detect variation of a work e.g. agent, Agent, AGENT
|
||||||
|
kw = []
|
||||||
|
# use for loop and detect_keyword function to get the exact variation of each keyword in the text then push to kw list
|
||||||
|
for keyword in detectKeywords
|
||||||
|
detected = detectKeywordVariation(keyword, text)
|
||||||
|
if detected !== nothing
|
||||||
|
push!(kw, detected)
|
||||||
|
else
|
||||||
|
error("Keyword $keyword not found in text: $text")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if typeof(kw[1]) <: AbstractArray
|
||||||
|
kw = reduce(vcat, kw)
|
||||||
|
end
|
||||||
|
|
||||||
|
od1, od2 =
|
||||||
|
if symbolkey
|
||||||
|
OrderedDict{Symbol, Any}(), OrderedDict{Symbol, Any}()
|
||||||
|
else
|
||||||
|
OrderedDict{String, Any}(), OrderedDict{String, Any}()
|
||||||
|
end
|
||||||
|
|
||||||
|
remainingtext = text
|
||||||
|
dictKey_ = reverse(dictKey)
|
||||||
|
|
||||||
|
# process text from back to front
|
||||||
|
rkw = reverse(kw)
|
||||||
|
for (i,keyword) in enumerate(rkw)
|
||||||
|
# Find the position of the keyword in the text
|
||||||
|
keywordidx = findlast(keyword, remainingtext)
|
||||||
|
dKey = dictKey_[i]
|
||||||
|
|
||||||
|
if keywordidx !== nothing
|
||||||
|
substr = remainingtext[keywordidx[end]+1:end]
|
||||||
|
str = string(strip(substr)) # Removes both leading and trailing whitespace.
|
||||||
|
_key = lowercasekey == true ? lowercase(dKey) : dKey
|
||||||
|
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: $text </end of error note>""")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# correct the order
|
||||||
|
ks = reverse([i for i in keys(od1)])
|
||||||
|
for k in ks
|
||||||
|
k = symbolkey == true ? Symbol(k) : k
|
||||||
|
od2[k] = od1[k]
|
||||||
|
end
|
||||||
|
|
||||||
|
return od2
|
||||||
|
end
|
||||||
|
|
||||||
|
""" Recursively convert dictionary into an HTML string representation.
|
||||||
|
The function walks a nested `AbstractDict` structure and produces a well-formed HTML string
|
||||||
|
where each dictionary key becomes an HTML tag. Nested dictionaries become
|
||||||
|
nested tags, and scalar values (numbers, strings, etc.) become the text
|
||||||
|
content of leaf tags.
|
||||||
|
|
||||||
|
# Arguments
|
||||||
|
- `d::AbstractDict`
|
||||||
|
The dictionary to convert. Keys must be strings or symbols that form valid
|
||||||
|
HTML tag names.
|
||||||
|
|
||||||
|
# Keyword Arguments
|
||||||
|
- `indent_level::Integer=1`
|
||||||
|
Initial indentation level for the output. Each recursive level increases
|
||||||
|
indentation by one.
|
||||||
|
- `indent_str::String=" "`
|
||||||
|
String used for each indentation level.
|
||||||
|
|
||||||
|
# Return
|
||||||
|
- A single HTML string representing the dictionary structure, with proper
|
||||||
|
opening and closing tags and appropriate indentation.
|
||||||
|
|
||||||
|
# Notes
|
||||||
|
- Keys are sorted alphabetically for deterministic output.
|
||||||
|
- Works recursively: dictionary values produce nested tags; non-dictionary
|
||||||
|
values are placed as text between opening/closing tags.
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
```jldoctest
|
||||||
|
julia> d = Dict(
|
||||||
|
"html" => Dict(
|
||||||
|
"head" => Dict("title" => "Test"),
|
||||||
|
"body" => Dict(
|
||||||
|
"h1" => "Hello",
|
||||||
|
"p" => "World"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
julia> println(dict_to_string_html(d))
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Test</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello</h1>
|
||||||
|
<p>World</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
function dict_to_string_html(d::AbstractDict; indent_level=1, indent_str=" ")
|
||||||
|
lines = String[]
|
||||||
|
padding = indent_str ^ indent_level
|
||||||
|
|
||||||
|
for k in keys(d)
|
||||||
|
v = d[k]
|
||||||
|
|
||||||
|
if v isa AbstractDict
|
||||||
|
# Open tag, recurse for children, then close tag
|
||||||
|
push!(lines, "$padding<$k>")
|
||||||
|
ind_level = indent_level + 1
|
||||||
|
push!(lines, dict_to_string_html(v; indent_level=ind_level, indent_str=indent_str))
|
||||||
|
push!(lines, "$padding</$k>")
|
||||||
|
else
|
||||||
|
# Leaf node: put key and value on a single line
|
||||||
|
push!(lines, "$padding<$k>$v</$k>")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return join(lines, "\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+911
-171
File diff suppressed because it is too large
Load Diff
+301
-209
@@ -1,47 +1,52 @@
|
|||||||
module util
|
module util
|
||||||
|
|
||||||
export timedifference, showstracktrace, findHighestIndexKey, uuid4snakecase, replaceDictKeys,
|
export timedifference, showstracktrace, findHighestIndexKey, uuid4snakecase, replaceDictKeys,
|
||||||
findMatchingDictKey, textToDict, randstring, randstrings, timeout,
|
findMatchingDictKey, randstring, randstrings, timeout,
|
||||||
dataframeToCSV, dfToVectorDict, disintegrate_vectorDict, getDataFrameValue, dfRowtoString,
|
dataframeToCSV, dfToVectorDict, disintegrate_vectorDict, getDataFrameValue, dfRowtoString,
|
||||||
dfToString, dataframe_to_json_list, dictToString, dictToString_noKey,
|
dfToString, dataframe_to_json_list, dictToString, dictToString_noKey, issomething,
|
||||||
dictToString_numbering, extract_triple_backtick_text,
|
dictToString_numbering, extract_triple_backtick_text,
|
||||||
countGivenWords, remove_french_accents, detect_keyword, extractTextBetweenCharacter,
|
countGivenWords, remove_french_accents, removestring,
|
||||||
convertCamelSnakeKebabCase
|
extractTextBetweenCharacter, extractTextBetweenString,
|
||||||
|
convertCamelSnakeKebabCase, fitrange, recentElementsIndex, nonRecentElementsIndex
|
||||||
|
|
||||||
using JSON3, DataStructures, Distributions, Random, Dates, UUIDs, MQTTClient, DataFrames
|
using JSON, DataStructures, Distributions, Random, Dates, UUIDs, DataFrames
|
||||||
|
|
||||||
# ---------------------------------------------- 100 --------------------------------------------- #
|
# ---------------------------------------------- 100 --------------------------------------------- #
|
||||||
|
|
||||||
""" Compute time different between start time and stop time in a given unit.
|
""" Computes the time difference between two `DateTime` values and returns the
|
||||||
Unit can be "milliseconds", "seconds", "minutes", "hours".
|
result in a specified unit: milliseconds, seconds, minutes, or hours.
|
||||||
|
|
||||||
# Arguments
|
# Arguments
|
||||||
- `starttime::DateTime`
|
- `starttime::DateTime`
|
||||||
start time
|
The starting `DateTime` value.
|
||||||
- `stoptime::DateTime`
|
- `stoptime::DateTime`
|
||||||
stop time
|
The ending `DateTime` value.
|
||||||
- `unit::String`
|
- `unit::String`
|
||||||
unit of time difference
|
The unit for the result. Must be one of: `"milliseconds"`, `"seconds"`,
|
||||||
|
`"minutes"`, `"hours"`.
|
||||||
|
|
||||||
# Return
|
# Return
|
||||||
- time difference in given unit
|
- `Integer`: The time difference converted to the specified unit.
|
||||||
|
|
||||||
# Example
|
# Notes
|
||||||
|
- The function computes `stoptime - starttime` and converts the result to the
|
||||||
|
requested unit using integer division.
|
||||||
|
- Errors with `ArgumentError` if an invalid unit is specified.
|
||||||
|
|
||||||
|
# Examples
|
||||||
```jldoctest
|
```jldoctest
|
||||||
julia> using Revise
|
|
||||||
julia> using GeneralUtils, Dates
|
julia> using GeneralUtils, Dates
|
||||||
julia> a = Dates.now()
|
julia> a = Dates.now()
|
||||||
julia> b = a + Dates.Day(5) # add 5 days
|
julia> b = a + Dates.Day(5)
|
||||||
julia> GeneralUtils.timedifference(a, b, "hours")
|
julia> timedifference(a, b, "hours")
|
||||||
120
|
120
|
||||||
```
|
```
|
||||||
|
|
||||||
# Signature
|
|
||||||
"""
|
"""
|
||||||
function timedifference(starttime::DateTime, stoptime::DateTime, unit::String)::Integer
|
function timedifference(starttime::DateTime, stoptime::DateTime, unit::String)::Integer
|
||||||
diff = stoptime - starttime
|
diff = stoptime - starttime
|
||||||
unit = lowercase(unit)
|
unit = lowercase(unit)
|
||||||
|
|
||||||
|
# Check the unit and calculate the time difference accordingly
|
||||||
if unit == "milliseconds"
|
if unit == "milliseconds"
|
||||||
return diff.value
|
return diff.value
|
||||||
elseif unit == "seconds"
|
elseif unit == "seconds"
|
||||||
@@ -182,21 +187,27 @@ end
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
""" Get uuid4 with snake case
|
""" Generates a UUID4 (version 4) identifier and converts it to snake case by
|
||||||
|
replacing hyphens with underscores.
|
||||||
|
|
||||||
|
# Arguments
|
||||||
|
- This function takes no arguments.
|
||||||
|
|
||||||
# Return
|
# Return
|
||||||
- `uuid4::String`
|
- `String`: A UUID4 string with underscores instead of hyphens (e.g.,
|
||||||
uuid4 with snake case
|
`"0f6e4f_568c_4df4_8c79_1d7a58072f4a"`).
|
||||||
|
|
||||||
# Example
|
# Notes
|
||||||
|
- Uses the `uuid4()` function from the UUIDs standard library to generate a
|
||||||
|
random UUID.
|
||||||
|
- The underscore character replaces all hyphens in the UUID string.
|
||||||
|
|
||||||
|
# Examples
|
||||||
```jldoctest
|
```jldoctest
|
||||||
julia> using Revise
|
|
||||||
julia> using GeneralUtils
|
julia> using GeneralUtils
|
||||||
julia> GeneralUtils.uuid4snakecase()
|
julia> uuid4snakecase()
|
||||||
"0f6e4f_568c_4df4_8c79_1d7a58072f4a"
|
"0f6e4f_568c_4df4_8c79_1d7a58072f4a"
|
||||||
```
|
```
|
||||||
|
|
||||||
# Signature
|
|
||||||
"""
|
"""
|
||||||
function uuid4snakecase()::String
|
function uuid4snakecase()::String
|
||||||
_id = string(uuid4())
|
_id = string(uuid4())
|
||||||
@@ -205,32 +216,37 @@ function uuid4snakecase()::String
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
""" Replace a dictionary key with the new key
|
""" Replaces keys in a dictionary according to a mapping, returning a new
|
||||||
|
dictionary with updated keys while preserving the original values.
|
||||||
|
|
||||||
# Arguments
|
# Arguments
|
||||||
- `d::Dict`
|
- `d::Dict`
|
||||||
The input dictionary that you want to modify
|
The input dictionary to modify.
|
||||||
- `replacementMap::Dict`
|
- `replacementMap::Dict`
|
||||||
A dictionary that maps old keys to new keys
|
A dictionary mapping old keys to new keys. Keys not present in this map are
|
||||||
|
left unchanged.
|
||||||
|
|
||||||
# Return
|
# Return
|
||||||
- `newDict::Dict`
|
- `Dict`: A new dictionary with replaced keys. Values are preserved from the
|
||||||
new dictionary with the replaced keys
|
original dictionary.
|
||||||
|
|
||||||
# Example
|
# Notes
|
||||||
|
- The function creates a new dictionary rather than modifying the input in
|
||||||
|
place.
|
||||||
|
- Keys not found in `replacementMap` are copied to the result with their
|
||||||
|
original keys unchanged.
|
||||||
|
|
||||||
|
# Examples
|
||||||
```jldoctest
|
```jldoctest
|
||||||
julia> using Revise
|
|
||||||
julia> using GeneralUtils
|
julia> using GeneralUtils
|
||||||
julia> d = Dict(:a => 1, :b => 2, :c => 3)
|
julia> d = Dict(:a => 1, :b => 2, :c => 3)
|
||||||
julia> replacement_map = Dict(:a => :x, :b => :y)
|
julia> replacement_map = Dict(:a => :x, :b => :y)
|
||||||
julia> new_dict = GeneralUtils.replaceDictKeys(d, replacement_map)
|
julia> replaceDictKeys(d, replacement_map)
|
||||||
Dict{Any, Any} with 3 entries:
|
Dict{Any, Any} with 3 entries:
|
||||||
:y => 2
|
:y => 2
|
||||||
:c => 3
|
:c => 3
|
||||||
:x => 1
|
:x => 1
|
||||||
```
|
```
|
||||||
|
|
||||||
# Signature
|
|
||||||
"""
|
"""
|
||||||
function replaceDictKeys(d::Dict, replacementMap::Dict)::Dict
|
function replaceDictKeys(d::Dict, replacementMap::Dict)::Dict
|
||||||
newDict = Dict()
|
newDict = Dict()
|
||||||
@@ -242,101 +258,6 @@ function replaceDictKeys(d::Dict, replacementMap::Dict)::Dict
|
|||||||
end
|
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, detectKeywords::Vector{String};
|
|
||||||
dictKey::Union{Vector{String}, Nothing}=nothing,
|
|
||||||
symbolkey::Bool=false, lowercasekey::Bool=false
|
|
||||||
)::OrderedDict
|
|
||||||
|
|
||||||
# make sure this function detect variation of a work e.g. agent, Agent, AGENT
|
|
||||||
kw = []
|
|
||||||
# use for loop and detect_keyword function to get the exact variation of each keyword in the text then push to kw list
|
|
||||||
for keyword in detectKeywords
|
|
||||||
detected = detect_keyword(keyword, text)
|
|
||||||
if detected !== nothing
|
|
||||||
push!(kw, detected)
|
|
||||||
else
|
|
||||||
error("Keyword $keyword not found in text.")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
od1, od2 =
|
|
||||||
if symbolkey
|
|
||||||
OrderedDict{Symbol, Any}(), OrderedDict{Symbol, Any}()
|
|
||||||
else
|
|
||||||
OrderedDict{String, Any}(), OrderedDict{String, Any}()
|
|
||||||
end
|
|
||||||
|
|
||||||
remainingtext = text
|
|
||||||
dictKey_ = reverse(dictKey)
|
|
||||||
|
|
||||||
# process text from back to front
|
|
||||||
for (i,keyword) in enumerate(reverse(kw))
|
|
||||||
# Find the position of the keyword in the text
|
|
||||||
keywordidx = findlast(keyword, remainingtext)
|
|
||||||
dKey = dictKey_[i]
|
|
||||||
|
|
||||||
if keywordidx !== nothing
|
|
||||||
substr = remainingtext[keywordidx[end]+1:end]
|
|
||||||
str = string(strip(substr)) # Removes both leading and trailing whitespace.
|
|
||||||
_key = lowercasekey == true ? lowercase(dKey) : dKey
|
|
||||||
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: $text </end of error note>""")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# correct the order
|
|
||||||
ks = reverse([i for i in keys(od1)])
|
|
||||||
for k in ks
|
|
||||||
k = symbolkey == true ? Symbol(k) : k
|
|
||||||
od2[k] = od1[k]
|
|
||||||
end
|
|
||||||
|
|
||||||
return od2
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
""" Generate a random string
|
""" Generate a random string
|
||||||
|
|
||||||
# Arguments
|
# Arguments
|
||||||
@@ -387,24 +308,33 @@ end
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
""" Execute a function with timer.
|
""" Executes a function with a timeout mechanism. If the function does not
|
||||||
|
complete within the specified time, it is interrupted and a timeout message
|
||||||
|
is returned.
|
||||||
|
|
||||||
# Arguments
|
# Arguments
|
||||||
- `f::Function`
|
- `f::Function`
|
||||||
a function to run
|
The function to execute.
|
||||||
- `timeoutwindow::Integer``
|
- `timeoutwindow::Integer`
|
||||||
timeout in seconds
|
The timeout duration in seconds.
|
||||||
|
|
||||||
# Keyword Argument
|
# Keyword Arguments
|
||||||
- `fargs`
|
- `fargs`
|
||||||
arguments for the function
|
Arguments to pass to the function `f`. If `nothing`, the function is called
|
||||||
|
without arguments.
|
||||||
- `timeoutmsg::String`
|
- `timeoutmsg::String`
|
||||||
time out message
|
The message to return if the function times out. Defaults to `"task timed out"`.
|
||||||
|
|
||||||
# Return
|
# Return
|
||||||
- task result otherwise timeout message
|
- The result of the function if it completes within the timeout, otherwise the
|
||||||
|
`timeoutmsg` string.
|
||||||
|
|
||||||
# Example
|
# Notes
|
||||||
|
- Uses Julia's `@task`, `schedule`, and `Timer` to implement non-blocking
|
||||||
|
execution with interruption via `Base.throwto`.
|
||||||
|
- Errors with `InterruptException` if the function exceeds the timeout.
|
||||||
|
|
||||||
|
# Examples
|
||||||
```jldoctest
|
```jldoctest
|
||||||
julia> function testfunc(x)
|
julia> function testfunc(x)
|
||||||
sleep(x)
|
sleep(x)
|
||||||
@@ -415,8 +345,6 @@ julia> result = timeout(testfunc, 10; fargs=20)
|
|||||||
julia> result = timeout(testfunc, 20; fargs=10)
|
julia> result = timeout(testfunc, 20; fargs=10)
|
||||||
"task done"
|
"task done"
|
||||||
```
|
```
|
||||||
|
|
||||||
# Signature
|
|
||||||
"""
|
"""
|
||||||
function timeout(f::Function, timeoutwindow::Integer; fargs=nothing, timeoutmsg="task timed out")
|
function timeout(f::Function, timeoutwindow::Integer; fargs=nothing, timeoutmsg="task timed out")
|
||||||
tsk = @task f(fargs)
|
tsk = @task f(fargs)
|
||||||
@@ -433,23 +361,26 @@ end
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
""" Convert a dataframe into CSV.
|
""" Converts a DataFrame to a CSV string representation using the CSV.jl package.
|
||||||
|
|
||||||
# Arguments
|
# Arguments
|
||||||
- `df::DataFrame`
|
- `df::DataFrame`
|
||||||
A connection object to Postgres database
|
The DataFrame to convert to CSV format.
|
||||||
|
|
||||||
# Return
|
# Return
|
||||||
- `result::String`
|
- `String`: The DataFrame contents as a CSV-formatted string.
|
||||||
|
|
||||||
# Example
|
# Notes
|
||||||
|
- Uses `CSV.write` with an `IOBuffer` to capture the output as a string.
|
||||||
|
- The returned string contains the full CSV representation including headers.
|
||||||
|
|
||||||
|
# Examples
|
||||||
```jldoctest
|
```jldoctest
|
||||||
julia> using DataFrames, GeneralUtils
|
julia> using DataFrames, GeneralUtils
|
||||||
julia> df = DataFrame(A=1:3, B=5:7, fixed=1)
|
julia> df = DataFrame(A=1:3, B=5:7, fixed=1)
|
||||||
julia> result = GeneralUtils.dataframeToCSV(df)
|
julia> dataframeToCSV(df)
|
||||||
|
"1,5,1\n2,6,1\n3,7,1\n"
|
||||||
```
|
```
|
||||||
|
|
||||||
# Signature
|
|
||||||
"""
|
"""
|
||||||
function dataframeToCSV(df::DataFrame)
|
function dataframeToCSV(df::DataFrame)
|
||||||
# Create an IOBuffer to capture the output
|
# Create an IOBuffer to capture the output
|
||||||
@@ -471,7 +402,7 @@ end
|
|||||||
|
|
||||||
# Example
|
# Example
|
||||||
```jldoctest
|
```jldoctest
|
||||||
julia> using DataFrames, JSON3, GeneralUtils
|
julia> using DataFrames, GeneralUtils
|
||||||
julia> df = DataFrame(A = [1, 2, 3], B = ["apple", "banana", "cherry"])
|
julia> df = DataFrame(A = [1, 2, 3], B = ["apple", "banana", "cherry"])
|
||||||
julia> vectorDict = GeneralUtils.dfToVectorDict(df)
|
julia> vectorDict = GeneralUtils.dfToVectorDict(df)
|
||||||
[Dict{String, Any}("B" => "apple", "A" => 1),
|
[Dict{String, Any}("B" => "apple", "A" => 1),
|
||||||
@@ -509,7 +440,7 @@ end
|
|||||||
|
|
||||||
# Example
|
# Example
|
||||||
```jldoctest
|
```jldoctest
|
||||||
julia> using GeneralUtils, Dates, JSON3, UUIDs
|
julia> using GeneralUtils, Dates, UUIDs
|
||||||
julia> vecDict = [Dict("a" => i) for i in 1:10]
|
julia> vecDict = [Dict("a" => i) for i in 1:10]
|
||||||
julia> d = GeneralUtils.disintegrate_vectorDict(vecDict, 3)
|
julia> d = GeneralUtils.disintegrate_vectorDict(vecDict, 3)
|
||||||
julia> println(d[:data])
|
julia> println(d[:data])
|
||||||
@@ -519,8 +450,6 @@ end
|
|||||||
3 => [Dict("a"=>7), Dict("a"=>8), Dict("a"=>9)]
|
3 => [Dict("a"=>7), Dict("a"=>8), Dict("a"=>9)]
|
||||||
4 => [Dict("a"=>10)]
|
4 => [Dict("a"=>10)]
|
||||||
```
|
```
|
||||||
|
|
||||||
# Signature
|
|
||||||
"""
|
"""
|
||||||
function disintegrate_vectorDict(data::Vector, partsize::Integer
|
function disintegrate_vectorDict(data::Vector, partsize::Integer
|
||||||
)
|
)
|
||||||
@@ -566,8 +495,6 @@ end
|
|||||||
julia> getDataFrameValue(df[1, :], :name)
|
julia> getDataFrameValue(df[1, :], :name)
|
||||||
"Alice"
|
"Alice"
|
||||||
```
|
```
|
||||||
|
|
||||||
# Signature
|
|
||||||
"""
|
"""
|
||||||
getDataFrameValue(row::DataFrameRow, key::Symbol) = row.:($key)
|
getDataFrameValue(row::DataFrameRow, key::Symbol) = row.:($key)
|
||||||
|
|
||||||
@@ -636,8 +563,6 @@ end
|
|||||||
julia> dfToString(df)
|
julia> dfToString(df)
|
||||||
"1) name: Alice, age: 25\n2) name: Bob, age: 30"
|
"1) name: Alice, age: 25\n2) name: Bob, age: 30"
|
||||||
```
|
```
|
||||||
|
|
||||||
# Signature
|
|
||||||
"""
|
"""
|
||||||
function dfToString(df::DataFrame)
|
function dfToString(df::DataFrame)
|
||||||
dfstr = ""
|
dfstr = ""
|
||||||
@@ -661,7 +586,7 @@ end
|
|||||||
|
|
||||||
# Example
|
# Example
|
||||||
```jldoctest
|
```jldoctest
|
||||||
julia> using DataFrames
|
julia> using DataFrames, GeneralUtils
|
||||||
|
|
||||||
julia> df = DataFrame(name=["Alice", "Bob"], age=[25, 30])
|
julia> df = DataFrame(name=["Alice", "Bob"], age=[25, 30])
|
||||||
2×2 DataFrame
|
2×2 DataFrame
|
||||||
@@ -671,13 +596,11 @@ end
|
|||||||
│ 1 │ Alice 25
|
│ 1 │ Alice 25
|
||||||
│ 2 │ Bob 30
|
│ 2 │ Bob 30
|
||||||
|
|
||||||
julia> dataframe_to_json_list(df)
|
julia> GeneralUtils.dataframe_to_json_list(df)
|
||||||
2-element Vector{String}:
|
2-element Vector{String}:
|
||||||
"{\"name\":\"Alice\",\"age\":25}"
|
"{\"name\":\"Alice\",\"age\":25}"
|
||||||
"{\"name\":\"Bob\",\"age\":30}"
|
"{\"name\":\"Bob\",\"age\":30}"
|
||||||
```
|
```
|
||||||
|
|
||||||
# Signature
|
|
||||||
"""
|
"""
|
||||||
function dataframe_to_json_list(df::DataFrame)::Vector{String}
|
function dataframe_to_json_list(df::DataFrame)::Vector{String}
|
||||||
json_list = []
|
json_list = []
|
||||||
@@ -711,8 +634,6 @@ end
|
|||||||
julia> dict_to_string(od)
|
julia> dict_to_string(od)
|
||||||
"1) name: Alice, 2) age: 25"
|
"1) name: Alice, 2) age: 25"
|
||||||
```
|
```
|
||||||
|
|
||||||
# Signature
|
|
||||||
"""
|
"""
|
||||||
function dictToString(od::T) where {T<:AbstractDict}
|
function dictToString(od::T) where {T<:AbstractDict}
|
||||||
items = []
|
items = []
|
||||||
@@ -770,46 +691,17 @@ function extract_triple_backtick_text(input::String)::Vector{String}
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
"""
|
wordwindow(word::String, startindex::Integer)::UnitRange = startindex:startindex + length(word) -1
|
||||||
detect_keyword(keyword::String, text::String) -> Union{Nothing, String}
|
|
||||||
|
|
||||||
Detects if a keyword exists in the text in different case variations (lowercase, uppercase first letter, or all uppercase).
|
function cuttext(range, text)
|
||||||
|
# check whether range is outside text boundary
|
||||||
# Arguments:
|
if range.start > length(text) || range.stop > length(text)
|
||||||
- `keyword::String` The keyword to search for
|
|
||||||
- `text::String` The text to search in
|
|
||||||
|
|
||||||
# Returns:
|
|
||||||
- `Union{Nothing, String}` Returns the matched keyword variation if found, otherwise returns nothing
|
|
||||||
|
|
||||||
# Examples:
|
|
||||||
```jldoctest
|
|
||||||
julia> detect_keyword("test", "This is a Test case")
|
|
||||||
"Test"
|
|
||||||
|
|
||||||
julia> detect_keyword("error", "NO ERRORS FOUND")
|
|
||||||
"ERRORS"
|
|
||||||
|
|
||||||
julia> detect_keyword("missing", "complete data")
|
|
||||||
nothing
|
|
||||||
```
|
|
||||||
|
|
||||||
# Signature
|
|
||||||
"""
|
|
||||||
function detect_keyword(keyword::String, text::String)::Union{Nothing, String}
|
|
||||||
# Define the keyword variations to search for
|
|
||||||
keyword_variations = [keyword, uppercasefirst(keyword), uppercase(keyword), lowercase(keyword)]
|
|
||||||
|
|
||||||
# Check if any of the keyword variations are in the text
|
|
||||||
for variation in keyword_variations
|
|
||||||
if occursin(variation, text)
|
|
||||||
return variation
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Return nothing if no variation is found
|
|
||||||
return nothing
|
return nothing
|
||||||
|
else
|
||||||
|
return text[range]
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -855,27 +747,39 @@ end
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
""" Remove French accents from the given text.
|
||||||
remove_french_accents(text::String) -> String
|
|
||||||
|
|
||||||
Remove French accents from the given text.
|
The function replaces accented French characters with their non-accented
|
||||||
|
counterparts using a dictionary mapping. Supported accented characters
|
||||||
|
include: à, â, ä, á, é, è, ê, ë, î, ï, í, ñ, ô, ö, ò, ó, ù, û, ü, ÿ, ç,
|
||||||
|
and their uppercase variants. The apostrophe character `’` is removed
|
||||||
|
completely.
|
||||||
|
|
||||||
# Arguments
|
# Arguments
|
||||||
- `text::String` The input string containing French accents.
|
- `text::AbstractString`
|
||||||
|
The input string containing French accented characters.
|
||||||
|
|
||||||
# Returns
|
# Return
|
||||||
- `String` The input string with all French accents removed.
|
- `AbstractString`: A new string with all French accents replaced by their
|
||||||
|
non-accented equivalents.
|
||||||
|
|
||||||
|
# Notes
|
||||||
|
- The function creates a character list and replaces each accented character
|
||||||
|
according to an internal dictionary mapping.
|
||||||
|
- Does **not** mutate the input; it allocates a new string.
|
||||||
|
|
||||||
# Examples
|
# Examples
|
||||||
```jldoctest
|
```jldoctest
|
||||||
|
julia> using GeneralUtils
|
||||||
julia> remove_french_accents("Café")
|
julia> remove_french_accents("Café")
|
||||||
"Cafe"
|
"Cafe"
|
||||||
|
|
||||||
julia> remove_french_accents("L'été est beau.")
|
julia> remove_french_accents("L'été est beau.")
|
||||||
"L'ete est beau."
|
"L'ete est beau."
|
||||||
```
|
|
||||||
|
|
||||||
# Signature
|
julia> remove_french_accents("Noël, naïve, François")
|
||||||
|
"Noel, naive, Francois"
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
function remove_french_accents(text::AbstractString)::AbstractString
|
function remove_french_accents(text::AbstractString)::AbstractString
|
||||||
textcharlist = [i for i in text]
|
textcharlist = [i for i in text]
|
||||||
@@ -924,9 +828,11 @@ Extracts and returns the text that is enclosed between two specified characters
|
|||||||
|
|
||||||
# Examples
|
# Examples
|
||||||
```jldoctest
|
```jldoctest
|
||||||
julia> text = "Hello [World]!"
|
julia> text = "Hello [World]! [Yay]"
|
||||||
julia> extracted_text = extractTextBetweenCharacter(text, '[', ']')
|
julia> extracted_text = extractTextBetweenCharacter(text, '[', ']')
|
||||||
println(extracted_text) # Output: "World"
|
2-element Vector{Any}:
|
||||||
|
"World"
|
||||||
|
"Yay"
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
function extractTextBetweenCharacter(text::String, startchar::Char, endchar::Char)
|
function extractTextBetweenCharacter(text::String, startchar::Char, endchar::Char)
|
||||||
@@ -950,6 +856,29 @@ function extractTextBetweenCharacter(text::String, startchar::Char, endchar::Cha
|
|||||||
end
|
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.
|
Determines if the given string follows camel case naming convention.
|
||||||
|
|
||||||
@@ -1075,10 +1004,173 @@ function convertCamelSnakeKebabCase(text::T, tocase::Symbol)::String where {T<:A
|
|||||||
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
|
||||||
|
|
||||||
|
""" Remove specified substrings from text.
|
||||||
|
|
||||||
|
Removes all occurrences of each string in `removelist` from the input text
|
||||||
|
by repeatedly replacing them with empty strings until none remain.
|
||||||
|
|
||||||
|
# Arguments
|
||||||
|
- `text::String`
|
||||||
|
The input string to modify.
|
||||||
|
- `removelist::Vector{String}`
|
||||||
|
A vector of substrings to remove from the text.
|
||||||
|
|
||||||
|
# Return
|
||||||
|
- `String`: The text with all specified substrings removed.
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
```jldoctest
|
||||||
|
julia> using GeneralUtils
|
||||||
|
julia> removestring("hello world", ["l", " "])
|
||||||
|
"heoword"
|
||||||
|
julia> removestring("foo bar baz", ["bar", " "])
|
||||||
|
"foobaz"
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
function removestring(text::String, removelist::Vector{String})::String
|
||||||
|
for i in removelist
|
||||||
|
while occursin(i, text)
|
||||||
|
text = replace(text, i => "")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return string(text)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Vendored
+3
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"julia.environmentPath": "/appfolder/app/dev/GeneralUtils/test"
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# This file is machine-generated - editing it directly is not advised
|
||||||
|
|
||||||
|
julia_version = "1.11.4"
|
||||||
|
manifest_format = "2.0"
|
||||||
|
project_hash = "71d91126b5a1fb1020e1098d9d492de2a4438fd2"
|
||||||
|
|
||||||
|
[[deps.Base64]]
|
||||||
|
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
|
||||||
|
version = "1.11.0"
|
||||||
|
|
||||||
|
[[deps.InteractiveUtils]]
|
||||||
|
deps = ["Markdown"]
|
||||||
|
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
|
||||||
|
version = "1.11.0"
|
||||||
|
|
||||||
|
[[deps.Logging]]
|
||||||
|
uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"
|
||||||
|
version = "1.11.0"
|
||||||
|
|
||||||
|
[[deps.Markdown]]
|
||||||
|
deps = ["Base64"]
|
||||||
|
uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"
|
||||||
|
version = "1.11.0"
|
||||||
|
|
||||||
|
[[deps.Random]]
|
||||||
|
deps = ["SHA"]
|
||||||
|
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
|
||||||
|
version = "1.11.0"
|
||||||
|
|
||||||
|
[[deps.SHA]]
|
||||||
|
uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"
|
||||||
|
version = "0.7.0"
|
||||||
|
|
||||||
|
[[deps.Serialization]]
|
||||||
|
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
|
||||||
|
version = "1.11.0"
|
||||||
|
|
||||||
|
[[deps.Test]]
|
||||||
|
deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
|
||||||
|
uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
|
||||||
|
version = "1.11.0"
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
[deps]
|
||||||
|
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
using Revise
|
|
||||||
using GeneralUtils, MQTTClient, JSON3
|
|
||||||
|
|
||||||
mqttMsgReceiveTopic = ["/receivetopic_1", "/receivetopic_2"]
|
|
||||||
mqttMsgReceiveChannel = (ch1=Channel(8), ch2=Channel(32))
|
|
||||||
keepaliveChannel = Channel(8)
|
|
||||||
function onMsgCallback(topic, payload)
|
|
||||||
jobj = JSON3.read(String(payload))
|
|
||||||
incomingMqttMsg = copy(jobj) # convert json object into julia dictionary recursively
|
|
||||||
|
|
||||||
if occursin("topic_1", topic)
|
|
||||||
put!(mqttMsgReceiveChannel[:ch1], incomingMqttMsg)
|
|
||||||
elseif occursin("topic_2", topic)
|
|
||||||
put!(mqttMsgReceiveChannel[:ch2], incomingMqttMsg)
|
|
||||||
elseif occursin("keepalive", topic)
|
|
||||||
put!(keepaliveChannel, incomingMqttMsg)
|
|
||||||
else
|
|
||||||
println("undefined condition ", @__FILE__, " ", @__LINE__)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
mqttInstance = GeneralUtils.mqttClientInstance_v2(
|
|
||||||
"mqtt.yiem.cc",
|
|
||||||
mqttMsgReceiveTopic,
|
|
||||||
mqttMsgReceiveChannel,
|
|
||||||
keepaliveChannel,
|
|
||||||
onMsgCallback
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
_ = GeneralUtils.checkMqttConnection!(mqttInstance)
|
|
||||||
|
|
||||||
|
|
||||||
println("GeneralUtils test done")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
using Test
|
||||||
|
using GeneralUtils: detect_keyword
|
||||||
|
|
||||||
|
@testset "detect_keyword tests" begin
|
||||||
|
@test detect_keyword(["test"], "this is a test") == Dict("test" => 1)
|
||||||
|
|
||||||
|
@test detect_keyword(["hello", "world"], "hello world hello") == Dict("hello" => 2, "world" => 1)
|
||||||
|
|
||||||
|
@test detect_keyword(["cat"], "category") == Dict("cat" => 1)
|
||||||
|
|
||||||
|
@test detect_keyword(["cat"], "category"; mode="individual") == Dict("cat" => 0)
|
||||||
|
|
||||||
|
@test detect_keyword(["dog"], "dogs and cats"; mode="individual", delimiter=[' ']) == Dict("dog" => 0)
|
||||||
|
|
||||||
|
@test detect_keyword(["test"], "test.case"; mode="individual", delimiter=['.']) == Dict("test" => 1)
|
||||||
|
|
||||||
|
@test detect_keyword(["word"], "") == Dict("word" => 0)
|
||||||
|
|
||||||
|
@test detect_keyword(String[], "some text") == Dict{String, Integer}()
|
||||||
|
|
||||||
|
@test detect_keyword(["a", "b"], "a.b\nc"; delimiter=['.', '\n']) == Dict("a" => 1, "b" => 1)
|
||||||
|
|
||||||
|
multiline_text = """
|
||||||
|
first line
|
||||||
|
second line
|
||||||
|
first word
|
||||||
|
"""
|
||||||
|
@test detect_keyword(["first"], multiline_text) == Dict("first" => 2)
|
||||||
|
|
||||||
|
@test detect_keyword(["word"], "word"; mode="individual") == Dict("word" => 1)
|
||||||
|
|
||||||
|
@test detect_keyword(["test"], "testing.test.tester"; mode="individual", delimiter=['.']) == Dict("test" => 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user