Lua中如何分割字符串?

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

原文链接 https://stackoverflow.com/questions/1426954

点赞
stackoverflow用户173806
stackoverflow用户173806

如果你想要在 Lua 中分割一个字符串,你可以尝试使用 string.gmatch() 或 string.sub() 方法。如果你知道想要分割字符串的位置,使用 string.sub() 方法。如果你需要解析字符串来找到分割位置,使用 string.gmatch() 方法。

以下是使用 string.gmatch() 方法的例子,来自 Lua 5.1 参考手册:

 t = {}
 s = "from=world, to=Lua"
 for k, v in string.gmatch(s, "(%w+)=(%w+)") do
   t[k] = v
 end
2009-09-15 15:59:12
stackoverflow用户191376
stackoverflow用户191376

以下是函数:

function split(pString, pPattern)
   local Table = {}  -- 注意:在Lua-5.0中使用{n = 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

2009-10-16 18:36:32
stackoverflow用户41661
stackoverflow用户41661

就像string.gmatch会在字符串中查找_pattern_一样,这个函数将查找在模式之间的_things_:

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

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

2009-10-30 01:37:52
stackoverflow用户276811
stackoverflow用户276811

如果您只想遍历标记,这样就很不错:

line = "one, two and 3!"

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

输出:

one,

two

and

3!

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

2010-09-12 03:52:53
stackoverflow用户621785
stackoverflow用户621785

你可以使用这个方法:

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)   -- 使用 string:split 方法获取按照定界符 pattern 分割后的字符串列表
2011-02-17 16:58:53
stackoverflow用户900078
stackoverflow用户900078

以下是我非常简单的解决方法。使用 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
2011-09-30 19:26:26
stackoverflow用户1514861
stackoverflow用户1514861

我喜欢这个简短的解决方案

function split(s, delimiter)
    result = {};
    for match in (s..delimiter):gmatch("(.-)"..delimiter) do
        table.insert(result, match);
    end
    return result;
end
2013-11-20 15:46:00
stackoverflow用户134758
stackoverflow用户134758

因为有多种方法来解决问题,这里是我的做法:

代码


local content = [=[
Lorem ipsum dolor sit amet, consectetur adipisicing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat.
]=]

local function split(str, sep)
   local result = {}
   local regex = ("([^%s]+)"):format(sep)
   for each in str:gmatch(regex) do
      table.insert(result, each)
   end
   return result
end

local lines = split(content, "\n")
for _,line in ipairs(lines) do
   print(line)
end

输出

Lorem ipsum dolor sit amet, consectetur adipisicing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat.

解释

gmatch函数作为迭代器,它抓取所有与regex匹配的字符串。 正则表达式regex 接收到分隔符之前的所有字符。

2014-08-22 14:38:17
stackoverflow用户953863
stackoverflow用户953863

我使用上述例子来创建自己的函数。但对我来说缺失的一块是自动转义特殊字符。

这是我的贡献:

function split(text, delim)
    --根据文本和分隔符(仅一个字符)返回字段的数组
    local result = {}           
    local magic = "().%+-*?[]^$"
 
    if delim == nil then
        delim = "%s"
    elseif string.find(delim, magic, 1, true) then
        --转义特殊字符
        delim = "%"..delim
    end
 
    local pattern = "[^"..delim.."]+"
    for w in string.gmatch(text, pattern) do
        table.insert(result, w)
    end
    return result
end
2015-10-23 23:32:47
stackoverflow用户1006422
stackoverflow用户1006422

仅仅坐在一个分隔符上

local str = 'one,two'
local regxEverythingExceptComma = '([^,]+)'
for x in string.gmatch(str, regxEverythingExceptComma) do
    print(x)
end
2016-04-27 07:49:16
stackoverflow用户5287638
stackoverflow用户5287638

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

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

-- gsplit: 迭代由模式分隔的字符串中的子字符串
--
-- 参数:
-- text (string)    - 要迭代的字符串
-- pattern (string) - 分隔符模式
-- plain (boolean)  - 如果为 true(或真值),则将模式解释为普通字符串
--                    而不是 Lua 模式
--
-- 返回: 迭代器
--
-- 用法:
-- 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
        -- 空分隔符!
        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: 将字符串分割为由模式分隔的子字符串。
--
-- 参数:
-- text (string)    - 要迭代的字符串
-- pattern (string) - 分隔符模式
-- plain (boolean)  - 如果为 true(或真值),则将模式解释为普通字符串
--                    而不是 Lua 模式
--
-- 返回: table (一个包含子字符串的序列表)
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
2017-04-24 07:23:40
stackoverflow用户6760065
stackoverflow用户6760065

一种独特的方法

function str_split(str, sep)
    if sep == nil then
        sep = '%s'
    end

    local res = {}
    local func = function(w)
        table.insert(res, w)
    end

    string.gsub(str, '[^'..sep..']+', func)
    return res
end
2018-08-23 11:45:15
stackoverflow用户88888888
stackoverflow用户88888888

你可以使用penlight库。其中有一个使用分隔符拆分字符串并输出列表的函数。

它实现了许多在Lua中编程时可能需要的函数,这些函数在Lua中缺失。

以下是使用示例:

>
> stringx = require "pl.stringx"
>
> str = "welcome to the world of lua"
>
> arr = stringx.split(str, " ")
>
> arr
{welcome,to,the,world,of,lua}
>

2019-07-01 12:31:47
stackoverflow用户6139563
stackoverflow用户6139563

根据使用情况,这可能很有用。它剪切旗帜两侧的所有文本:

b = "This is a string used for testing"

--Removes unwanted text
c = (b:match("a([^/]+)used"))

print (c)

输出:

string
2019-08-12 22:36:42
stackoverflow用户2150472
stackoverflow用户2150472
-- 使用分隔符和限制将字符串拆分成表格
string.split = function(str, pat, limit)
  local t = {}
  local fpat = "(.-)" .. pat
  local last_end = 1
  local s, e, cap = str:find(fpat, 1)
  while s do
    if s ~= 1 or cap ~= "" then
      table.insert(t, cap)
    end

    last_end = e+1
    s, e, cap = str:find(fpat, last_end)

    if limit ~= nil and limit <= #t then
      break
    end
  end

  if last_end <= #str then
    cap = str:sub(last_end)
    table.insert(t, cap)
  end

  return t
end

这是一个处理分割数量的版本,请参考。虽然问得很迟,但希望能对某些人有帮助。

2020-02-11 15:13:15
stackoverflow用户7518149
stackoverflow用户7518149

这是在Lua 4.0中有效的例程,返回一个由sep限定的inputstr中的子字符串组成的表格t

function string_split(inputstr, sep)
    local inputstr = inputstr .. sep
    local idx, inc, t = 0, 1, {}
    local idx_prev, substr
    repeat
        idx_prev = idx
        inputstr = strsub(inputstr, idx + 1, -1)    -- 去掉包含最后一次strfind寻找到的匹配(或最初为空),保留其余部分(或最初的全部)
        idx = strfind(inputstr, sep)                -- 找到分隔符首次出现的0-based r_index
        if idx == nil then break end                -- 如果没找到就结束
        substr = strsub(inputstr, 0, idx)           -- 提取分隔符之前出现的子字符串(即下一个定界符之前的数据区域)
        substr = gsub(substr, "[%c" .. sep .. " ]", "") -- 消除控制字符、分隔符和空格
        t[inc] = substr             -- 存储子字符串(即数据区域)
        inc = inc + 1               -- 迭代到下一个
    until idx == nil
    return t
end

这个简单的测试

inputstr = "the brown lazy fox jumped over the fat grey hen ... or something."
sep = " "
t = {}
t = string_split(inputstr,sep)
for i=1,15 do
    print(i, t[i])
end

输出:

--> t[1]=the
--> t[2]=brown
--> t[3]=lazy
--> t[4]=fox
--> t[5]=jumped
--> t[6]=over
--> t[7]=the
--> t[8]=fat
--> t[9]=grey
--> t[10]=hen
--> t[11]=...
--> t[12]=or
--> t[13]=something.
2022-05-16 21:28:06
stackoverflow用户23213
stackoverflow用户23213

我发现许多其他回答存在无法处理的边缘情况 (例如,当给定的字符串包含 #{} 字符,或者当给定分隔符字符如 % 需要转义时)。因此,这里是我选择的实现方式:

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

    -- 如果需要,添加转义字符
    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
2022-07-07 19:59:21