我需要做一个简单的字符串分割,但似乎没有一个函数,我测试的手动方式似乎不起作用。我该怎么做呢?


当前回答

很多答案只接受单字符分隔符,或者不能很好地处理边缘情况(例如空分隔符),所以我认为我将提供一个更明确的解决方案。

这里有两个函数,gsplit和split,改编自Scribunto MediaWiki扩展中的代码,用于维基百科等维基。该代码在GPL v2下获得许可。我已经更改了变量名,并添加了注释,使代码更容易理解,我还更改了代码,使用常规的Lua字符串模式,而不是Scribunto的Unicode字符串模式。原始代码在这里有测试用例。

-- gsplit: iterate over substrings in a string separated by a pattern
-- 
-- Parameters:
-- text (string)    - the string to iterate over
-- pattern (string) - the separator pattern
-- plain (boolean)  - if true (or truthy), pattern is interpreted as a plain
--                    string, not a Lua pattern
-- 
-- Returns: iterator
--
-- Usage:
-- for substr in gsplit(text, pattern, plain) do
--   doSomething(substr)
-- end
local function gsplit(text, pattern, plain)
  local splitStart, length = 1, #text
  return function ()
    if splitStart then
      local sepStart, sepEnd = string.find(text, pattern, splitStart, plain)
      local ret
      if not sepStart then
        ret = string.sub(text, splitStart)
        splitStart = nil
      elseif sepEnd < sepStart then
        -- Empty separator!
        ret = string.sub(text, splitStart, sepStart)
        if sepStart < length then
          splitStart = sepStart + 1
        else
          splitStart = nil
        end
      else
        ret = sepStart > splitStart and string.sub(text, splitStart, sepStart - 1) or ''
        splitStart = sepEnd + 1
      end
      return ret
    end
  end
end

-- split: split a string into substrings separated by a pattern.
-- 
-- Parameters:
-- text (string)    - the string to iterate over
-- pattern (string) - the separator pattern
-- plain (boolean)  - if true (or truthy), pattern is interpreted as a plain
--                    string, not a Lua pattern
-- 
-- Returns: table (a sequence table containing the substrings)
local function split(text, pattern, plain)
  local ret = {}
  for match in gsplit(text, pattern, plain) do
    table.insert(ret, match)
  end
  return ret
end

split函数的一些例子:

local function printSequence(t)
  print(unpack(t))
end

printSequence(split('foo, bar,baz', ',%s*'))       -- foo     bar     baz
printSequence(split('foo, bar,baz', ',%s*', true)) -- foo, bar,baz
printSequence(split('foo', ''))                    -- f       o       o

其他回答

如果你只想遍历这些令牌,这是非常简洁的:

line = "one, two and 3!"

for token in string.gmatch(line, "[^%s]+") do
   print(token)
end

输出:

一个, 两个 而且 3!

简单解释:“[^%s]+”模式匹配空格字符之间的每个非空字符串。

我有一个非常简单的解决办法。使用gmatch()函数捕获包含除所需分隔符以外的至少一个字符的字符串。分隔符默认为任何空格(Lua中的%s):

function mysplit (inputstr, sep)
        if sep == nil then
                sep = "%s"
        end
        local t={}
        for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
                table.insert(t, str)
        end
        return t
end

就像字符串一样。Gmatch将查找字符串中的模式,这个函数将查找模式之间的内容:

function string:split(pat)
  pat = pat or '%s+'
  local st, g = 1, self:gmatch("()("..pat..")")
  local function getter(segs, seps, sep, cap1, ...)
    st = sep and seps + #sep
    return self:sub(segs, (seps or 0) - 1), cap1 or sep, ...
  end
  return function() if st then return getter(st, g()) end end
end

默认情况下,它返回由空格分隔的任何内容。

函数如下:

function split(pString, pPattern)
   local Table = {}  -- NOTE: use {n = 0} in Lua-5.0
   local fpat = "(.-)" .. pPattern
   local last_end = 1
   local s, e, cap = pString:find(fpat, 1)
   while s do
      if s ~= 1 or cap ~= "" then
     table.insert(Table,cap)
      end
      last_end = e+1
      s, e, cap = pString:find(fpat, last_end)
   end
   if last_end <= #pString then
      cap = pString:sub(last_end)
      table.insert(Table, cap)
   end
   return Table
end

这样称呼它:

list=split(string_to_split,pattern_to_match)

例如:

list=split("1:2:3:4","\:")

更多信息请点击这里: http://lua-users.org/wiki/SplitJoin

我发现许多其他答案都有失败的边缘情况(例如。当给定的字符串包含#,{或}字符,或给定的分隔符,如%,需要转义)。下面是我使用的实现:

local function newsplit(delimiter, str)
    assert(type(delimiter) == "string")
    assert(#delimiter > 0, "Must provide non empty delimiter")

    -- Add escape characters if delimiter requires it
    delimiter = delimiter:gsub("[%(%)%.%%%+%-%*%?%[%]%^%$]", "%%%0")

    local start_index = 1
    local result = {}

    while true do
       local delimiter_index, _ = str:find(delimiter, start_index)

       if delimiter_index == nil then
          table.insert(result, str:sub(start_index))
          break
       end

       table.insert(result, str:sub(start_index, delimiter_index - 1))

       start_index = delimiter_index + 1
    end

    return result
end