TeeChart Data source as Excel file for the series - activex

Can anyone help me out with how can I read Series Data ( X, Y and Series Naane) In Teechart from excel. I tried with CSeriesTextSource to read a Data.xls file but was not successful.
Thanks
Akshay

You can create a csv from your xls and then import this csv with CSeriesTextSource as in the example published here.
EDIT: Here it is the code from that post:
Private Sub Form_Load()
TChart1.Aspect.View3D = False
TChart1.Axis.Bottom.Labels.Style = 2 'talValue
TChart1.Axis.Left.Logarithmic = True
TChart1.AddSeries scFastLine
TChart1.AddSeries scFastLine
TChart1.AddSeries scPoint
TChart1.AddSeries scPoint
TChart1.Series(0).XValues.DateTime = True
TChart1.Series(1).XValues.DateTime = True
TChart1.Series(2).XValues.DateTime = True
TChart1.Series(3).XValues.DateTime = True
With SeriesTextSource1
.FileName = "C:\tmp\Data.csv"
.HeaderLines = 1
.FieldSeparator = ";"
.Series = TChart1.Series(0)
.AddField "X", 1
.AddField "Y", 2
.Active = True
.Series = TChart1.Series(1)
.AddField "X", 3
.AddField "Y", 4
.Active = True
' This works with v2012, but with v8
' .Series = TChart1.Series(2)
' .AddField "X", 5
' .AddField "Y", 6
' .Active = True
'
' .Series = TChart1.Series(3)
' .AddField "X", 7
' .AddField "Y", 8
' .Active = True
End With
' I add the values manually in v8:
TChart1.Series(2).AddXY CDate("10/11/2003"), 0, "", clTeeColor
TChart1.Series(3).AddXY CDate("01/02/1999"), 231.48, "", clTeeColor
End Sub
Private Sub TChart1_OnClick()
Caption = "Min: " + FormatDateTime(TChart1.Axis.Bottom.MinVisibleSeriesValue(True, 0)) + ", Max: " + FormatDateTime(TChart1.Axis.Bottom.MaxVisibleSeriesValue(True, 0))
End Sub
You can download the csv with the data for testing here.

Related

Unit root test on lagged variables

guys!
I'm using this sintaxe but when I use the last part ("modelo = ...") it shows the following: "Error in merge.zoo(difetanol, detanol, mes2, mes3, mes4, mes5, mes6, mes7, :
all(sapply(args, function(x) is.zoo(x) || !is.plain(x) || (is.plain(x) && .... is not TRUE"
ethidra = (tsrelatorio[,"etanol"])
ethidra
length(ethidra)
acuavhp = (tsrelatorio[,"avhp"])
acuavhp
length(acuavhp)```
matr <- matrix(0, nr = 12, nc = 12)
matr[row(matr) == col(matr)] <- 1
matr
Djt <- rbind(matr,matr,matr,matr); Djt
dim(Djt)
names(Djt)
dimnames(Djt) = list(c(),c("M1", "M2", "M3", "M4","M5","M6","M7","M8","M9","M10","M11","M12"))
Djt
dim(Djt)```
teste=data.frame(Djt)
attach(teste)
mes2= teste[1:47,2]
mes2
length(mes2)
mes3= teste[1:47,3]
mes3
length(mes3)
mes4= teste[1:47,4]
mes4
length(mes4)
mes5= teste[1:47,5]
mes5
length(mes5)
mes6= teste[1:47,6]
mes6
length(mes6)
mes7= teste[1:47,7]
mes7
length(mes7)
mes8= teste[1:47,8]
mes8
length(mes8)
mes9= teste[1:47,9]
mes9
length(mes9)
mes10= teste[1:47,10]
mes10
length(mes10)
mes11= teste[1:47,11]
mes11
length(mes11)
mes12= teste[1:47,12]
mes12
length(mes12)
detanol = (ethidra[1:47])
detanol
length(detanol)
difetanol=diff(detanol)
difetanol
length(difetanol)
tempo = tempo <- seq(1:47)
modelo = dynlm(difetanol ~ detanol + mes2 +mes3 +mes4 + mes5 + mes6 + mes7 + mes8 + mes9 + mes10 + mes11 + mes12 + tempo + L(difetanol,1) + L(difetanol,2))
summary(modelo)

ggplotly tooltip is showing data twice

I have 2 datasets included in one chart using ggplot. I am using ggplotly to create a tooltip but the information in the tooltips for the 2 points is showing twice. The following code is a little lengthy but will recreate the chart:
AreaName <- c("A", "B", "C", "A", "B", "C")
Timeperiod <- c("2018", "2018", "2018", "2019", "2019", "2019")
Value <- c(11.5, 39.3, 9.4, 14.2, 40.7, 19.1)
df <- data.frame(cbind(AreaName, Timeperiod, Value), stringsAsFactors = F)
df$Value <- as.numeric(df$Value)
AreaName <- c("A", "A")
Timeperiod <- c("2019", "2020")
qtr <- c("Q1-Q2", "Q1-Q2")
Value <- c(15.6, 10.2)
df2 <- data.frame(cbind(Timeperiod, qtr, AreaName, Value), stringsAsFactors = F)
df2$Value <- as.numeric(df2$Value)
ggp <- ggplotly(ggplot(data = df, aes(x=Timeperiod, y=Value, group = AreaName, colour = AreaName, text = paste("Area name: ", AreaName, "<br>Time period: ", Timeperiod, "<br>Rate: ", round(Value,1), "per 100,000"))) +
geom_line() +
geom_point() +
geom_point(data = df2, aes(shape = c(paste(AreaName, qtr, Timeperiod)),text = paste("Area name: ", AreaName, "<br>Quarter: ", qtr, "<br>Time period: ", Timeperiod, "<br>Rate: ", round(Value,1), "per 100,000"))) +
scale_shape_manual(values = c(18, 17)) +
theme(axis.text.x = element_text(vjust = 0.5), axis.title.x = element_blank()) +
labs(y = "Crude rate per 100,000 persons all ages", colour = "Area", shape = "") +
guides(shape = guide_legend(order = 2),colour = guide_legend(order = 1)) +
expand_limits(y=0), tooltip = "text")
ggpNames <- unique(df$AreaName)
legs <- paste(df2$AreaName, df2$qtr, df2$Timeperiod)
ggpNames <- c(ggpNames,legs)
for (i in 1:length(ggp$x$data)) { # this goes over all places where legend values are stored
n1 <- ggp$x$data[[i]]$name # and this is how the value is stored in plotly
n2 <- " "
for (j in 1:length(ggpNames)) {
if (grepl(x = n1, pattern = ggpNames[j])) {n2 = ggpNames[j]} # if the plotly legend name contains the original value, replace it with the original value
}
ggp$x$data[[i]]$name <- n2 # now is the time for actual replacement
if (n2 == " ") {ggp$x$data[[i]]$showlegend = FALSE} # sometimes plotly adds to the legend values that we don't want, this is how to get rid of them, too
}
ggp %>% config(displaylogo = FALSE, modeBarButtonsToRemove = list("autoScale2d", "resetScale2d","select2d", "lasso2d", "zoomIn2d", "zoomOut2d", "toggleSpikelines", "zoom2d", "pan2d"))
ggp
Does anyone have an elegant solution to this?
Thanks
Do not define text in geom_point for the second dataframe df2. Then you will get only one tooltip for those two points.
ggp <- ggplotly(ggplot(data = df, aes(x=Timeperiod, y=Value, group = AreaName, colour = AreaName, text = paste("Area name: ", AreaName, "<br>Time period: ", Timeperiod, "<br>Rate: ", round(Value,1), "per 100,000"))) +
geom_line() +
geom_point() +
geom_point(data = df2, aes(shape = c(paste(AreaName, qtr, Timeperiod)) #,
#text = paste("Area name: ", AreaName, "<br>Quarter: ", qtr, "<br>Time period: ", Timeperiod, "<br>Rate: ", round(Value,1), "per 100,000")
)) +
scale_shape_manual(values = c(18, 17)) +
theme(axis.text.x = element_text(vjust = 0.5), axis.title.x = element_blank()) +
labs(y = "Crude rate per 100,000 persons all ages", colour = "Area", shape = "") +
guides(shape = guide_legend(order = 2),colour = guide_legend(order = 1)) +
expand_limits(y=0), tooltip = "text")
ggpNames <- unique(df$AreaName)
legs <- paste(df2$AreaName, df2$qtr, df2$Timeperiod)
ggpNames <- c(ggpNames,legs)
for (i in 1:length(ggp$x$data)) { # this goes over all places where legend values are stored
n1 <- ggp$x$data[[i]]$name # and this is how the value is stored in plotly
n2 <- " "
for (j in 1:length(ggpNames)) {
if (grepl(x = n1, pattern = ggpNames[j])) {n2 = ggpNames[j]} # if the plotly legend name contains the original value, replace it with the original value
}
ggp$x$data[[i]]$name <- n2 # now is the time for actual replacement
if (n2 == " ") {ggp$x$data[[i]]$showlegend = FALSE} # sometimes plotly adds to the legend values that we don't want, this is how to get rid of them, too
}
ggp %>% config(displaylogo = FALSE, modeBarButtonsToRemove = list("autoScale2d", "resetScale2d","select2d", "lasso2d", "zoomIn2d", "zoomOut2d", "toggleSpikelines", "zoom2d", "pan2d"))
ggp

Rails lazy_high_charts: how to format tooltip label

I would to print into my charts the hours and minutes, for example "development: 27 h 30 m".
Now I have this:
In my script "data" represents "hours"
{
name: value.blank? ? "other" : value,
data: all_weeks.merge(data_weeks.to_h).values.map do |data_value|
data_value.nil? ? 0 : ( data_value.to_f / 60 ).round(2)
end
}
....
f.tooltip(
pointFormat: "<span style='color:{series.color}'>{series.name}</span>: <b>{point.y} h</b><br/>",
split: true
)
I have tried to set point.y into pointFormat but no have effects. ( Edit: pointFormat would a generic string! )
How can I solve? Thanks in advance.
Edit:
I solved adding:
LazyHighCharts::HighChart.new("container") do |f|
f.tooltip(
formatter: "\
function() { \
var s = []; \
s.push(this.x); \
this.points.forEach(function(point) { \
s.push('<b>' + point.series.name + '</b>: ' + Math.floor(point.y) + ' h ' + Math.floor((point.y % 1) * 60) + ' m'); \
}); \
return s; \
}".js_code,
split: true
)
....
end
Maybe you could introduce two variables, data_hours and data_minutes, and write a string interpolation with theses variables.
data_hours = data_value.to_i
data_minutes = ((data_value - data_hours) * 60).to_i
data_to_display = "#{data_hours} h #{data_minutes} m"
Hope it will help !
Written in 0.12 hours ;)
["dev: 27.5 h", "dev: 22 h", "dev: 0.3h"].map do |s|
s.gsub(/\d+(\.\d+)?\s*h/i) do |h|
h, m = h.to_f.divmod(1)
[
("#{h} h" unless h.zero?),
("#{(60 * m).round} m" unless m.zero?)
].compact.join(" ")
end
end
#⇒ ["dev: 27 h 30 m", "dev: 22 h", "dev: 18 m"]

How to dump a table to console?

I'm having trouble displaying the contents of a table which contains nested tables (n-deep). I'd like to just dump it to std out or the console via a print statement or something quick and dirty but I can't figure out how. I'm looking for the rough equivalent that I'd get when printing an NSDictionary using gdb.
If the requirement is "quick and dirty"
I've found this one useful. Because of the recursion it can print nested tables too. It doesn't give the prettiest formatting in the output but for such a simple function it's hard to beat for debugging.
function dump(o)
if type(o) == 'table' then
local s = '{ '
for k,v in pairs(o) do
if type(k) ~= 'number' then k = '"'..k..'"' end
s = s .. '['..k..'] = ' .. dump(v) .. ','
end
return s .. '} '
else
return tostring(o)
end
end
e.g.
local people = {
{
name = "Fred",
address = "16 Long Street",
phone = "123456"
},
{
name = "Wilma",
address = "16 Long Street",
phone = "123456"
},
{
name = "Barney",
address = "17 Long Street",
phone = "123457"
}
}
print("People:", dump(people))
Produces the following output:
People: { [1] = { ["address"] = 16 Long Street,["phone"] =
123456,["name"] = Fred,} ,[2] = { ["address"] = 16 Long
Street,["phone"] = 123456,["name"] = Wilma,} ,[3] = { ["address"] = 17
Long Street,["phone"] = 123457,["name"] = Barney,} ,}
I know this question has already been marked as answered, but let me plug my own library here. It's called inspect.lua, and you can find it here:
https://github.com/kikito/inspect.lua
It's just a single file that you can require from any other file. It returns a function that transforms any Lua value into a human-readable string:
local inspect = require('inspect')
print(inspect({1,2,3})) -- {1, 2, 3}
print(inspect({a=1,b=2})
-- {
-- a = 1
-- b = 2
-- }
It indents subtables properly, and handles "recursive tables" (tables that contain references to themselves) correctly, so it doesn't get into infinite loops. It sorts values in a sensible way. It also prints metatable information.
Regards!
Feel free to browse the Lua Wiki on table serialization. It lists several ways on how to dump a table to the console.
You just have to choose which one suits you best. There are many ways to do it, but I usually end up using the one from Penlight:
> t = { a = { b = { c = "Hello world!", 1 }, 2, d = { 3 } } }
> require 'pl.pretty'.dump(t)
{
a = {
d = {
3
},
b = {
c = "Hello world!",
1
},
2
}
}
found this:
-- Print contents of `tbl`, with indentation.
-- `indent` sets the initial level of indentation.
function tprint (tbl, indent)
if not indent then indent = 0 end
for k, v in pairs(tbl) do
formatting = string.rep(" ", indent) .. k .. ": "
if type(v) == "table" then
print(formatting)
tprint(v, indent+1)
elseif type(v) == 'boolean' then
print(formatting .. tostring(v))
else
print(formatting .. v)
end
end
end
from here
https://gist.github.com/ripter/4270799
works pretty good for me...
Most pure lua print table functions I've seen have a problem with deep recursion
and tend to cause a stack overflow when going too deep. This print
table function that I've written does not have this problem. It should also be capable of handling really large tables due to the way it handles concatenation. In my personal usage of this function, it outputted 63k lines to file in about a second.
The output also keeps lua syntax and the script can easily be modified
for simple persistent storage by writing the output to file if modified to allow
only number, boolean, string and table data types to be formatted.
function print_table(node)
local cache, stack, output = {},{},{}
local depth = 1
local output_str = "{\n"
while true do
local size = 0
for k,v in pairs(node) do
size = size + 1
end
local cur_index = 1
for k,v in pairs(node) do
if (cache[node] == nil) or (cur_index >= cache[node]) then
if (string.find(output_str,"}",output_str:len())) then
output_str = output_str .. ",\n"
elseif not (string.find(output_str,"\n",output_str:len())) then
output_str = output_str .. "\n"
end
-- This is necessary for working with HUGE tables otherwise we run out of memory using concat on huge strings
table.insert(output,output_str)
output_str = ""
local key
if (type(k) == "number" or type(k) == "boolean") then
key = "["..tostring(k).."]"
else
key = "['"..tostring(k).."']"
end
if (type(v) == "number" or type(v) == "boolean") then
output_str = output_str .. string.rep('\t',depth) .. key .. " = "..tostring(v)
elseif (type(v) == "table") then
output_str = output_str .. string.rep('\t',depth) .. key .. " = {\n"
table.insert(stack,node)
table.insert(stack,v)
cache[node] = cur_index+1
break
else
output_str = output_str .. string.rep('\t',depth) .. key .. " = '"..tostring(v).."'"
end
if (cur_index == size) then
output_str = output_str .. "\n" .. string.rep('\t',depth-1) .. "}"
else
output_str = output_str .. ","
end
else
-- close the table
if (cur_index == size) then
output_str = output_str .. "\n" .. string.rep('\t',depth-1) .. "}"
end
end
cur_index = cur_index + 1
end
if (size == 0) then
output_str = output_str .. "\n" .. string.rep('\t',depth-1) .. "}"
end
if (#stack > 0) then
node = stack[#stack]
stack[#stack] = nil
depth = cache[node] == nil and depth + 1 or depth - 1
else
break
end
end
-- This is necessary for working with HUGE tables otherwise we run out of memory using concat on huge strings
table.insert(output,output_str)
output_str = table.concat(output)
print(output_str)
end
Here is an example:
local t = {
["abe"] = {1,2,3,4,5},
"string1",
50,
["depth1"] = { ["depth2"] = { ["depth3"] = { ["depth4"] = { ["depth5"] = { ["depth6"] = { ["depth7"]= { ["depth8"] = { ["depth9"] = { ["depth10"] = {1000}, 900}, 800},700},600},500}, 400 }, 300}, 200}, 100},
["ted"] = {true,false,"some text"},
"string2",
[function() return end] = function() return end,
75
}
print_table(t)
Output:
{
[1] = 'string1',
[2] = 50,
[3] = 'string2',
[4] = 75,
['abe'] = {
[1] = 1,
[2] = 2,
[3] = 3,
[4] = 4,
[5] = 5
},
['function: 06472B70'] = 'function: 06472A98',
['depth1'] = {
[1] = 100,
['depth2'] = {
[1] = 200,
['depth3'] = {
[1] = 300,
['depth4'] = {
[1] = 400,
['depth5'] = {
[1] = 500,
['depth6'] = {
[1] = 600,
['depth7'] = {
[1] = 700,
['depth8'] = {
[1] = 800,
['depth9'] = {
[1] = 900,
['depth10'] = {
[1] = 1000
}
}
}
}
}
}
}
}
}
},
['ted'] = {
[1] = true,
[2] = false,
[3] = 'some text'
}
}
As previously mentioned, you have to write it.
Here is my humble version: (super basic one)
function tprint (t, s)
for k, v in pairs(t) do
local kfmt = '["' .. tostring(k) ..'"]'
if type(k) ~= 'string' then
kfmt = '[' .. k .. ']'
end
local vfmt = '"'.. tostring(v) ..'"'
if type(v) == 'table' then
tprint(v, (s or '')..kfmt)
else
if type(v) ~= 'string' then
vfmt = tostring(v)
end
print(type(t)..(s or '')..kfmt..' = '..vfmt)
end
end
end
example:
local mytbl = { ['1']="a", 2, 3, b="c", t={d=1} }
tprint(mytbl)
output (Lua 5.0):
table[1] = 2
table[2] = 3
table["1"] = "a"
table["t"]["d"] = 1
table["b"] = "c"
I use my own function to print the contents of a table but not sure how well it translates to your environment:
---A helper function to print a table's contents.
---#param tbl table #The table to print.
---#param depth number #The depth of sub-tables to traverse through and print.
---#param n number #Do NOT manually set this. This controls formatting through recursion.
function PrintTable(tbl, depth, n)
n = n or 0;
depth = depth or 5;
if (depth == 0) then
print(string.rep(' ', n).."...");
return;
end
if (n == 0) then
print(" ");
end
for key, value in pairs(tbl) do
if (key and type(key) == "number" or type(key) == "string") then
key = string.format("[\"%s\"]", key);
if (type(value) == "table") then
if (next(value)) then
print(string.rep(' ', n)..key.." = {");
PrintTable(value, depth - 1, n + 4);
print(string.rep(' ', n).."},");
else
print(string.rep(' ', n)..key.." = {},");
end
else
if (type(value) == "string") then
value = string.format("\"%s\"", value);
else
value = tostring(value);
end
print(string.rep(' ', n)..key.." = "..value..",");
end
end
end
if (n == 0) then
print(" ");
end
end
The simplest way, with circular reference handling and all:
function dump(t, indent, done)
done = done or {}
indent = indent or 0
done[t] = true
for key, value in pairs(t) do
print(string.rep("\t", indent))
if type(value) == "table" and not done[value] then
done[value] = true
print(key, ":\n")
dump(value, indent + 2, done)
done[value] = nil
else
print(key, "\t=\t", value, "\n")
end
end
end
There are 2 solutions that I want to mention: a quick&dirty one, and another which properly escapes all keys and values but is bigger
Simple & fast solution (use only on "safe" inputs):
local function format_any_value(obj, buffer)
local _type = type(obj)
if _type == "table" then
buffer[#buffer + 1] = '{"'
for key, value in next, obj, nil do
buffer[#buffer + 1] = tostring(key) .. '":'
format_any_value(value, buffer)
buffer[#buffer + 1] = ',"'
end
buffer[#buffer] = '}' -- note the overwrite
elseif _type == "string" then
buffer[#buffer + 1] = '"' .. obj .. '"'
elseif _type == "boolean" or _type == "number" then
buffer[#buffer + 1] = tostring(obj)
else
buffer[#buffer + 1] = '"???' .. _type .. '???"'
end
end
Usage:
local function format_as_json(obj)
if obj == nil then return "null" else
local buffer = {}
format_any_value(obj, buffer)
return table.concat(buffer)
end
end
local function print_as_json(obj)
print(_format_as_json(obj))
end
print_as_json {1, 2, 3}
print_as_json(nil)
print_as_json("string")
print_as_json {[1] = 1, [2] = 2, three = { { true } }, four = "four"}
Correct solution with key/value escaping
Small library that I wrote in pure Lua for this specific use-case: https://github.com/vn971/fast_json_encode
Or specifically this 1 file that includes both a formatter and a printer: https://github.com/vn971/fast_json_encode/blob/master/json_format.lua
You have to code it yourself I'm afraid. I wrote this, and it may be of some use to you
function printtable(table, indent)
indent = indent or 0;
local keys = {};
for k in pairs(table) do
keys[#keys+1] = k;
table.sort(keys, function(a, b)
local ta, tb = type(a), type(b);
if (ta ~= tb) then
return ta < tb;
else
return a < b;
end
end);
end
print(string.rep(' ', indent)..'{');
indent = indent + 1;
for k, v in pairs(table) do
local key = k;
if (type(key) == 'string') then
if not (string.match(key, '^[A-Za-z_][0-9A-Za-z_]*$')) then
key = "['"..key.."']";
end
elseif (type(key) == 'number') then
key = "["..key.."]";
end
if (type(v) == 'table') then
if (next(v)) then
printf("%s%s =", string.rep(' ', indent), tostring(key));
printtable(v, indent);
else
printf("%s%s = {},", string.rep(' ', indent), tostring(key));
end
elseif (type(v) == 'string') then
printf("%s%s = %s,", string.rep(' ', indent), tostring(key), "'"..v.."'");
else
printf("%s%s = %s,", string.rep(' ', indent), tostring(key), tostring(v));
end
end
indent = indent - 1;
print(string.rep(' ', indent)..'}');
end
The table.tostring metehod of metalua is actually very complete. It deals with nested tables, the indentation level is changeable, ...
See https://github.com/fab13n/metalua/blob/master/src/lib/metalua/table2.lua
This is my version that supports excluding tables and userdata
-- Lua Table View by Elertan
table.print = function(t, exclusions)
local nests = 0
if not exclusions then exclusions = {} end
local recurse = function(t, recurse, exclusions)
indent = function()
for i = 1, nests do
io.write(" ")
end
end
local excluded = function(key)
for k,v in pairs(exclusions) do
if v == key then
return true
end
end
return false
end
local isFirst = true
for k,v in pairs(t) do
if isFirst then
indent()
print("|")
isFirst = false
end
if type(v) == "table" and not excluded(k) then
indent()
print("|-> "..k..": "..type(v))
nests = nests + 1
recurse(v, recurse, exclusions)
elseif excluded(k) then
indent()
print("|-> "..k..": "..type(v))
elseif type(v) == "userdata" or type(v) == "function" then
indent()
print("|-> "..k..": "..type(v))
elseif type(v) == "string" then
indent()
print("|-> "..k..": ".."\""..v.."\"")
else
indent()
print("|-> "..k..": "..v)
end
end
nests = nests - 1
end
nests = 0
print("### START TABLE ###")
for k,v in pairs(t) do
print("root")
if type(v) == "table" then
print("|-> "..k..": "..type(v))
nests = nests + 1
recurse(v, recurse, exclusions)
elseif type(v) == "userdata" or type(v) == "function" then
print("|-> "..k..": "..type(v))
elseif type(v) == "string" then
print("|-> "..k..": ".."\""..v.."\"")
else
print("|-> "..k..": "..v)
end
end
print("### END TABLE ###")
end
This is an example
t = {
location = {
x = 10,
y = 20
},
size = {
width = 100000000,
height = 1000,
},
name = "Sidney",
test = {
hi = "lol",
},
anotherone = {
1,
2,
3
}
}
table.print(t, { "test" })
Prints:
### START TABLE ###
root
|-> size: table
|
|-> height: 1000
|-> width: 100000000
root
|-> location: table
|
|-> y: 20
|-> x: 10
root
|-> anotherone: table
|
|-> 1: 1
|-> 2: 2
|-> 3: 3
root
|-> test: table
|
|-> hi: "lol"
root
|-> name: "Sidney"
### END TABLE ###
Notice that the root doesn't remove exclusions
Made this version to print tables with identation. Can probably be extended to work recursively.
function printtable(table, indent)
print(tostring(table) .. '\n')
for index, value in pairs(table) do
print(' ' .. tostring(index) .. ' : ' .. tostring(value) .. '\n')
end
end
--~ print a table
function printTable(list, i)
local listString = ''
--~ begin of the list so write the {
if not i then
listString = listString .. '{'
end
i = i or 1
local element = list[i]
--~ it may be the end of the list
if not element then
return listString .. '}'
end
--~ if the element is a list too call it recursively
if(type(element) == 'table') then
listString = listString .. printTable(element)
else
listString = listString .. element
end
return listString .. ', ' .. printTable(list, i + 1)
end
local table = {1, 2, 3, 4, 5, {'a', 'b'}, {'G', 'F'}}
print(printTable(table))
Hi man, I wrote a siple code that do this in pure Lua, it has a bug (write a coma after the last element of the list) but how i wrote it quickly as a prototype I will let it to you adapt it to your needs.
Adding another version. This one tries to iterate over userdata as well.
function inspect(o,indent)
if indent == nil then indent = 0 end
local indent_str = string.rep(" ", indent)
local output_it = function(str)
print(indent_str..str)
end
local length = 0
local fu = function(k, v)
length = length + 1
if type(v) == "userdata" or type(v) == 'table' then
output_it(indent_str.."["..k.."]")
inspect(v, indent+1)
else
output_it(indent_str.."["..k.."] "..tostring(v))
end
end
local loop_pairs = function()
for k,v in pairs(o) do fu(k,v) end
end
local loop_metatable_pairs = function()
for k,v in pairs(getmetatable(o)) do fu(k,v) end
end
if not pcall(loop_pairs) and not pcall(loop_metatable_pairs) then
output_it(indent_str.."[[??]]")
else
if length == 0 then
output_it(indent_str.."{}")
end
end
end
Convert to json and then print.
local json = require('cjson')
json_string = json.encode(this_table)
print (json_string)
simple example of dump a table in lua
i suggest using serpent.lua
local function parser(value, indent, subcategory)
local indent = indent or 2
local response = '(\n'
local subcategory = type(subcategory) == 'number' and subcategory or indent
for key, value in pairs(value) do
if type(value) == 'table' then
value = parser(value, indent, subcategory + indent)
elseif type(value) == 'string' then
value = '\''.. value .. '\''
elseif type(value) ~= 'number' then
value = tostring(value)
end
if type(tonumber(key)) == 'number' then
key = '[' .. key .. ']'
elseif not key:match('^([A-Za-z_][A-Za-z0-9_]*)$') then
key = '[\'' .. key .. '\']'
end
response = response .. string.rep(' ', subcategory) .. key .. ' = ' .. value .. ',\n'
end
return response .. string.rep(' ', subcategory - indent) .. ')'
end
example
response = parser{1,2,3, {ok = 10, {}}}
print(response)
result
(
[1] = 1,
[2] = 2,
[3] = 3,
[4] = (
[1] = (),
ok = 10
)
)
here's my little snippet for that:
--- Dump value of a variable in a formatted string
--
--- #param o table Dumpable object
--- #param tbs string|nil Tabulation string, ' ' by default
--- #param tb number|nil Initial tabulation level, 0 by default
--- #return string
local function dump(o, tbs, tb)
tb = tb or 0
tbs = tbs or ' '
if type(o) == 'table' then
local s = '{'
if (next(o)) then s = s .. '\n' else return s .. '}' end
tb = tb + 1
for k,v in pairs(o) do
if type(k) ~= 'number' then k = '"' .. k .. '"' end
s = s .. tbs:rep(tb) .. '[' .. k .. '] = ' .. dump(v, tbs, tb)
s = s .. ',\n'
end
tb = tb - 1
return s .. tbs:rep(tb) .. '}'
else
return tostring(o)
end
end
I have humbly modified a bit Alundaio code:
-- by Alundaio
-- KK modified 11/28/2019
function dump_table_to_string(node, tree, indentation)
local cache, stack, output = {},{},{}
local depth = 1
if type(node) ~= "table" then
return "only table type is supported, got " .. type(node)
end
if nil == indentation then indentation = 1 end
local NEW_LINE = "\n"
local TAB_CHAR = " "
if nil == tree then
NEW_LINE = "\n"
elseif not tree then
NEW_LINE = ""
TAB_CHAR = ""
end
local output_str = "{" .. NEW_LINE
while true do
local size = 0
for k,v in pairs(node) do
size = size + 1
end
local cur_index = 1
for k,v in pairs(node) do
if (cache[node] == nil) or (cur_index >= cache[node]) then
if (string.find(output_str,"}",output_str:len())) then
output_str = output_str .. "," .. NEW_LINE
elseif not (string.find(output_str,NEW_LINE,output_str:len())) then
output_str = output_str .. NEW_LINE
end
-- This is necessary for working with HUGE tables otherwise we run out of memory using concat on huge strings
table.insert(output,output_str)
output_str = ""
local key
if (type(k) == "number" or type(k) == "boolean") then
key = "["..tostring(k).."]"
else
key = "['"..tostring(k).."']"
end
if (type(v) == "number" or type(v) == "boolean") then
output_str = output_str .. string.rep(TAB_CHAR,depth*indentation) .. key .. " = "..tostring(v)
elseif (type(v) == "table") then
output_str = output_str .. string.rep(TAB_CHAR,depth*indentation) .. key .. " = {" .. NEW_LINE
table.insert(stack,node)
table.insert(stack,v)
cache[node] = cur_index+1
break
else
output_str = output_str .. string.rep(TAB_CHAR,depth*indentation) .. key .. " = '"..tostring(v).."'"
end
if (cur_index == size) then
output_str = output_str .. NEW_LINE .. string.rep(TAB_CHAR,(depth-1)*indentation) .. "}"
else
output_str = output_str .. ","
end
else
-- close the table
if (cur_index == size) then
output_str = output_str .. NEW_LINE .. string.rep(TAB_CHAR,(depth-1)*indentation) .. "}"
end
end
cur_index = cur_index + 1
end
if (size == 0) then
output_str = output_str .. NEW_LINE .. string.rep(TAB_CHAR,(depth-1)*indentation) .. "}"
end
if (#stack > 0) then
node = stack[#stack]
stack[#stack] = nil
depth = cache[node] == nil and depth + 1 or depth - 1
else
break
end
end
-- This is necessary for working with HUGE tables otherwise we run out of memory using concat on huge strings
table.insert(output,output_str)
output_str = table.concat(output)
return output_str
end
then:
print(dump_table_to_string("AA", true,3))
print(dump_table_to_string({"AA","BB"}, true,3))
print(dump_table_to_string({"AA","BB"}))
print(dump_table_to_string({"AA","BB"},false))
print(dump_table_to_string({"AA","BB",{22,33}},true,2))
gives:
only table type is supported, got string
{
[1] = 'AA',
[2] = 'BB'
}
{
[1] = 'AA',
[2] = 'BB'
}
{[1] = 'AA',[2] = 'BB'}
{
[1] = 'AA',
[2] = 'BB',
[3] = {
[1] = 22,
[2] = 33
}
}
Now the function print can print the (flat) tables!
oprint = print -- origin print
print = function (...)
if type(...) == "table" then
local str = ''
local amount = 0
for i,v in pairs(...) do
amount=amount+1
local pre = type(i) == "string" and i.."=" or ""
str = str .. pre..tostring(v) .. "\t"
end
oprint('#'..amount..':', str)
else
oprint(...)
end
end
For example:
print ({x=7, y=9, w=11, h="height", 7, 8, 9})
prints:
#7: 7 8 9 y=9 x=7 h=height w=11
The same way it can be just new function tostring:
otostring = tostring -- origin tostring
tostring = function (...)
if type(...) == "table" then
local str = '{'
for i,v in pairs(...) do
local pre = type(i) == "string" and i.."=" or ""
str = str .. pre..tostring(v) .. ", "
end
str = str:sub(1, -3)
return str..'}'
else
return otostring(...)
end
end

Does VBA have any built in URL decoding?

I just need to decode a URL, for example, replace %2E with .
I can hack out a method if one isn't build in, but my assumption is that there must be a URL decoding tool already existing.
Here's a snippet I wrote years ago
-markus
Public Function URLDecode(sEncodedURL As String) As String
On Error GoTo Catch
Dim iLoop As Integer
Dim sRtn As String
Dim sTmp As String
If Len(sEncodedURL) > 0 Then
' Loop through each char
For iLoop = 1 To Len(sEncodedURL)
sTmp = Mid(sEncodedURL, iLoop, 1)
sTmp = Replace(sTmp, "+", " ")
' If char is % then get next two chars
' and convert from HEX to decimal
If sTmp = "%" and LEN(sEncodedURL) + 1 > iLoop + 2 Then
sTmp = Mid(sEncodedURL, iLoop + 1, 2)
sTmp = Chr(CDec("&H" & sTmp))
' Increment loop by 2
iLoop = iLoop + 2
End If
sRtn = sRtn & sTmp
Next
URLDecode = sRtn
End If
Finally:
Exit Function
Catch:
URLDecode = ""
Resume Finally
End Function
No.
But here's one: URL Encoder and Decoder for VB
Or something along the lines of (possibly not complete):
Public Function URLDecode(ByVal strEncodedURL As String) As String
Dim str As String
str = strEncodedURL
If Len(str) > 0 Then
str = Replace(str, "&amp", " & ")
str = Replace(str, "&#03", Chr(39))
str = Replace(str, "&quo", Chr(34))
str = Replace(str, "+", " ")
str = Replace(str, "%2A", "*")
str = Replace(str, "%40", "#")
str = Replace(str, "%2D", "-")
str = Replace(str, "%5F", "_")
str = Replace(str, "%2B", "+")
str = Replace(str, "%2E", ".")
str = Replace(str, "%2F", "/")
URLDecode = str
End If
End Function
Also, take a look at How can I URL encode a string in Excel VBA?
EncodeURL and DecodeURL function using htmlfile object(Late binding)
I got this source from this site: http://cocosoft.kr/442
Function ENCODEURL(varText As Variant, Optional blnEncode = True)
Static objHtmlfile As Object
If objHtmlfile Is Nothing Then
Set objHtmlfile = CreateObject("htmlfile")
With objHtmlfile.parentWindow
.execScript "function encode(s) {return encodeURIComponent(s)}", "jscript"
End With
End If
If blnEncode Then
ENCODEURL = objHtmlfile.parentWindow.encode(varText)
End If
End Function
Function DECODEURL(varText As Variant, Optional blnEncode = True)
Static objHtmlfile As Object
If objHtmlfile Is Nothing Then
Set objHtmlfile = CreateObject("htmlfile")
With objHtmlfile.parentWindow
.execScript "function decode(s) {return decodeURIComponent(s)}", "jscript"
End With
End If
If blnEncode Then
DECODEURL = objHtmlfile.parentWindow.decode(varText)
End If
End Function
For example,
str = ENCODEURL("/?&=") 'returns "%2F%3F%26%3D"
str = DECODEURL("%2F%3F%26%3D") 'returns "/?&="
Here is the code from the URL posted in another answer in case it goes down as it works great.
http://www.freevbcode.com/ShowCode.asp?ID=1512
Public Function URLEncode(StringToEncode As String, Optional _
UsePlusRatherThanHexForSpace As Boolean = False) As String
Dim TempAns As String
Dim CurChr As Integer
CurChr = 1
Do Until CurChr - 1 = Len(StringToEncode)
Select Case Asc(Mid(StringToEncode, CurChr, 1))
Case 48 To 57, 65 To 90, 97 To 122
TempAns = TempAns & Mid(StringToEncode, CurChr, 1)
Case 32
If UsePlusRatherThanHexForSpace = True Then
TempAns = TempAns & "+"
Else
TempAns = TempAns & "%" & Hex(32)
End If
Case Else
TempAns = TempAns & "%" & _
Format(Hex(Asc(Mid(StringToEncode, _
CurChr, 1))), "00")
End Select
CurChr = CurChr + 1
Loop
URLEncode = TempAns
End Function
Public Function URLDecode(StringToDecode As String) As String
Dim TempAns As String
Dim CurChr As Integer
CurChr = 1
Do Until CurChr - 1 = Len(StringToDecode)
Select Case Mid(StringToDecode, CurChr, 1)
Case "+"
TempAns = TempAns & " "
Case "%"
TempAns = TempAns & Chr(Val("&h" & _
Mid(StringToDecode, CurChr + 1, 2)))
CurChr = CurChr + 2
Case Else
TempAns = TempAns & Mid(StringToDecode, CurChr, 1)
End Select
CurChr = CurChr + 1
Loop
URLDecode = TempAns
End Function
' URLDecode function in Perl for reference
' both VB and Perl versions must return same
'
' sub urldecode{
' local($val)=#_;
' $val=~s/\+/ /g;
' $val=~s/%([0-9A-H]{2})/pack('C',hex($1))/ge;
' return $val;
' }

Resources