在Lua中分割字符串?


160

我需要对字符串进行简单的拆分,但是似乎没有为此功能,而且我测试的手动方式似乎无效。我该怎么办?


Answers:


96

这是我真正简单的解决方案。使用gmatch函数捕获包含至少一个除所需分隔符以外的任何字符的字符串。分隔符默认为** any *空格(在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


1
谢谢。只是我一直在寻找。
尼古拉斯

3
哇,这是整个问题的第一个答案,实际上它具有返回表的功能。不过请注意,t和t需要“ local”修饰符,因为它正在覆盖全局变量。:)
cib

3
正如其他人指出的那样,您可以使用table.insert(t,str)代替t [i] = str来简化此过程,然后就不需要i = 1或i = i +1了
James Newton

2
如果string包含空值,则无效。'foo,,bar'。您得到的{'foo','bar'}不是{'foo', '', 'bar'}
andras

5
那就对了。在这种情况下,可以使用下一个版本: function split(inputstr, sep) sep=sep or '%s' local t={} for field,s in string.gmatch(inputstr, "([^"..sep.."]*)("..sep.."?)") do table.insert(t,field) if s=="" then return t end end end
巴特(Bart)

33

如果要在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用户页面“借用”了一个实现–感谢
RCIX

24

如果您只想遍历令牌,这非常简洁:

line = "one, two and 3!"

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

输出:

之一,

3!

简短说明:“ [^%s] +”模式与空格字符之间的每个非空字符串匹配。


2
该模式%S等于你提到的一个,因为%S是否定%s,好像%D是的否定%d。此外,%w等于[A-Za-z0-9_](取决于您的语言环境,可能支持其他字符)。
Lars Gyrup Brink Nielsen 2014年

14

就像在字符串中string.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

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


6
+1。请注意其他Lua初学者:这将返回一个迭代器,并且“之间的模式”包括字符串的开头和结尾。(作为一个新手,我不得不尝试解决这些问题。)
Darius Bacon

12

这是函数:

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


7

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

function split(s, delimiter)
    result = {};
    for match in (s..delimiter):gmatch("(.-)"..delimiter) do
        table.insert(result, match);
    end
    return result;
end

这是我的最爱,因为它非常简短。我不太了解会发生什么,有人可以向我解释吗?
2013年

2
使用点作为定界符(或可能使用任何其他图案魔术字符)时,此操作将失败
TurboHz

6

因为有多种方法可以给猫皮毛,所以这是我的方法:

代码

#!/usr/bin/env lua

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直到它找到一个分离器需要的所有字符。


5

您可以使用以下方法:

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) 

5

这些答案很多都只接受单字符分隔符,或者不能很好地处理边缘情况(例如,空分隔符),因此我想我会提供一个更确定的解决方案。

这是两个功能,gsplitsplit,根据Scribunto MediaWiki扩展中代码改编而成,这是在像Wikipedia维基使用。该代码是根据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

5

一种别人看不见的方式

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

4

只需坐在分隔符上

local str = 'one,two'
local regxEverythingExceptComma = '([^,]+)'
for x in string.gmatch(str, regxEverythingExceptComma) do
    print(x)
end

3

我使用以上示例来构建自己的功能。但是对我来说,缺少的部分是自动转义魔术角色。

这是我的贡献:

function split(text, delim)
    -- returns an array of fields based on text and delimiter (one character only)
    local result = {}
    local magic = "().%+-*?[]^$"

    if delim == nil then
        delim = "%s"
    elseif string.find(delim, magic, 1, true) then
        -- escape magic
        delim = "%"..delim
    end

    local pattern = "[^"..delim.."]+"
    for w in string.gmatch(text, pattern) do
        table.insert(result, w)
    end
    return result
end

这也是我的大问题。这适用于魔术角色,很
Andrew White

1

您可以使用penlight库。它具有使用定界符分割字符串的功能,该定界符输出列表。

它实现了我们在Lua编程和丢失时可能需要的许多功能。

这是使用它的示例。

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

0

根据使用情况,这可能会很有用。它将在标志的两边剪切所有文本:

b = "This is a string used for testing"

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

print (c)

输出:

string

0

这个问题超级晚了,但是如果有人想要一个可以处理您想要的拆分数量的版本.....

-- Split a string into a table using a delimiter and a limit
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

0

如果您在Lua编程,那么您在这里很不幸。Lua是一种臭名昭著的编程语言,因为它的作者从未在标准库中实现过“拆分”功能,而是写了16屏完整的解释和la脚的借口,说明为什么不这样做,不愿意这样做,穿插着那些几乎保证工作几乎每个人都休息,但在众多的半工作例极端情况。这只是Lua的最新技术,在Lua中编程的每个人最终都只是咬紧牙关,反复浏览角色。存在许多有时更好的解决方案,但恰好是零的可靠解决方案。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.