`
jinnianshilongnian
  • 浏览: 21504057 次
  • 性别: Icon_minigender_1
博客专栏
5c8dac6a-21dc-3466-8abb-057664ab39c7
跟我学spring3
浏览量:2418680
D659df3e-4ad7-3b12-8b9a-1e94abd75ac3
Spring杂谈
浏览量:3008784
43989fe4-8b6b-3109-aaec-379d27dd4090
跟开涛学SpringMVC...
浏览量:5639490
1df97887-a9e1-3328-b6da-091f51f886a1
Servlet3.1规范翻...
浏览量:259916
4f347843-a078-36c1-977f-797c7fc123fc
springmvc杂谈
浏览量:1597318
22722232-95c1-34f2-b8e1-d059493d3d98
hibernate杂谈
浏览量:250219
45b32b6f-7468-3077-be40-00a5853c9a48
跟我学Shiro
浏览量:5858952
Group-logo
跟我学Nginx+Lua开...
浏览量:702004
5041f67a-12b2-30ba-814d-b55f466529d5
亿级流量网站架构核心技术
浏览量:785224
社区版块
存档分类
最新评论

第五章 常用Lua开发库2-JSON库、编码转换、字符串处理

阅读更多

 

JSON库

 

在进行数据传输时JSON格式目前应用广泛,因此从Lua对象与JSON字符串之间相互转换是一个非常常见的功能;目前Lua也有几个JSON库,本人用过cjson、dkjson。其中cjson的语法严格(比如unicode \u0020\u7eaf),要求符合规范否则会解析失败(如\u002),而dkjson相对宽松,当然也可以通过修改cjson的源码来完成一些特殊要求。而在使用dkjson时也没有遇到性能问题,目前使用的就是dkjson。使用时要特别注意的是大部分JSON库都仅支持UTF-8编码;因此如果你的字符编码是如GBK则需要先转换为UTF-8然后进行处理。

1.1、test_cjson.lua

local cjson = require("cjson")

--lua对象到字符串
local obj = {
    id = 1,
    name = "zhangsan",
    age = nil,
    is_male = false,
    hobby = {"film", "music", "read"}
}

local str = cjson.encode(obj)
ngx.say(str, "<br/>")

--字符串到lua对象
str = '{"hobby":["film","music","read"],"is_male":false,"name":"zhangsan","id":1,"age":null}'
local obj = cjson.decode(str)

ngx.say(obj.age, "<br/>")
ngx.say(obj.age == nil, "<br/>")
ngx.say(obj.age == cjson.null, "<br/>")
ngx.say(obj.hobby[1], "<br/>")


--循环引用
obj = {
   id = 1
}
obj.obj = obj
-- Cannot serialise, excessive nesting
--ngx.say(cjson.encode(obj), "<br/>")
local cjson_safe = require("cjson.safe")
--nil
ngx.say(cjson_safe.encode(obj), "<br/>")
null将会转换为cjson.null;循环引用会抛出异常Cannot serialise, excessive nesting,默认解析嵌套深度是1000,可以通过cjson.encode_max_depth()设置深度提高性能;使用cjson.safe不会抛出异常而是返回nil。 

 

1.2、example.conf配置文件

     location ~ /lua_cjson {
        default_type 'text/html';
        lua_code_cache on;
        content_by_lua_file /usr/example/lua/test_cjson.lua;
     }
 

1.3、访问如http://192.168.1.2/lua_cjson将得到如下结果

{"hobby":["film","music","read"],"is_male":false,"name":"zhangsan","id":1}
null
false
true
film
nil

 

lua-cjson文档http://www.kyne.com.au/~mark/software/lua-cjson-manual.html

 

接下来学习下dkjson。

 

2.1、下载dkjson库 

cd /usr/example/lualib/
wget http://dkolf.de/src/dkjson-lua.fsl/raw/dkjson.lua?name=16cbc26080996d9da827df42cb0844a25518eeb3 -O dkjson.lua

 

2.2、test_dkjson.lua

local dkjson = require("dkjson")

--lua对象到字符串
local obj = {
    id = 1,
    name = "zhangsan",
    age = nil,
    is_male = false,
    hobby = {"film", "music", "read"}
}

local str = dkjson.encode(obj, {indent = true})
ngx.say(str, "<br/>")

--字符串到lua对象
str = '{"hobby":["film","music","read"],"is_male":false,"name":"zhangsan","id":1,"age":null}'
local obj, pos, err = dkjson.decode(str, 1, nil)

ngx.say(obj.age, "<br/>")
ngx.say(obj.age == nil, "<br/>")
ngx.say(obj.hobby[1], "<br/>")

--循环引用
obj = {
   id = 1
}
obj.obj = obj
--reference cycle
--ngx.say(dkjson.encode(obj), "<br/>")                                     
默认情况下解析的json的字符会有缩排和换行,使用{indent = true}配置将把所有内容放在一行。和cjson不同的是解析json字符串中的null时会得到nil。  

2.3、example.conf配置文件

     location ~ /lua_dkjson {
        default_type 'text/html';
        lua_code_cache on;
        content_by_lua_file /usr/example/lua/test_dkjson.lua;
     }
 

2.4、访问如http://192.168.1.2/lua_dkjson将得到如下结果

{ "hobby":["film","music","read"], "is_male":false, "name":"zhangsan", "id":1 }
nil
true
film

dkjson文档http://dkolf.de/src/dkjson-lua.fsl/homehttp://dkolf.de/src/dkjson-lua.fsl/wiki?name=Documentation

 

编码转换

我们在使用一些类库时会发现大部分库仅支持UTF-8编码,因此如果使用其他编码的话就需要进行编码转换的处理;而Linux上最常见的就是iconv,而lua-iconv就是它的一个Lua API的封装。

 

安装lua-iconv可以通过如下两种方式:

ubuntu下可以使用如下方式

apt-get install luarocks
luarocks install lua-iconv 
cp /usr/local/lib/lua/5.1/iconv.so  /usr/example/lualib/

源码安装方式,需要有gcc环境

wget https://github.com/do^Cloads/ittner/lua-iconv/lua-iconv-7.tar.gz
tar -xvf lua-iconv-7.tar.gz
cd lua-iconv-7
gcc -O2 -fPIC -I/usr/include/lua5.1 -c luaiconv.c -o luaiconv.o -I/usr/include
gcc -shared -o iconv.so -L/usr/local/lib luaiconv.o -L/usr/lib
cp iconv.so  /usr/example/lualib/

  

1、test_iconv.lua

ngx.say("中文")

此时文件编码必须为UTF-8,即Lua文件编码为什么里边的字符编码就是什么。

  

2、example.conf配置文件

     location ~ /lua_iconv {
        default_type 'text/html';
        charset gbk;
        lua_code_cache on;
        content_by_lua_file /usr/example/lua/test_iconv.lua;
     }

通过charset告诉浏览器我们的字符编码为gbk。  

 

3、访问 http://192.168.1.2/lua_iconv会发现输出乱码;

 

此时需要我们将test_iconv.lua中的字符进行转码处理:

local iconv = require("iconv")
local togbk = iconv.new("gbk", "utf-8")
local str, err = togbk:iconv("中文")
ngx.say(str)

通过转码我们得到最终输出的内容编码为gbk, 使用方式iconv.new(目标编码, 源编码)。

 

有如下可能出现的错误:

nil   
    没有错误成功。
iconv.ERROR_NO_MEMORY
    内存不足。
iconv.ERROR_INVALID
    有非法字符。
iconv.ERROR_INCOMPLETE
    有不完整字符。
iconv.ERROR_FINALIZED
    使用已经销毁的转换器,比如垃圾回收了。
iconv.ERROR_UNKNOWN 
    未知错误

 

iconv在转换时遇到非法字符或不能转换的字符就会失败,此时可以使用如下方式忽略转换失败的字符

local togbk_ignore = iconv.new("GBK//IGNORE", "UTF-8")

 

另外在实际使用中进行UTF-8到GBK转换过程时,会发现有些字符在GBK编码表但是转换不了,此时可以使用更高的编码GB18030来完成转换。 

 

更多介绍请参考http://ittner.github.io/lua-iconv/

 

位运算

Lua 5.3之前是没有提供位运算支持的,需要使用第三方库,比如LuaJIT提供了bit库。

1、test_bit.lua 

local bit = require("bit")
ngx.say(bit.lshift(1, 2))
lshift进行左移位运算,即得到4。

  

其他位操作API请参考http://bitop.luajit.org/api.html。Lua 5.3的位运算操作符http://cloudwu.github.io/lua53doc/manual.html#3.4.2

 

cache

ngx_lua模块本身提供了全局共享内存ngx.shared.DICT可以实现全局共享,另外可以使用如Redis来实现缓存。另外还一个lua-resty-lrucache实现,其和ngx.shared.DICT不一样的是它是每Worker进程共享,即每个Worker进行会有一份缓存,而且经过实际使用发现其性能不如ngx.shared.DICT。但是其好处就是不需要进行全局配置。

 

1、创建缓存模块来实现只初始化一次:

vim /usr/example/lualib/mycache.lua 
local lrucache = require("resty.lrucache")
--创建缓存实例,并指定最多缓存多少条目
local cache, err = lrucache.new(200)
if not cache then
   ngx.log(ngx.ERR, "create cache error : ", err)
end

local function set(key, value, ttlInSeconds)
    cache:set(key, value, ttlInSeconds)
end

local function get(key)
    return cache:get(key)
end

local _M = {
  set = set,
  get = get
}

return _M

此处利用了模块的特性实现了每个Worker进行只初始化一次cache实例。

 

2、test_lrucache.lua  

local mycache = require("mycache")
local count = mycache.get("count") or 0
count = count + 1
mycache.set("count", count, 10 * 60 * 60) --10分钟
ngx.say(mycache.get("count"))              

可以实现诸如访问量统计,但仅是每Worker进程的。   

 

3、example.conf配置文件

     location ~ /lua_lrucache {
        default_type 'text/html';
        lua_code_cache on;
        content_by_lua_file /usr/example/lua/test_lrucache.lua;
     }

访问如http://192.168.1.2/lua_lrucache测试。

 

更多介绍请参考https://github.com/openresty/lua-resty-lrucache

 

字符串处理

Lua 5.3之前没有提供字符操作相关的函数,如字符串截取、替换等都是字节为单位操作;在实际使用时尤其包含中文的场景下显然不能满足需求;即使Lua 5.3也仅提供了基本的UTF-8操作

 

Lua UTF-8库

https://github.com/starwing/luautf8

 

LuaRocks安装

#首先确保git安装了
apt-get install git
luarocks install utf8
cp /usr/local/lib/lua/5.1/utf8.so  /usr/example/lualib/

 

源码安装

wget https://github.com/starwing/luautf8/archive/master.zip
unzip master.zip
cd luautf8-master/
gcc -O2 -fPIC -I/usr/include/lua5.1 -c utf8.c -o utf8.o -I/usr/include
gcc -shared -o utf8.so -L/usr/local/lib utf8.o -L/usr/lib

 

1、test_utf8.lua

local utf8 = require("utf8")
local str = "abc中文"
ngx.say("len : ", utf8.len(str), "<br/>")
ngx.say("sub : ", utf8.sub(str, 1, 4))
文件编码必须为UTF8,此处我们实现了最常用的字符串长度计算和字符串截取。
2、example.conf配置文件
     location ~ /lua_utf8 {
        default_type 'text/html';
        lua_code_cache on;
        content_by_lua_file /usr/example/lua/test_utf8.lua;
     }
  

3、访问如http://192.168.1.2/lua_utf8测试得到如下结果

len : 5
sub : abc中

 

字符串转换为unicode编码:

local bit = require("bit")
local bit_band = bit.band
local bit_bor = bit.bor
local bit_lshift = bit.lshift
local string_format = string.format
local string_byte = string.byte
local table_concat = table.concat

local function utf8_to_unicode(str)
    if not str or str == "" or str == ngx.null then
        return nil
    end
    local res, seq, val = {}, 0, nil
    for i = 1, #str do
        local c = string_byte(str, i)
        if seq == 0 then
            if val then
                res[#res + 1] = string_format("%04x", val)
            end

           seq = c < 0x80 and 1 or c < 0xE0 and 2 or c < 0xF0 and 3 or
                              c < 0xF8 and 4 or --c < 0xFC and 5 or c < 0xFE and 6 or
                              0
            if seq == 0 then
                ngx.log(ngx.ERR, 'invalid UTF-8 character sequence' .. ",,," .. tostring(str))
                return str
            end

            val = bit_band(c, 2 ^ (8 - seq) - 1)
        else
            val = bit_bor(bit_lshift(val, 6), bit_band(c, 0x3F))
        end
        seq = seq - 1
    end
    if val then
        res[#res + 1] = string_format("%04x", val)
    end
    if #res == 0 then
        return str
    end
    return "\\u" .. table_concat(res, "\\u")
end

ngx.say("utf8 to unicode : ", utf8_to_unicode("abc中文"), "<br/>")

如上方法将输出utf8 to unicode : \u0061\u0062\u0063\u4e2d\u6587。

 

删除空格:

local function ltrim(s)
    if not s then
        return s
    end
    local res = s
    local tmp = string_find(res, '%S')
    if not tmp then
        res = ''
    elseif tmp ~= 1 then
        res = string_sub(res, tmp)
    end
    return res
end

local function rtrim(s)
    if not s then
        return s
    end
    local res = s
    local tmp = string_find(res, '%S%s*$')
    if not tmp then
        res = ''
    elseif tmp ~= #res then
        res = string_sub(res, 1, tmp)
    end

    return res
end

local function trim(s)
    if not s then
        return s
    end
    local res1 = ltrim(s)
    local res2 = rtrim(res1)
    return res2
end

 

字符串分割:

function split(szFullString, szSeparator)
    local nFindStartIndex = 1
    local nSplitIndex = 1
    local nSplitArray = {}
    while true do
       local nFindLastIndex = string.find(szFullString, szSeparator, nFindStartIndex)
       if not nFindLastIndex then
        nSplitArray[nSplitIndex] = string.sub(szFullString, nFindStartIndex, string.len(szFullString))
        break
       end
       nSplitArray[nSplitIndex] = string.sub(szFullString, nFindStartIndex, nFindLastIndex - 1)
       nFindStartIndex = nFindLastIndex + string.len(szSeparator)
       nSplitIndex = nSplitIndex + 1
    end
    return nSplitArray
end

如split("a,b,c", ",") 将得到一个分割后的table。

 

到此基本的字符串操作就完成了,其他luautf8模块的API和LuaAPI类似可以参考

http://cloudwu.github.io/lua53doc/manual.html#6.4

http://cloudwu.github.io/lua53doc/manual.html#6.5

 

另外对于GBK的操作,可以先转换为UTF-8,最后再转换为GBK即可。

 

 

3
1
分享到:
评论
4 楼 Godparent 2016-09-09  
3 楼 Godparent 2016-09-07  
2 楼 jinnianshilongnian 2015-09-14  
jiuyuehe 写道
开-涛-哥真厉害,一直走在技术的最前端。彻底膜拜!

请问一个问题:在使用同样的库的条件下,c语言算出来的文件crc32 与javascript算出来是否不一致呢?


https://github.com/happyfish100/fastdfs/issues/25

   不回复也没关系哈


这个没做过,可以找相同的算法库,或者是不是因为字符集的问题
1 楼 jiuyuehe 2015-09-02  
开-涛-哥真厉害,一直走在技术的最前端。彻底膜拜!

请问一个问题:在使用同样的库的条件下,c语言算出来的文件crc32 与javascript算出来是否不一致呢?


https://github.com/happyfish100/fastdfs/issues/25

   不回复也没关系哈

相关推荐

    LUA的JSON库

    在LUA环境中,为了实现与JSON数据的互操作,开发者通常需要借助特定的LUA库来解析和生成JSON字符串。"LUA的JSON库"就是这样一个工具,它使得LUA程序能够方便地处理JSON格式的数据,从而与JavaScript环境或其他支持...

    json转lua-table工具

    该脚本的工作原理可能是读取JSON文件,使用`json.load()`或`json.loads()`函数解析JSON数据,然后将解析得到的Python字典或其他数据结构转化为Lua兼容的字符串。转化过程中可能需要注意以下几点: 1. JSON的键是...

    lua-cjson-2.1.0

    2. **序列化Lua数据**:相反,`encode`函数可以将Lua的数据结构转化为JSON字符串,方便数据传输或存储。 3. **速度与效率**:`lua-cjson`使用C语言编写,因此比纯Lua实现的JSON库在性能上有显著优势,特别是在处理...

    jsonnet​的lua开发包luajit-jsonnet.zip

    luajit-jsonnet 是 针对google jsonnet的lua开发支持。 Name luajit-jsonnet - The Google Jsonnet( operation data template language) for Luajit Table of Contents ...

    lua文本转成json文本

    lua json文件转换 数据编排 lua配置表转成 json配置表

    json4lua-0.9.50.zip

    这个库允许 Lua 程序员轻松地处理 JSON 数据,无论是解析来自网络或其他源的 JSON 文件,还是将 Lua 数据结构转换为 JSON 格式以便于传输或存储。 在 Lua 中加载 JSON 文件,首先你需要解压 "json4lua-0.9.50" ...

    lua解析json

    在处理JSON(JavaScript Object Notation)数据时,Lua并不内置直接支持JSON的解析和序列化功能,但我们可以利用其强大的字符串处理能力,尤其是正则表达式,来实现这一目标。本文将深入探讨如何在Lua中解析JSON数据...

    json文件转lua的小工具

    当你在进行Lua开发时,可能会遇到需要将JSON数据转换为Lua数据结构的情况,这时“json2lua”工具就能派上用场。 "json2lua"是一个专门用于将JSON格式的数据转换为Lua语法的实用程序。这个小工具能够解析JSON文件,...

    lua-cjson-2.1.0 lua第三方库(已编译dll)

    1. **编码(Encoding):** 可以将Lua的数据结构(如表、字符串、数值等)转换为JSON格式的字符串。 2. **解码(Decoding):** 支持将JSON字符串解析为相应的Lua值。 3. **速度优化:** 由于是C实现,相对于纯Lua...

    Lua小程序十六进制字符串和二进制数据间的转换[借鉴].pdf

    Lua 小程序十六进制字符串和二进制数据间的转换 本篇文章将介绍 Lua 小程序在十六进制字符串...本文展示了如何使用 Lua 实现十六进制字符串和二进制数据之间的转换,这些技术可以广泛应用于软件开发、数据处理等领域。

    lua-nginx-module-0.10.13

    Lua-Nginx-Module由OpenResty团队开发,旨在提供一种轻量级、高效且易于使用的机制,使开发者能够在Nginx内部处理复杂的业务逻辑,如动态内容生成、流量控制、API网关等功能,从而避免了传统的CGI或FastCGI等模型...

    lua-cjson-2.1.0-已编译

    Lua-cjson是一个为Lua语言设计的JSON(JavaScript Object Notation)编码和解码库,它在Lua环境中提供了高效且易用的JSON接口。JSON是一种轻量级的数据交换格式,广泛应用于网络服务之间的数据通信以及存储数据。Lua...

    lua json插件

    在Lua中,原始的内置功能并不支持直接对JSON进行操作,因此需要依赖于像lua-cjson这样的第三方库来实现JSON与Lua数据结构之间的转换。 lua-cjson-2.1.0是这个插件的一个版本,它是一个高效的C语言实现的JSON编解码...

    6-lua基础篇-字符串

    Lua基础篇-字符串 Lua是一种轻量级的脚本语言,广泛应用于游戏、嵌入式系统等领域。字符串是 Lua 中最基本的数据类型之一,本文将对 Lua 中的字符串进行详细介绍。 字符串定义 在 Lua 中,字符串是由数字、字母...

    lua-json:Lua的JSON编码解码模块

    用于Lua的JSON编码/解码模块 为Lua提供了快速的JSON编码/解码例程: 支持通过元方法/处理程序进行内联数据转换/过滤。 用C语言编写,具有32/64位感知能力。 没有外部依赖性。 json.encode(值,[事件]) 返回...

    lua-nginx-module-master.zip

    2. **配置使用**:在Nginx的配置文件(如`nginx.conf`)中,你可以通过`lua_code_cache`指令控制Lua脚本的缓存策略,`init_by_lua_file`或`init_by_lua`用于执行启动时的Lua代码,`set_by_lua_block`、`rewrite_by_...

    lua-rapidjson-master

    在这个库中,`decode`函数用于解析JSON字符串,而`encode`函数则用于将Lua对象编码为JSON字符串。这些功能极大地提升了Lua处理JSON数据的能力,简化了与外部服务或系统的数据交互。 lua-rapidjson-master的实现充分...

    lua中文手册lua-5.3-zh-manual.pdf

    提供了如数学、字符串处理、表操作等功能。 10. 标准库 标准库是Lua提供的一系列功能库,包括字符串、数学、操作系统交互、调试等方面的功能。 11. 独立版Lua 指的是可以在没有其他依赖的情况下运行的Lua解释器。 ...

    lua-devel-5.3.4-12.el8.aarch64

    2. **库文件**:`liblua.a` 或 `liblua.so` 是静态和动态链接库,它们包含了 Lua 解释器的实现,使得 C/C++ 代码能够链接到 Lua 运行时环境。 3. **其他开发工具**:可能还包括文档、示例代码和测试套件,帮助...

    云风-lua源码欣赏-lua-5.21

    首先,第一章概览中,作者深入到源代码层面,分析了Lua的源文件结构,这包括了源文件的组织方式以及代码风格。通过了解源文件划分,读者可以更好地理解Lua的模块化设计,而代码风格部分则有助于我们了解Lua编程的...

Global site tag (gtag.js) - Google Analytics