Skip to content

Instantly share code, notes, and snippets.

@d-lua-stuff
Created September 2, 2020 02:34

Revisions

  1. d-lua-stuff created this gist Sep 2, 2020.
    140 changes: 140 additions & 0 deletions json.lua
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,140 @@
    -- Extracts values from a JSON string with pattern matching
    -- This is faster than using dkjson when only a few fields are needed

    -- Use this only with trusted data sources! Limitations:
    -- * Character escapes are not supported
    -- * Field nesting is ignored

    local find, gsub = string.find, string.gsub

    ---@param json string
    ---@param key string
    ---@param init number|nil
    ---@return string|nil, number|nil, number|nil
    local function extractStringJsonValue (json, key, init)
    local pattern = [["]] .. key .. [["%s*:%s*"([^"]*)"]]
    local startIndex, endIndex, valueStr = find(json, pattern, init)
    return valueStr, startIndex, endIndex
    end

    ---@param json string
    ---@param key string
    ---@param init number|nil
    ---@return number|nil, number|nil, number|nil
    local function extractNumberJsonValue (json, key, init)
    local pattern = [["]] .. key .. [["%s*:%s*(-?[0-9.e-]+)]]
    local startIndex, endIndex, valueStr = find(json, pattern, init)
    return tonumber(valueStr), startIndex, endIndex
    end

    ---@param json string
    ---@param key string
    ---@param init number|nil
    ---@return boolean|nil, number|nil, number|nil
    local function extractBooleanJsonValue (json, key, init)
    local pattern = [["]] .. key .. [["%s*:%s*([truefals]+)]]
    local startIndex, endIndex, valueStr = find(json, pattern, init)

    if valueStr == "true" then
    return true, startIndex, endIndex
    elseif valueStr == "false" then
    return false, startIndex, endIndex
    else
    return nil
    end
    end

    ---@param extractJsonValue function
    ---@param json string
    ---@param key string
    ---@param stopAfterIndex number|nil
    ---@param stopAfterValue any|nil
    ---@return any[]
    local function extractAllJsonValues (extractJsonValue, json, key, stopAfterIndex, stopAfterValue)
    local values = {}
    local valuesLen = 0

    local jsonPos = 1
    local value, valueStartIndex, valueEndIndex -- luacheck: ignore valueStartIndex -- unused

    repeat
    value, valueStartIndex, valueEndIndex = extractJsonValue(json, key, jsonPos)

    if value ~= nil then
    valuesLen = valuesLen + 1
    values[valuesLen] = value

    jsonPos = valueEndIndex + 1
    end

    if value == stopAfterValue then break end
    if valuesLen == stopAfterIndex then break end
    until value == nil

    return values
    end

    ---@param json string
    ---@param key string
    ---@param stopAfterIndex number|nil
    ---@param stopAfterValue string|nil
    ---@return string[]
    local function extractAllStringJsonValues (json, key, stopAfterIndex, stopAfterValue)
    return extractAllJsonValues(extractStringJsonValue, json, key, stopAfterIndex, stopAfterValue)
    end

    ---@param json string
    ---@param key string
    ---@param stopAfterIndex number|nil
    ---@param stopAfterValue number|nil
    ---@return number[]
    local function extractAllNumberJsonValues (json, key, stopAfterIndex, stopAfterValue)
    return extractAllJsonValues(extractNumberJsonValue, json, key, stopAfterIndex, stopAfterValue)
    end

    ---@param json string
    ---@param key string
    ---@param stopAfterIndex number|nil
    ---@param stopAfterValue boolean|nil
    ---@return boolean[]
    local function extractAllBooleanJsonValues (json, key, stopAfterIndex, stopAfterValue)
    return extractAllJsonValues(extractBooleanJsonValue, json, key, stopAfterIndex, stopAfterValue)
    end

    ---@param json string
    ---@param key string
    ---@return string
    local function deleteAllStringJsonValues (json, key)
    local pattern = [[%s*"]] .. key .. [["%s*:%s*"[^"]*"%s*,?]]
    return (gsub(json, pattern, ""))
    end

    ---@param json string
    ---@param key string
    ---@return string
    local function deleteAllNumberJsonValues (json, key)
    local pattern = [[%s*"]] .. key .. [["%s*:%s*-?[0-9.e-]+%s*,?]]
    return (gsub(json, pattern, ""))
    end

    ---@param json string
    ---@param key string
    ---@return string
    local function deleteAllBooleanJsonValue (json, key)
    local pattern = [[%s*"]] .. key .. [["%s*:%s*[truefals]+%s*,?]]
    return (gsub(json, pattern, ""))
    end

    return {
    extractStringJsonValue = extractStringJsonValue,
    extractNumberJsonValue = extractNumberJsonValue,
    extractBooleanJsonValue = extractBooleanJsonValue,

    extractAllStringJsonValues = extractAllStringJsonValues,
    extractAllNumberJsonValues = extractAllNumberJsonValues,
    extractAllBooleanJsonValues = extractAllBooleanJsonValues,

    deleteAllStringJsonValues = deleteAllStringJsonValues,
    deleteAllNumberJsonValues = deleteAllNumberJsonValues,
    deleteAllBooleanJsonValue = deleteAllBooleanJsonValue
    }