Переглянути джерело

add: string.split支持保留空片段

Wendal Chen 2 роки тому
батько
коміт
6cd21c45c0
2 змінених файлів з 144 додано та 27 видалено
  1. 94 0
      demo/string/main.lua
  2. 50 27
      lua/src/lstrlib_exts.c

+ 94 - 0
demo/string/main.lua

@@ -0,0 +1,94 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "strtest"
+VERSION = "2.0.0"
+
+--[[
+本demo演示 string字符串的基本操作
+1. lua的字符串是带长度, 这意味着, 它不依赖0x00作为结束字符串, 可以包含任意数据
+2. lua的字符串是不可变的, 就不能直接修改字符串的一个字符, 修改字符会返回一个新的字符串
+]]
+
+-- sys库是标配
+_G.sys = require("sys")
+
+sys.taskInit(function ()
+    sys.wait(1000) -- 免得看不到日志
+    local tmp
+
+    ----------------------------------------------
+    --================================================
+    -- 字符串的声明和生成
+    --================================================
+
+    -- 常量声明
+    local str = "123455" 
+    log.info("str", str)
+
+    -- 合成式
+    str = string.char(0x31, 0x32, 0x33, 0x34)
+    log.info("str", str)
+    -- lua的字符串可以包含任意数据, 包括 0x00
+    str = string.char(0x12, 0x00, 0xF1, 0x3A)
+    log.info("str", str:toHex()) -- 注意, 这里用toHex(), 因为包含了不可见字符
+
+    -- 使用转义字符
+    str = "\x00\x12ABC"
+    log.info("str", str:toHex()) -- 注意, 这里用toHex(), 因为包含了不可见字符
+    str = "ABC\r\n\t"
+    log.info("str", str:toHex()) -- 注意, 这里用toHex(), 因为包含了不可见字符
+
+
+    -- 解析生成
+    str = string.fromHex("AABB00EE")
+    log.info("str", str:toHex())
+    str = string.fromHex("393837363433")
+    log.info("str", #str, str)
+
+    -- 连接字符串, 操作符 ".."
+    str = "123" .. "," .. "ABC"
+    log.info("str", #str, str)
+
+    -- 格式化生成
+    str = string.format("%s,%d,%f", "123", 45678, 1.5)
+    log.info("str", #str, str)
+
+
+    --================================================
+    -- 字符串的解析与处理
+    --================================================
+    -- 获取长度
+    str = "1234567"
+    log.info("str", #str)
+    -- 获取字符串的HEX字符串显示
+    log.info("str", str:toHex())
+
+    -- 获取指定位置的值, 注意lua的下标是1开始的
+    str = "123ddss"
+    log.info("str[1]", str:byte(1))
+    log.info("str[4]", str:byte(4))
+    log.info("str[1]", string.byte(str, 1))
+    log.info("str[4]", string.byte(str, 4))
+
+    -- 按字符串分割
+    str = "12,2,3,4,5"
+    tmp = str:split(",")
+    log.info("str.split", #tmp, tmp[1], tmp[3])
+    tmp = string.split(str, ",") -- 与前面的等价
+    log.info("str.split", #tmp, tmp[1], tmp[3])
+    str = "/tmp//def/1234/"
+    tmp = str:split("/")
+    log.info("str.split", #tmp, json.encode(tmp))
+    -- 2023.04.11新增的, 可以保留空的分割片段
+    tmp = str:split("/", true) 
+    log.info("str.split", #tmp, json.encode(tmp))
+
+    -- 更多资料
+    -- https://wiki.luatos.com/develop/hex_string.html
+    -- https://wiki.luatos.com/_static/lua53doc/manual.html#3.4
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 50 - 27
lua/src/lstrlib_exts.c

@@ -2,6 +2,7 @@
 @module  string
 @summary 字符串操作函数
 @tag LUAT_CONF_BSP
+@demo    string
 */
 #include "luat_base.h"
 #include "luat_malloc.h"
@@ -126,16 +127,26 @@ int l_str_fromHex (lua_State *L) {
 
 /*
 按照指定分隔符分割字符串
-@api string.split(str, delimiter)
+@api string.split(str, delimiter, keepEmtry)
 @string 输入字符串
-@string 分隔符
+@string 分隔符,可选,默认 ","
+@bool 是否保留空白片段,默认为false,不保留. 2023.4.11之后的固件可用
 @return table 分割后的字符串表
 @usage
-("123,456,789"):split(',') --> {'123','456','789'}
+local tmp = string.split("123,233333,122")
+log.info("tmp", json.encode(tmp))
+local tmp = ("123,456,789"):split(',') --> {'123','456','789'}
+log.info("tmp", json.encode(tmp))
+
+-- 保留空片段, 2023.4.11之后的固件可用
+local str = "/tmp//def/1234/"
+local tmp = str:split("/", true) 
+log.info("str.split", #tmp, json.encode(tmp))
 */
 int l_str_split (lua_State *L) {
   size_t len = 0;
-  const char *tmp = luaL_checklstring(L, 1, &len);
+  int keepEmtry = 0;
+  const char *str = luaL_checklstring(L, 1, &len);
   if (len == 0) {
     lua_newtable(L);
     return 1;
@@ -145,32 +156,44 @@ int l_str_split (lua_State *L) {
   const char *delimiters = luaL_checklstring(L, 2, &dlen);
   if (dlen < 1) {
     delimiters = ",";
+    dlen = 1;
   }
-
-  // 因为strtok会修改字符串, 所以需要把str临时拷贝一份
-  char* str = (char*)luat_heap_malloc(len + 1);
-  char* ptr = str;
-  if (str == NULL) {
-    lua_newtable(L);
-    LLOGW("out of memory when split");
-    return 1;
+  if (lua_isboolean(L, 3) && lua_toboolean(L, 3)) {
+    keepEmtry = 1;
   }
-  memset(str, 0, len + 1);
-  memcpy(str, tmp, len);
-
-  char *token;
-  size_t count = 0;
-  token = strtok(str, delimiters);
   lua_newtable(L);
-  while( token != NULL ) {
-    lua_pushnumber(L,count+1);
-    lua_pushstring(L, token);
-    lua_settable(L,-3);
-    // printf("%s - %ld\n", token, count);
-    count ++;
-    token = strtok(NULL, delimiters);
-  }
-  luat_heap_free(ptr);
+  int prev = -1;
+  size_t count = 1;
+  for (int i = 0; i < len; i++)
+  {
+    // LLOGD("d[%s] [%.*s] %d", delimiters, dlen, str+i, dlen);
+    if (!memcmp(delimiters, str+i, dlen)) {
+      // LLOGD("match %d %i %d",prev, i, keepEmtry);
+      if ((prev+1) != i || (keepEmtry)) {
+        lua_pushinteger(L, count);
+        lua_pushlstring(L, str + prev + 1, i - prev - 1);
+        // LLOGD("add %d [%.*s]", count, i - prev, str+prev);
+        lua_settable(L, -3);
+        count += 1;
+      }
+      i += (dlen - 1);
+      prev = i;
+      if (i == len - 1 && keepEmtry) {
+        lua_pushinteger(L, count);
+        lua_pushlstring(L, "", 0);
+        lua_settable(L, -3);
+        break;
+      }
+    }
+    else {
+      if (i == len - 1) {
+        // 最后一个字符了
+        lua_pushinteger(L, count);
+        lua_pushlstring(L, str + prev + 1, len - prev - 1);
+        lua_settable(L, -3);
+      }
+    }
+  }
   return 1;
 }