lua中指定分隔符拆分字符串

我正在尝试创建一个在lua中具有选择分隔符的split()函数,当默认值为空格时,它可以正常工作。但是当我为函数提供分隔符时,就会出现问题,不知何故它不返回最后一个子字符串。

函数:

function split(str,sep)
if sep == nil then
    words = {}
    for word in str:gmatch("%w+") do table.insert(words, word) end
    return words
end
return {str:match((str:gsub("[^"..sep.."]*"..sep, "([^"..sep.."]*)"..sep)))} -- BUG!! doesnt return last value
end

我尝试运行以下代码:

local str = "a,b,c,d,e,f,g"
local sep = ","
t = split(str,sep)
for i,j in ipairs(t) do
    print(i,j)
end

我得到的输出为:

1   a
2   b
3   c
4   d
5   e
6   f

无法找到哪里出现了错误...

点赞
用户107090
用户107090

当分割字符串时,避免边角情况的最简单方法是在你知道字符串不会以分隔符结尾时,将分隔符附加到字符串末尾:

str = "a,b,c,d,e,f,g"
str = str .. ','
for w in str:gmatch("(.-),") do print(w) end

或者,你可以使用包含可选分隔符的模式:

str = "a,b,c,d,e,f,g"
for w in str:gmatch("([^,]+),?") do print(w) end

实际上,由于我们正在捕获非分隔符,所以我们不需要可选分隔符:

str = "a,b,c,d,e,f,g"
for w in str:gmatch("([^,]+)") do print(w) end
2016-10-20 10:18:02
用户1849746
用户1849746

下面是我常用的 split() 函数:

-- split("a,b,c", ",") => {"a", "b", "c"}
function split(s, sep)
    local fields = {}

    -- 如果没有传入分隔符,则默认以空格为分隔符
    local sep = sep or " "
    -- 构造分隔符匹配模式
    local pattern = string.format("([^%s]+)", sep)
    -- 使用 pattern 匹配 s,并将分割后的结果添加到 fields 数组中
    string.gsub(s, pattern, function(c) fields[#fields + 1] = c end)

    -- 返回结果数组
    return fields
end
2016-10-21 15:30:24
用户4984564
用户4984564

"[^"..sep.."]*"..sep 这就是问题所在。你正在匹配一个由非分隔符字符组成并以分隔符结尾的字符串。然而,你要匹配的最后一个子字符串(g)并不是由分隔符字符而是由字符串结尾所结尾的。

最快解决此问题的方法是也将 \0 视为分隔符 ("[^"..sep.."\0]*"..sep),因为它代表了字符串的开始和/或结尾。这样,g 就算不是由分隔符而是由字符串结尾所结尾,仍会被视为匹配。

我认为你的方法总体上过于复杂;首先,你可以只匹配不包含分隔符的个别子字符串;其次,你可以在 for 循环中使用 gmatch 函数来实现。

local result = {}
for field in your_string:gsub(("[^%s]+"):format(your_separator)) do
  table.insert(result, field)
end
return result

编辑:上面的代码可以更加简单:

local pattern = "[^%" .. your_separator .. "]+"
for field in string.gsub(your_string, pattern) do
-- ...and so on (其余部分应该很容易理解)

编辑 2:请记得你还需要对分隔符进行转义。如 % 这样的分隔符如果不转义为 %% 将会导致问题。

function escape(str)
  return str:gsub("([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1")
end
2016-10-22 11:09:21