Lua C 字符串和数组操作

转自lua程序设计第二版

数组操作

在Lua中,“数组”只是table的一个别名,像lua_settable和lua_gettable这种操作table的函数,也可以用于操作数组。
然而API为为数组操作提供了专门的函数。
* 出于性能考虑,通常会在算法中用循环来访问数组
* 为了方便,像字符串key,整数key是很常用的

//index表示在栈中的位置,key表示元素在 table中的位置
void lua_rawgeti(Lua_State *L,int index,int key);
void lua_rawseti(Lua_State *L,int index,int key);

//假设t为整数,
//lua_rawgeti(L,t,key)等价于
lua_pushnumber(L,key);
lua_rawget(L,t);

//lua_rawseti(L,t,key)等价于
lua_pushnumber(L,key);
lua_insert(L,-2);
lua_rawset(L,t);

示例

int l_map(lua_State *L){
    int i,n;
    //第一个参数必须是table
    luaL_checktype(L,1,LUA_TABLE);
    //第二个参数必须是一个函数
    lua_checktype(L,2,LUA_FUNCTION);

    //获取table的大小
    n = lua_objlen(L,1);

    for(i = 1;i<=n;i++){
        //压入f
        lua_pushvalue(L,2);
        //压入t[i]
        lua_rawgeti(L,1,i);
        //调用f(t[i])
        lua_call(L,1,1);
        //t[i] = 结果
        lua_rawseti(L,1,i);
    }

    return 0;
}

字符串操作

当一个C函数从Lua收到一个字符串参数时,必须遵守两条规则:
* 不要再访问字符串时从栈中弹出它
* 不要修改字符串

//把一个字符串s的子串传递给Lua
//区间[i,j]
lua_pushlstring(L,s+i,j-i+1)

切割字符串实例

static int  l_split(lua_State *L){
    const char *s = luaL_checkstring(L,1);
    const char *sep = luaL_chcekcstring(L,2);
    const char *e ;
    int i = 1;

    //结果
    lua_newtable(L);

    //遍历所有分隔符
    while((e = strchr(s,*sep)) != NULL){
        //压入字符串
        lua_pushlstring(L,s,e-s);

        lua_rawseti(L,-2,i++);

        //跳过分隔符
        s=e+1;
    }

    //压入最后一个字符串
    lua_pushstring(L,s);
    lua_rawseti(L,-2,i);

    //返回table
    return 1;
}

字符串链接

lua_concat

//链接并弹出栈顶的n个值
void lua_concat (lua_State *L, int n);

lua_pushfstring(lua_State *L,const char *fmt,…)

类似于C函数sprintf.
但与sprintf不同的是,无需提供这个新字符串的缓冲。Lua会动态的创建一个足够大的缓存来存放新字符串。
* %% 字符%
* %s 字符串
* %d 整数
* %f 表示Lua中的数字,即双精度浮点数
* %c 接受一个整数,并将其格式化为一个字符

缓存机制

这套机制包含两个层面的缓冲
1. 类似于I/O操作中的缓冲,就是在一个本地缓冲中收集较小的字符串,并在本地缓冲填满后将结果传递给Lua(通过lua_pushlstring)
2. 使用lua_concat或其他栈算法来链接多次缓冲填满后的结果

//string.upper缓冲示例
static int str_upper(lua_State *L){
    size_t l;
    size_t i;
    //声明一个luaL_Buffer变量
    luaL_Buffer b;
    const char* s = luaL_checklstr(L,1,&l);
    //用luaL_buffinit来初始化,在初始化后,这个变量中会保留一份状态L的副本,由此再调用其他操作缓冲的函数时,就无需传递状态参数了。
    luaL_buffinit(L,&b);
    for(i = 0;i//将一个字符放入缓冲中 
        luaL_addchar(&b,toupper(unsigned char)(s[i])));
        //将具有显式长度的字符串 luaL_addlstring 
        //将对于“0结尾”的字符串 luaL_addstring
    }
    //更新缓冲,并将最终的字符留在栈顶
    lua_pushresult(&b);
    return 1;
}

当向缓冲中添加东西时,缓冲会将一些中间结果放到栈中。因此,不应假设栈顶还是和使用缓冲之前一样。

你可能感兴趣的:(lua)