I am using Lua version 54 inside my windows 64 bit OS. I am struggling writing the proper syntax for opening a directory, then opening the local file with path. Then once the file is open (JSON File) converting it to Lua Table.
Code I am using:
Lua54 syntax
local archhudbasic = io.open("C:\\Users\\Lichr\\Documents",)
Internal functions
local function kind_of(obj)
if type(obj) ~= 'table' then return type(obj) end
local i = 1
for _ in pairs(obj) do
if obj[i] ~= nil then i = i + 1 else return 'table' end
end
if i == 1 then return 'table' else return 'array' end
end
local function escape_str(s)
local in_char = {'\\', '"', '/', '\b', '\f', '\n', '\r', '\t'}
local out_char = {'\\', '"', '/', 'b', 'f', 'n', 'r', 't'}
for i, c in ipairs(in_char) do s = s:gsub(c, '\\' .. out_char[i])
end
return s
end
Returns pos, did_find; there are two cases:
Delimiter found: pos = pos after leading space + delim; did_find = true.
Delimiter not found: pos = pos after leading space; did_find = false.
This throws an error if err_if_missing is true and the delim is not found.
local function skip_delim(str, pos, delim, err_if_missing)
pos = pos + #str:match('^%s*', pos)
if str:sub(pos, pos) ~= delim then
if err_if_missing then
error('Expected ' .. delim .. ' near position ' .. pos)
end
return pos, false
end
return pos + 1, true
end
Expects the given pos to be the first character after the opening quote.
Returns val, pos; the returned pos is after the closing quote character.
local function parse_str_val(str, pos, val)
val = val or ''
local early_end_error = 'End of input found while parsing string.'
if pos > #str then error(early_end_error) end
local c = str:sub(pos, pos)
if c == '"' then return val, pos + 1 end
if c ~= '\\' then return parse_str_val(str, pos + 1, val .. c) end
-- We must have a \ character.
local esc_map = {b = '\b', f = '\f', n = '\n', r = '\r', t = '\t'}
local nextc = str:sub(pos + 1, pos + 1)
if not nextc then error(early_end_error) end
return parse_str_val(str, pos + 2, val .. (esc_map[nextc] or nextc))
end
Returns val, pos; the returned pos is after the number's final character.
local function parse_num_val(str, pos)
local num_str = str:match('^-?%d+%.?%d*[eE]?[+-]?%d*', pos)
local val = tonumber(num_str)
if not val then error('Error parsing number at position ' .. pos .. '.') end
return val, pos + #num_str
end
Public values and functions.
function json.stringify(obj, as_key)
local s = {} -- We'll build the string as an array of strings to be concatenated.
local kind = kind_of(obj) -- This is 'array' if it's an array or type(obj)
otherwise.
if kind == 'array' then
if as_key then error('Can\'t encode array as key.') end
s[#s + 1] = '['
for i, val in ipairs(obj) do
if i > 1 then s[#s + 1] = ', ' end
s[#s + 1] = json.stringify(val)
end
s[#s + 1] = ']'
elseif kind == 'table' then
if as_key then error('Can\'t encode table as key.') end
s[#s + 1] = '{'
for k, v in pairs(obj) do
if #s > 1 then s[#s + 1] = ', ' end
s[#s + 1] = json.stringify(k, true)
s[#s + 1] = ':'
s[#s + 1] = json.stringify(v)
end
s[#s + 1] = '}'
elseif kind == 'string' then
return '"' .. escape_str(obj) .. '"'
elseif kind == 'number' then
if as_key then return '"' .. tostring(obj) .. '"' end
return tostring(obj)
elseif kind == 'boolean' then
return tostring(obj)
elseif kind == 'nil' then
return 'null'
else
error('Unjsonifiable type: ' .. kind .. '.')
end
return table.concat(s)
end
json.null = {} //This is a one-off table to represent the null value.
function json.parse(str, pos, end_delim)
pos = pos or 1
if pos > #str then error('Reached unexpected end of input.') end
local pos = pos + #str:match('^%s*', pos) -- Skip whitespace.
local first = str:sub(pos, pos)
if first == '{' then -- Parse an object.
local obj, key, delim_found = {}, true, true
pos = pos + 1
while true do
key, pos = json.parse(str, pos, '}')
if key == nil then return obj, pos end
if not delim_found then error('Comma missing between object items.') end
pos = skip_delim(str, pos, ':', true) -- true -> error if missing.
obj[key], pos = json.parse(str, pos)
pos, delim_found = skip_delim(str, pos, ',')
end
elseif first == '[' then -- Parse an array.
local arr, val, delim_found = {}, true, true
pos = pos + 1
while true do
val, pos = json.parse(str, pos, ']')
if val == nil then return arr, pos end
if not delim_found then error('Comma missing between array items.') end
arr[#arr + 1] = val
pos, delim_found = skip_delim(str, pos, ',')
end
elseif first == '"' then -- Parse a string.
return parse_str_val(str, pos + 1)
elseif first == '-' or first:match('%d') then -- Parse a number.
return parse_num_val(str, pos)
elseif first == end_delim then -- End of an object or array.
return nil, pos + 1
else -- Parse true, false, or null.
local literals = {['true'] = true, ['false'] = false, ['null'] = json.null}
for lit_str, lit_val in pairs(literals) do
local lit_end = pos + #lit_str - 1
if str:sub(pos, lit_end) == lit_str then return lit_val, lit_end + 1 end
end
local pos_info_str = 'position ' .. pos .. ': ' .. str:sub(pos, pos + 10)
error('Invalid json syntax starting at ' .. pos_info_str)
end
end
return json
I am new to lua coding. What am I missing? How can I make this code functional inside the terminal?
Related
I run the following code, but Lua keeps giving me "attempt to call a nil value". When I change the _G[fi] to _G.fi it gives me "attempt to call a string value".
i = "0"
j = "0"
k = "0"
fi = "f"..i
fj = "f"..j
fk= "f"..k
functions = {
f1 = function(next, v)
for t = 1, 1, 4 do
v[t] = v[t] + 1
v[t] = v[t] % 3
end
if (next == "0") then return v
else return functions[next](0, v) end
end,
f2 = function(next, v)
for t = 1, 1, 4 do
v[t] = v[t] + 2
v[t] = v[t] % 3
end
if (next == "0") then return v
else return functions[next](0, v) end
end,
f3 = function(next, v)
if (next == "0") then return v
else return functions[next](0, v) end
end,
f4 = function(next, v)
swap(v[2], v[3])
if (next == "0") then return v
else return functions[next](0, v) end
end,
f5 = function(next, v)
swap(v[1], v[3])
if (next == "0") then return v
else return functions[next](0, v) end
end,
f6 = function(next, v)
swap(v[1], v[2])
if (next == "0") then return v
else return functions[next](0, v) end
end,
}
for i = 0, 1, 6 do
for j = 0, 1, 6 do
for k = 0, 1, 6 do
if _G[fi](fj, {1,2,0}) == _G[fj](fk, {1,2,0}) and not _G[fi](-1, {1,2,0}) == _G[fk](-1, {1,2,0}) then
print(i + " " + j + " " + k)
end
end
end
end
The problem is you set fi = "f"..i at the start, which sets fi == "f0", and that never changes for the rest of the program until you later invoke _G[fi]. The value of fi does not automatically change just because you changed the value of i.
You probably want to expand i (and j and k) at the call point, with something more like:
_G["f"..i]("f"..j, {1,2,0})... etc
So what I am trying to do here is for a given json_body which is decoded json into a table using cjson I want to remove a given element by a configurable value conf.remove.json, I feel I am pretty close but its still not working, and is there a better way? Is there a safe way to find the tables "depth" and then reach out like conf.remove.json= I.want.to.remove.this creates the behavior json_table[I][want][to][remove][this] = nil without throwing some kind of NPE?
local configRemovePath= {}
local configRemoveDepth= 0
local recursiveCounter = 1
local function splitString(inputstr)
sep = "%." --Split on .
configRemovePath={}
configRemoveDepth=0
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
configRemovePath[configRemoveDepth + 1] = str
configRemoveDepth = configRemoveDepth + 1
end
end
local function recursiveSearchAndNullify(jsonTable)
for key, value in pairs(jsonTable) do --unordered search
-- First iteration
--Sample Json below, where conf.remove.json = data.id and nothing happened. conf.remove.json=data.id
--{
--"data": {
-- "d": 2,
-- "id": 1
--}
--}
-- value = {"d": 2, "id": 1}, key = "data", configRemovePath[recursiveCounter] = "data" , configRemovePath ['data','id'] , configRemoveDepth = 2
if(type(value) == "table" and value == configRemovePath[recursiveCounter] and recursiveCounter < configRemoveDepth) then --If the type is table, the current table is one we need to dive into, and we have not exceeded the configurations remove depth level
recursiveCounter = recursiveCounter + 1
jsonTable = recursiveSearchAndNullify(value)
else
if(key == configRemovePath[recursiveCounter] and recursiveCounter == configRemoveDepth) then --We are at the depth to remove and the key matches then we delete.
for key in pairs (jsonTable) do --Remove all occurances of said element
jsonTable[key] = nil
end
end
end
end
return jsonTable
end
for _, name in iter(conf.remove.json) do
splitString(name)
if(configRemoveDepth == 0) then
for name in pairs (json_body) do
json_body[name] = nil
end
else
recursiveCounter = 1 --Reset to 1 for each for call
json_body = recursiveSearchAndNullify(json_body)
end
end
Thanks to any who assist, this is my first day with Lua so I am pretty newb.
This is the official answer, found a better way with the help of Christian Sciberras!
local json_body_test_one = {data = { id = {"a", "b"},d = "2" }} --decoded json w cjson
local json_body_test_two = {data = { { id = "a", d = "1" }, { id = "b", d = "2" } } }
local config_json_remove = "data.id"
local function dump(o) --Method to print test tables for debugging
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
local function splitstring(inputstr, sep)
if sep == nil then
sep = "%." --Dot notation default
end
local t={} ; i=1
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
t[i] = str
i = i + 1
end
return t
end
local function setjsonprop(json_object, path, newvalue)
local configarray = splitstring(path)
while (#configarray > 1) do
json_object = json_object[table.remove(configarray, 1)]
if(type(json_object) == "table" and #json_object > 0) then
local recursepath = table.concat(configarray, ".")
for _, item in pairs(json_object) do
setjsonprop(item, recursepath, newvalue)
end
return
end
end
json_object[table.remove(configarray, 1)] = newvalue
end
setjsonprop(json_body_test_one, config_json_remove, nil)
print(dump(json_body_test_one))
I am new to JSON, and I am attempting to read a string in JSON format returned from a data source. I am using classic ASP, and I am getting the following error from the class code for VbsJson.
Microsoft VBScript runtime error '800a01a8'
Object required
/MyTestPage.asp, line 83
Below in the code I comment where the error is occuring. My desire is for the code to parse and provide the key/value pair of data to sort through.
Here is the JSON string
[
{
"branchNumber": null,
"createdOn": "2017-02-03T22:44:22.656062",
"employeeId": "00",
"id": "0000000-000F-DB00-999D",
"lastUpdatedOn": "2017-02-04T17:26:37.137217",
"name": {
"firstName": "MyFirstName",
"lastName": "MyLastName",
"middleNamesOrInitial": null,
"preferredFirstName": null,
"prefix": null,
"suffix": null
},
"userName": "MyEMail#MyCorp.com"
},
{
"branchNumber": null,
"createdOn": "2017-02-03T22:44:22.656062",
"employeeId": "01",
"id": "0000000-000F-DB00-999F",
"lastUpdatedOn": "2017-02-04T17:26:37.137217",
"name": {
"firstName": "MyFirstName",
"lastName": "MyLastName",
"middleNamesOrInitial": null,
"preferredFirstName": null,
"prefix": null,
"suffix": null
},
"userName": "MyEMail2#MyCorp.com"
}
]
Here is my code calling VbsJson:
Dim simonResponseArray
Dim jsonClsUser, jsonParsedUser
Dim fso, json
Set json = New VbsJson
Set fso = server.CreateObject("Scripting.Filesystemobject")
simonXmlResponse = fso.OpenTextFile("C:\Temp\users_small.json").ReadAll
Set jsonClsUser = New VbsJson
Set jsonParsedUser = jsonClsUser.Decode(simonXmlResponse) 'This is where the error occurs
Also, below is the class code for VbsJson:
Class VbsJson
'Author: Demon
'Date: 2012/5/3
'Website: http://demon.tw
Private Whitespace, NumberRegex, StringChunk
Private b, f, r, n, t
Private Sub Class_Initialize
Whitespace = " " & vbTab & vbCr & vbLf
b = ChrW(8)
f = vbFormFeed
r = vbCr
n = vbLf
t = vbTab
Set NumberRegex = New RegExp
NumberRegex.Pattern = "(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?"
NumberRegex.Global = False
NumberRegex.MultiLine = True
NumberRegex.IgnoreCase = True
Set StringChunk = New RegExp
StringChunk.Pattern = "([\s\S]*?)([""\\\x00-\x1f])"
StringChunk.Global = False
StringChunk.MultiLine = True
StringChunk.IgnoreCase = True
End Sub
'Return a JSON string representation of a VBScript data structure
'Supports the following objects and types
'+-------------------+---------------+
'| VBScript | JSON |
'+===================+===============+
'| Dictionary | object |
'+-------------------+---------------+
'| Array | array |
'+-------------------+---------------+
'| String | string |
'+-------------------+---------------+
'| Number | number |
'+-------------------+---------------+
'| True | true |
'+-------------------+---------------+
'| False | false |
'+-------------------+---------------+
'| Null | null |
'+-------------------+---------------+
Public Function Encode(ByRef obj)
Dim buf, i, c, g
Set buf = CreateObject("Scripting.Dictionary")
Select Case VarType(obj)
Case vbNull
buf.Add buf.Count, "null"
Case vbBoolean
If obj Then
buf.Add buf.Count, "true"
Else
buf.Add buf.Count, "false"
End If
Case vbInteger, vbLong, vbSingle, vbDouble
buf.Add buf.Count, obj
Case vbString
buf.Add buf.Count, """"
For i = 1 To Len(obj)
c = Mid(obj, i, 1)
Select Case c
Case """" buf.Add buf.Count, "\"""
Case "\" buf.Add buf.Count, "\\"
Case "/" buf.Add buf.Count, "/"
Case b buf.Add buf.Count, "\b"
Case f buf.Add buf.Count, "\f"
Case r buf.Add buf.Count, "\r"
Case n buf.Add buf.Count, "\n"
Case t buf.Add buf.Count, "\t"
Case Else
If AscW(c) >= 0 And AscW(c) <= 31 Then
c = Right("0" & Hex(AscW(c)), 2)
buf.Add buf.Count, "\u00" & c
Else
buf.Add buf.Count, c
End If
End Select
Next
buf.Add buf.Count, """"
Case vbArray + vbVariant
g = True
buf.Add buf.Count, "["
For Each i In obj
If g Then g = False Else buf.Add buf.Count, ","
buf.Add buf.Count, Encode(i)
Next
buf.Add buf.Count, "]"
Case vbObject
If TypeName(obj) = "Dictionary" Then
g = True
buf.Add buf.Count, "{"
For Each i In obj
If g Then g = False Else buf.Add buf.Count, ","
buf.Add buf.Count, """" & i & """" & ":" & Encode(obj(i))
Next
buf.Add buf.Count, "}"
Else
Err.Raise 8732,,"None dictionary object"
End If
Case Else
buf.Add buf.Count, """" & CStr(obj) & """"
End Select
Encode = Join(buf.Items, "")
End Function
'Return the VBScript representation of ``str(``
'Performs the following translations in decoding
'+---------------+-------------------+
'| JSON | VBScript |
'+===============+===================+
'| object | Dictionary |
'+---------------+-------------------+
'| array | Array |
'+---------------+-------------------+
'| string | String |
'+---------------+-------------------+
'| number | Double |
'+---------------+-------------------+
'| true | True |
'+---------------+-------------------+
'| false | False |
'+---------------+-------------------+
'| null | Null |
'+---------------+-------------------+
Public Function Decode(ByRef str)
Dim idx
str=Replace(str,"[]","[""""]")
str=Replace(str,"{}","[""""]")
idx = SkipWhitespace(str, 1)
If Mid(str, idx, 1) = "{" Then
Set Decode = ScanOnce(str, 1)
Else
Decode = ScanOnce(str, 1)
End If
End Function
Private Function ScanOnce(ByRef str, ByRef idx)
Dim c, ms
idx = SkipWhitespace(str, idx)
c = Mid(str, idx, 1)
If c = "{" Then
idx = idx + 1
Set ScanOnce = ParseObject(str, idx)
Exit Function
ElseIf c = "[" Then
idx = idx + 1
ScanOnce = ParseArray(str, idx)
Exit Function
ElseIf c = """" Then
idx = idx + 1
ScanOnce = ParseString(str, idx)
Exit Function
ElseIf c = "n" And StrComp("null", Mid(str, idx, 4)) = 0 Then
idx = idx + 4
ScanOnce = Null
Exit Function
ElseIf c = "t" And StrComp("true", Mid(str, idx, 4)) = 0 Then
idx = idx + 4
ScanOnce = True
Exit Function
ElseIf c = "f" And StrComp("false", Mid(str, idx, 5)) = 0 Then
idx = idx + 5
ScanOnce = False
Exit Function
End If
Set ms = NumberRegex.Execute(Mid(str, idx))
If ms.Count = 1 Then
idx = idx + ms(0).Length
ScanOnce = CDbl(ms(0))
Exit Function
End If
Err.Raise 8732,,"No JSON object could be ScanOnced"
End Function
Private Function ParseObject(ByRef str, ByRef idx)
Dim c, key, value
Set ParseObject = CreateObject("Scripting.Dictionary")
idx = SkipWhitespace(str, idx)
c = Mid(str, idx, 1)
If c = "}" Then
Exit Function
ElseIf c <> """" Then
Err.Raise 8732,,"Expecting property name"
End If
idx = idx + 1
Do
key = ParseString(str, idx)
idx = SkipWhitespace(str, idx)
If Mid(str, idx, 1) <> ":" Then
Err.Raise 8732,,"Expecting : delimiter"
End If
idx = SkipWhitespace(str, idx + 1)
If Mid(str, idx, 1) = "{" Then
Set value = ScanOnce(str, idx)
Else
value = ScanOnce(str, idx)
End If
ParseObject.Add key, value
idx = SkipWhitespace(str, idx)
c = Mid(str, idx, 1)
If c = "}" Then
Exit Do
ElseIf c <> "," Then
Err.Raise 8732,,"Expecting , delimiter"
End If
idx = SkipWhitespace(str, idx + 1)
c = Mid(str, idx, 1)
If c <> """" Then
Err.Raise 8732,,"Expecting property name"
End If
idx = idx + 1
Loop
idx = idx + 1
End Function
Private Function ParseArray(ByRef str, ByRef idx)
Dim c, values, value
Set values = CreateObject("Scripting.Dictionary")
idx = SkipWhitespace(str, idx)
c = Mid(str, idx, 1)
If c = "]" Then
ParseArray = values.Items
Exit Function
End If
Do
idx = SkipWhitespace(str, idx)
If Mid(str, idx, 1) = "{" Then
Set value = ScanOnce(str, idx)
Else
value = ScanOnce(str, idx)
End If
values.Add values.Count, value
idx = SkipWhitespace(str, idx)
c = Mid(str, idx, 1)
If c = "]" Then
Exit Do
ElseIf c <> "," Then
Err.Raise 8732,,"Expecting , delimiter"
End If
idx = idx + 1
Loop
idx = idx + 1
ParseArray = values.Items
End Function
Private Function ParseString(ByRef str, ByRef idx)
Dim chunks, content, terminator, ms, esc, char
Set chunks = CreateObject("Scripting.Dictionary")
Do
Set ms = StringChunk.Execute(Mid(str, idx))
If ms.Count = 0 Then
Err.Raise 8732,,"Unterminated string starting"
End If
content = ms(0).Submatches(0)
terminator = ms(0).Submatches(1)
If Len(content) > 0 Then
chunks.Add chunks.Count, content
End If
idx = idx + ms(0).Length
If terminator = """" Then
Exit Do
ElseIf terminator <> "\" Then
Err.Raise 8732,,"Invalid control character"
End If
esc = Mid(str, idx, 1)
If esc <> "u" Then
Select Case esc
Case """" char = """"
Case "\" char = "\"
Case "/" char = "/"
Case "b" char = b
Case "f" char = f
Case "n" char = n
Case "r" char = r
Case "t" char = t
Case Else Err.Raise 8732,,"Invalid escape"
End Select
idx = idx + 1
Else
char = ChrW("&H" & Mid(str, idx + 1, 4))
idx = idx + 5
End If
chunks.Add chunks.Count, char
Loop
ParseString = Join(chunks.Items, "")
End Function
Private Function SkipWhitespace(ByRef str, ByVal idx)
Do While idx <= Len(str) And _
InStr(Whitespace, Mid(str, idx, 1)) > 0
idx = idx + 1
Loop
SkipWhitespace = idx
End Function
End Class
If there is anymore info someone needs, please let me know. Consuming JSON from classic ASP has proven difficult for me.
Your JSON data is an array of objects/dictionaries. So your
Set jsonParsedUser = jsonClsUser.Decode(simonXmlResponse)
should be:
jsonParsedUser = jsonClsUser.Decode(simonXmlResponse)
(Set is used for assignment of objects; see here)
My goal is to search a CSV's first column twice, then execute an action (dependent of a value in the third column of same record). I began in VBScript using InStr() :
Set objFS = CreateObject("Scripting.FileSystemObject")
roster = "C:\bin\roster.csv"
Set objFile = objFS.OpenTextFile(roster)
Do Until objFile.AtEndOfStream
strLine = objFile.ReadLine
intLength = Len(strLine)
intZeros = 5 - intLength
If InStr(strLine, strIP)> 0 Then
strinfo = split(strLine, ",")
siteNumA = strinfo (0)
siteNumB = string(5 - Len(siteNumA), "0") & siteNumA
siteIP = strinfo (1)
siteDist = strinfo (2)
siteReg = strinfo (3)
End If
It could compare values of siteDist to same data from a second search. However, I prefer to use AutoIt. Is there a way to achieve this using AutoIt (or a command to achieve my plan)?
A simple CSV file I am using for testing :
Site,District,Region
1,1,1
2,1,1
3,1,2
4,2,2
5,2,1
Searching two separate entries for Site and confirming that District matches afterwards, running this script at site 1 should have it evaluate as true for Site 1, 2, or 3, and false for Site 4 and 5.
Use this:
; #FUNCTION# ====================================================================================================================
; Name...........: _ParseCSV
; Description ...: Reads a CSV-file
; Syntax.........: _ParseCSV($sFile, $sDelimiters=',', $sQuote='"', $iFormat=0)
; Parameters ....: $sFile - File to read or string to parse
; $sDelimiters - [optional] Fieldseparators of CSV, mulitple are allowed (default: ,;)
; $sQuote - [optional] Character to quote strings (default: ")
; $iFormat - [optional] Encoding of the file (default: 0):
; |-1 - No file, plain data given
; |0 or 1 - automatic (ASCII)
; |2 - Unicode UTF16 Little Endian reading
; |3 - Unicode UTF16 Big Endian reading
; |4 or 5 - Unicode UTF8 reading
; Return values .: Success - 2D-Array with CSV data (0-based)
; Failure - 0, sets #error to:
; |1 - could not open file
; |2 - error on parsing data
; |3 - wrong format chosen
; Author ........: ProgAndy
; Modified.......:
; Remarks .......:
; Related .......: _WriteCSV
; Link ..........:
; Example .......:
; ===============================================================================================================================
Func _ParseCSV($sFile, $sDelimiters=',;', $sQuote='"', $iFormat=0)
Local Static $aEncoding[6] = [0, 0, 32, 64, 128, 256]
If $iFormat < -1 Or $iFormat > 6 Then
Return SetError(3,0,0)
ElseIf $iFormat > -1 Then
Local $hFile = FileOpen($sFile, $aEncoding[$iFormat]), $sLine, $aTemp, $aCSV[1], $iReserved, $iCount
If #error Then Return SetError(1,#error,0)
$sFile = FileRead($hFile)
FileClose($hFile)
EndIf
If $sDelimiters = "" Or IsKeyword($sDelimiters) Then $sDelimiters = ',;'
If $sQuote = "" Or IsKeyword($sQuote) Then $sQuote = '"'
$sQuote = StringLeft($sQuote, 1)
Local $srDelimiters = StringRegExpReplace($sDelimiters, '[\\\^\-\[\]]', '\\\0')
Local $srQuote = StringRegExpReplace($sQuote, '[\\\^\-\[\]]', '\\\0')
Local $sPattern = StringReplace(StringReplace('(?m)(?:^|[,])\h*(["](?:[^"]|["]{2})*["]|[^,\r\n]*)(\v+)?',',', $srDelimiters, 0, 1),'"', $srQuote, 0, 1)
Local $aREgex = StringRegExp($sFile, $sPattern, 3)
If #error Then Return SetError(2,#error,0)
$sFile = '' ; save memory
Local $iBound = UBound($aREgex), $iIndex=0, $iSubBound = 1, $iSub = 0
Local $aResult[$iBound][$iSubBound]
For $i = 0 To $iBound-1
Select
Case StringLen($aREgex[$i])<3 And StringInStr(#CRLF, $aREgex[$i])
$iIndex += 1
$iSub = 0
ContinueLoop
Case StringLeft(StringStripWS($aREgex[$i], 1),1)=$sQuote
$aREgex[$i] = StringStripWS($aREgex[$i], 3)
$aResult[$iIndex][$iSub] = StringReplace(StringMid($aREgex[$i], 2, StringLen($aREgex[$i])-2), $sQuote&$sQuote, $sQuote, 0, 1)
Case Else
$aResult[$iIndex][$iSub] = $aREgex[$i]
EndSelect
$aREgex[$i]=0 ; save memory
$iSub += 1
If $iSub = $iSubBound Then
$iSubBound += 1
ReDim $aResult[$iBound][$iSubBound]
EndIf
Next
If $iIndex = 0 Then $iIndex=1
ReDim $aResult[$iIndex][$iSubBound]
Return $aResult
EndFunc
; #FUNCTION# ====================================================================================================================
; Name...........: _WriteCSV
; Description ...: Writes a CSV-file
; Syntax.........: _WriteCSV($sFile, Const ByRef $aData, $sDelimiter, $sQuote, $iFormat=0)
; Parameters ....: $sFile - Destination file
; $aData - [Const ByRef] 0-based 2D-Array with data
; $sDelimiter - [optional] Fieldseparator (default: ,)
; $sQuote - [optional] Quote character (default: ")
; $iFormat - [optional] character encoding of file (default: 0)
; |0 or 1 - ASCII writing
; |2 - Unicode UTF16 Little Endian writing (with BOM)
; |3 - Unicode UTF16 Big Endian writing (with BOM)
; |4 - Unicode UTF8 writing (with BOM)
; |5 - Unicode UTF8 writing (without BOM)
; Return values .: Success - True
; Failure - 0, sets #error to:
; |1 - No valid 2D-Array
; |2 - Could not open file
; Author ........: ProgAndy
; Modified.......:
; Remarks .......:
; Related .......: _ParseCSV
; Link ..........:
; Example .......:
; ===============================================================================================================================
Func _WriteCSV($sFile, Const ByRef $aData, $sDelimiter=',', $sQuote='"', $iFormat=0)
Local Static $aEncoding[6] = [2, 2, 34, 66, 130, 258]
If $sDelimiter = "" Or IsKeyword($sDelimiter) Then $sDelimiter = ','
If $sQuote = "" Or IsKeyword($sQuote) Then $sQuote = '"'
Local $iBound = UBound($aData, 1), $iSubBound = UBound($aData, 2)
If Not $iSubBound Then Return SetError(2,0,0)
Local $hFile = FileOpen($sFile, $aEncoding[$iFormat])
If #error Then Return SetError(2,#error,0)
For $i = 0 To $iBound-1
For $j = 0 To $iSubBound-1
FileWrite($hFile, $sQuote & StringReplace($aData[$i][$j], $sQuote, $sQuote&$sQuote, 0, 1) & $sQuote)
If $j < $iSubBound-1 Then FileWrite($hFile, $sDelimiter)
Next
FileWrite($hFile, #CRLF)
Next
FileClose($hFile)
Return True
EndFunc
; === EXAMPLE ===================================================
;~ #include<Array.au3>
;~ $aResult = _ParseCSV(#ScriptDir & '\test.csv', "\", '$', 4)
;~ _ArrayDisplay($aResult)
;~ _WriteCSV(#ScriptDir & '\written.csv', $aResult, ',', '"', 5)
; ===============================================================
or this:
#region ;************ Includes ************
#include <Array.au3>
#endregion ;************ Includes ************
; _csvTo2DArray
Local $re = _csvTo2DArray("c:\Repository.csv", ';')
_ArrayDisplay($re)
Func _csvTo2DArray($file, $delim = ',')
Local $content = FileRead($file)
Local $rows_A = StringSplit(StringStripCR($content), #LF, 2)
StringReplace($rows_A[0], $delim, $delim)
Local $countColumns = #extended
Local $columns_A = 0
Local $2D_A[UBound($rows_A)][$countColumns + 1]
For $z = 0 To UBound($rows_A) - 1
$columns_A = StringSplit($rows_A[$z], $delim, 2)
For $y = 0 To UBound($columns_A) - 1
$2D_A[$z][$y] = $columns_A[$y]
Next
Next
Return $2D_A
EndFunc ;==>_csvTo2DArray
and then compare the cells with normal Stringfunctions or use the _Array functions on the array.
… is there another way to achieve my end goal in AutoIT, or is there a direct equivalent command set to what is outlined above to achieve my original plan?
Example using _ArraySearch() (replace ConsoleWrite() by whatever action required) :
#include <FileConstants.au3>
#include <File.au3>
#include <Array.au3>
Global Enum $CSV_COL_SITE, _
$CSV_COL_DISTRICT, _
$CSV_COL_REGION
Global Const $g_sFileCSV = 'C:\bin\roster.csv'
Global Const $g_sFileDelim = ','
Global Const $g_iColSearch = $CSV_COL_DISTRICT
Global Const $g_sValSearch = '1'
Global Const $g_sMessage = 'Matched row #%i : %s\n'
Global $g_iRow = 0
Global $g_aCSV
_FileReadToArray($g_sFileCSV, $g_aCSV, $FRTA_NOCOUNT, $g_sFileDelim)
While True
$g_iRow = _ArraySearch($g_aCSV, $g_sValSearch, ($g_iRow ? $g_iRow + 1 : $g_iRow), 0, 0, 0, 1, $g_iColSearch, False)
If #error Then ExitLoop
ConsoleWrite(StringFormat($g_sMessage, $g_iRow, _ArrayToString($g_aCSV, $g_sFileDelim, $g_iRow, $g_iRow, '')))
WEnd
Console output (row number +1 for presence of header record):
Matched row #2 : 1,1,1
Matched row #3 : 2,1,1
Matched row #4 : 3,1,2
I need to convert a Json String to a table data structure in Lua. I am using the following code.
local json = require "json"
local t = {
["name1"] = "value1",
["name2"] = { 1, false, true, 23.54, "a \021 string" },
name3 = json.null
}
local encode = json.encode (t)
print (encode) --> {"name1":"value1","name3":null,"name2":[1,false,true,23.54,"a \u0015 string"]}
local decode = json.decode( encode )
But when I run the script, I get the following errors,
no field package.preload['json']
no file '/usr/local/share/lua/5.2/json.lua'
no file '/usr/local/share/lua/5.2/json/init.lua'
no file '/usr/local/lib/lua/5.2/json.lua'
no file '/usr/local/lib/lua/5.2/json/init.lua'
no file './json.lua'
no file '/usr/local/lib/lua/5.2/json.so'
no file '/usr/local/lib/lua/5.2/loadall.so'
no file './json.so'
So how to convert my json string to lua table?
maybe lua-cjsonis your friend:
install e.g. through luarocks:
$sudo luarocks install lua-cjson
then in lua:
local json = require('cjson')
local tab = json.decode(json_string)
json_string = json.encode(tab)
https://gist.github.com/tylerneylon/59f4bcf316be525b30ab
I found pure lua script file to parse json data (just one file).
local json = {}
-- Internal functions.
local function kind_of(obj)
if type(obj) ~= 'table' then return type(obj) end
local i = 1
for _ in pairs(obj) do
if obj[i] ~= nil then i = i + 1 else return 'table' end
end
if i == 1 then return 'table' else return 'array' end
end
local function escape_str(s)
local in_char = {'\\', '"', '/', '\b', '\f', '\n', '\r', '\t'}
local out_char = {'\\', '"', '/', 'b', 'f', 'n', 'r', 't'}
for i, c in ipairs(in_char) do
s = s:gsub(c, '\\' .. out_char[i])
end
return s
end
-- Returns pos, did_find; there are two cases:
-- 1. Delimiter found: pos = pos after leading space + delim; did_find = true.
-- 2. Delimiter not found: pos = pos after leading space; did_find = false.
-- This throws an error if err_if_missing is true and the delim is not found.
local function skip_delim(str, pos, delim, err_if_missing)
pos = pos + #str:match('^%s*', pos)
if str:sub(pos, pos) ~= delim then
if err_if_missing then
error('Expected ' .. delim .. ' near position ' .. pos)
end
return pos, false
end
return pos + 1, true
end
-- Expects the given pos to be the first character after the opening quote.
-- Returns val, pos; the returned pos is after the closing quote character.
local function parse_str_val(str, pos, val)
val = val or ''
local early_end_error = 'End of input found while parsing string.'
if pos > #str then error(early_end_error) end
local c = str:sub(pos, pos)
if c == '"' then return val, pos + 1 end
if c ~= '\\' then return parse_str_val(str, pos + 1, val .. c) end
-- We must have a \ character.
local esc_map = {b = '\b', f = '\f', n = '\n', r = '\r', t = '\t'}
local nextc = str:sub(pos + 1, pos + 1)
if not nextc then error(early_end_error) end
return parse_str_val(str, pos + 2, val .. (esc_map[nextc] or nextc))
end
-- Returns val, pos; the returned pos is after the number's final character.
local function parse_num_val(str, pos)
local num_str = str:match('^-?%d+%.?%d*[eE]?[+-]?%d*', pos)
local val = tonumber(num_str)
if not val then error('Error parsing number at position ' .. pos .. '.') end
return val, pos + #num_str
end
-- Public values and functions.
function json.stringify(obj, as_key)
local s = {} -- We'll build the string as an array of strings to be concatenated.
local kind = kind_of(obj) -- This is 'array' if it's an array or type(obj) otherwise.
if kind == 'array' then
if as_key then error('Can\'t encode array as key.') end
s[#s + 1] = '['
for i, val in ipairs(obj) do
if i > 1 then s[#s + 1] = ', ' end
s[#s + 1] = json.stringify(val)
end
s[#s + 1] = ']'
elseif kind == 'table' then
if as_key then error('Can\'t encode table as key.') end
s[#s + 1] = '{'
for k, v in pairs(obj) do
if #s > 1 then s[#s + 1] = ', ' end
s[#s + 1] = json.stringify(k, true)
s[#s + 1] = ':'
s[#s + 1] = json.stringify(v)
end
s[#s + 1] = '}'
elseif kind == 'string' then
return '"' .. escape_str(obj) .. '"'
elseif kind == 'number' then
if as_key then return '"' .. tostring(obj) .. '"' end
return tostring(obj)
elseif kind == 'boolean' then
return tostring(obj)
elseif kind == 'nil' then
return 'null'
else
error('Unjsonifiable type: ' .. kind .. '.')
end
return table.concat(s)
end
json.null = {} -- This is a one-off table to represent the null value.
function json.parse(str, pos, end_delim)
pos = pos or 1
if pos > #str then error('Reached unexpected end of input.') end
local pos = pos + #str:match('^%s*', pos) -- Skip whitespace.
local first = str:sub(pos, pos)
if first == '{' then -- Parse an object.
local obj, key, delim_found = {}, true, true
pos = pos + 1
while true do
key, pos = json.parse(str, pos, '}')
if key == nil then return obj, pos end
if not delim_found then error('Comma missing between object items.') end
pos = skip_delim(str, pos, ':', true) -- true -> error if missing.
obj[key], pos = json.parse(str, pos)
pos, delim_found = skip_delim(str, pos, ',')
end
elseif first == '[' then -- Parse an array.
local arr, val, delim_found = {}, true, true
pos = pos + 1
while true do
val, pos = json.parse(str, pos, ']')
if val == nil then return arr, pos end
if not delim_found then error('Comma missing between array items.') end
arr[#arr + 1] = val
pos, delim_found = skip_delim(str, pos, ',')
end
elseif first == '"' then -- Parse a string.
return parse_str_val(str, pos + 1)
elseif first == '-' or first:match('%d') then -- Parse a number.
return parse_num_val(str, pos)
elseif first == end_delim then -- End of an object or array.
return nil, pos + 1
else -- Parse true, false, or null.
local literals = {['true'] = true, ['false'] = false, ['null'] = json.null}
for lit_str, lit_val in pairs(literals) do
local lit_end = pos + #lit_str - 1
if str:sub(pos, lit_end) == lit_str then return lit_val, lit_end + 1 end
end
local pos_info_str = 'position ' .. pos .. ': ' .. str:sub(pos, pos + 10)
error('Invalid json syntax starting at ' .. pos_info_str)
end
end
return json
You can use json-lua. A pure lua implementation of json. First install json-lua using Luarocks. luarocks install json-lua . Then Use this code :
local json = require "json"
local t = {
["name1"] = "value1",
["name2"] = { 1, false, true, 23.54, "a \021 string" },
name3 = json.null
}
local encode = json:encode (t)
print (encode) --> {"name1":"value1","name3":null,"name2":[1,false,true,23.54,"a \u0015 string"]}
local decode = json:decode( encode )
Tested & Verified on win 7 64 bit with lua 5.1. lua-cjson is fine, but it is not a pure lua rock. So, it's installation will not be easier to you.