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


当前回答

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

这里有两个函数,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

其他回答

就像字符串一样。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

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

如果你在Lua中拆分字符串,你应该尝试string.gmatch()或string.sub()方法。如果知道要分割字符串的索引,则使用string.sub()方法;如果要解析字符串以找到要分割字符串的位置,则使用string.gmatch()方法。

使用Lua 5.1参考手册中的string.gmatch()示例:

 t = {}
 s = "from=world, to=Lua"
 for k, v in string.gmatch(s, "(%w+)=(%w+)") do
   t[k] = v
 end

对于那些从“在Lua中编程”这本书的练习10.1中学习过的人来说,似乎很清楚我们不能使用后面书中解释的概念(迭代器),而且函数应该接受多个字符分隔符。

split()是一个让模式匹配不需要的内容(split)并在空字符串上返回一个空表的技巧。plainSplit()的返回更像其他语言中的split。

magic = "([%%%.%(%)%+%*%?%[%]%^%$])"

function split(str, sep, plain)
    if plain then sep = string.gsub(sep, magic, "%%%1") end
    
    local N = '\255'
    str = N..str..N
    str = string.gsub(str, sep, N..N)

    local result = {}
    for word in string.gmatch(str, N.."(.-)"..N) do
        if word ~= "" then
            table.insert(result, word)
        end
    end
    return result
end


function plainSplit(str, sep)
    sep = string.gsub(sep, magic, "%%%1")

    local result = {}
    local start = 0
    repeat
        start = start + 1

        local from, to = string.find(str, sep, start)
        from = from and from-1
        
        local word = string.sub(str, start, from, true)
        table.insert(result, word)

        start = to
    until start == nil

    return result
end


function tableToString(t)
    local ret = "{"
    for _, word in ipairs(t) do
        ret = ret .. '"' .. word .. '", '
    end
    ret = string.sub(ret, 1, -3)
    ret = ret .. "}"

    return #ret > 1 and ret or "{}"
end

function runSplit(func, title, str, sep, plain)
    print("\n" .. title)
    print("str: '"..str.."'")
    print("sep: '"..sep.."'")
    local t = func(str, sep, plain)
    print("-- t = " .. tableToString(t))
end



print("\n\n\n=== Pattern split ===")
runSplit(split, "Exercice 10.1", "a whole new world", " ")
runSplit(split, "With trailing seperator", "  a  whole   new world  ", " ")
runSplit(split, "A word seperator", "a whole new world", " whole ")
runSplit(split, "Pattern seperator", "a1whole2new3world", "%d")
runSplit(split, "Magic characters as plain seperator", "a$.%whole$.%new$.%world", "$.%", true)
runSplit(split, "Control seperator", "a\0whole\1new\2world", "%c")
runSplit(split, "ISO Time", "2020-07-10T15:00:00.000", "[T:%-%.]")

runSplit(split, " === [Fails] with \\255 ===", "a\255whole\0new\0world", "\0", true)

runSplit(split, "How does your function handle empty string?", "", " ")



print("\n\n\n=== Plain split ===")
runSplit(plainSplit, "Exercice 10.1", "a whole new world", " ")
runSplit(plainSplit, "With trailing seperator", "  a  whole   new world  ", " ")
runSplit(plainSplit, "A word seperator", "a whole new world", " whole ")
runSplit(plainSplit, "Magic characters as plain seperator", "a$.%whole$.%new$.%world", "$.%")

runSplit(plainSplit, "How does your function handle empty string?", "", " ")

输出

=== Pattern split ===

Exercice 10.1
str: 'a whole new world'
sep: ' '
-- t = {"a", "whole", "new", "world"}

With trailing seperator
str: '  a  whole   new world  '
sep: ' '
-- t = {"a", "whole", "new", "world"}

A word seperator
str: 'a whole new world'
sep: ' whole '
-- t = {"a", "new world"}

Pattern seperator
str: 'a1whole2new3world'
sep: '%d'
-- t = {"a", "whole", "new", "world"}

Magic characters as plain seperator
str: 'a$.%whole$.%new$.%world'
sep: '$.%'
-- t = {"a", "whole", "new", "world"}

Control seperator
str: 'awholenewworld'
sep: '%c'
-- t = {"a", "whole", "new", "world"}

ISO Time
str: '2020-07-10T15:00:00.000'
sep: '[T:%-%.]'
-- t = {"2020", "07", "10", "15", "00", "00", "000"}

 === [Fails] with \255 ===
str: 'a�wholenewworld'
sep: ''
-- t = {"a"}

How does your function handle empty string?
str: ''
sep: ' '
-- t = {}



=== Plain split ===

Exercice 10.1
str: 'a whole new world'
sep: ' '
-- t = {"a", "whole", "new", "world"}

With trailing seperator
str: '  a  whole   new world  '
sep: ' '
-- t = {"", "", "a", "", "whole", "", "", "new", "world", "", ""}

A word seperator
str: 'a whole new world'
sep: ' whole '
-- t = {"a", "new world"}

Magic characters as plain seperator
str: 'a$.%whole$.%new$.%world'
sep: '$.%'
-- t = {"a", "whole", "new", "world"}

How does your function handle empty string?
str: ''
sep: ' '
-- t = {""}

函数如下:

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

你可以使用这个方法:

function string:split(delimiter)
  local result = { }
  local from  = 1
  local delim_from, delim_to = string.find( self, delimiter, from  )
  while delim_from do
    table.insert( result, string.sub( self, from , delim_from-1 ) )
    from  = delim_to + 1
    delim_from, delim_to = string.find( self, delimiter, from  )
  end
  table.insert( result, string.sub( self, from  ) )
  return result
end

delimiter = string.split(stringtodelimite,pattern)