在Lua中拆分字符串?

Posted

技术标签:

【中文标题】在Lua中拆分字符串?【英文标题】:Split string in Lua? 【发布时间】:2010-11-28 10:57:53 【问题描述】:

我需要对字符串进行简单的拆分,但似乎没有此功能,而且我测试的手动方式似乎不起作用。我该怎么做?

【问题讨论】:

请看Splitting Strings 【参考方案1】:

这是我非常简单的解决方案。使用 gmatch 函数捕获除所需分隔符之外至少包含 一个 字符的 anything 字符的字符串。默认情况下,分隔符是 **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

.

【讨论】:

谢谢。 正是我正在寻找的东西。 哇,这整个问题中的第一个答案实际上有一个返回表格的函数。但请注意, t 和 i 需要“本地”修饰符,因为它是您覆盖全局变量。 :) 正如其他人指出的那样,您可以通过使用 table.insert(t,str) 而不是 t[i] = str 来简化这一点,然后您就不需要 i=1 或 i = i +1 如果字符串包含空值则不起作用,例如。 'foo,,bar'。你得到'foo','bar' 而不是'foo', '', 'bar' 没错。下一个版本将在这种情况下工作: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【参考方案2】:

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

使用来自Lua 5.1 Reference Manual 的 string.gmatch() 的示例:

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

【讨论】:

我从那个 lua-users 页面“借”了一个实现,谢谢【参考方案3】:

如果您只是想遍历标记,这非常简洁:

line = "one, two and 3!"

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

输出:

一个,

两个

3!

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

【讨论】:

模式%S等于你提到的那个,因为%S%s的否定,就像%D%d的否定。此外,%w 等于 [A-Za-z0-9_](可能支持其他字符,具体取决于您的语言环境)。【参考方案4】:

就像string.gmatch 会在字符串中找到patterns,这个函数会找到between 模式的东西:

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

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

【讨论】:

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

如果你在 Lua 中编程,那么你在这里就不走运了。 Lua 是一种恰好臭名昭著的编程语言,因为它的作者从未在标准库中实现“拆分”函数,而是写了 16 个屏幕全屏的解释和蹩脚的借口来解释为什么他们没有和不会,穿插着许多半工作的例子,这些例子几乎可以保证对几乎所有人都有效,但会打破你的极端情况。这只是 Lua 最先进的技术,使用 Lua 编程的每个人最终都会咬紧牙关,迭代字符。存在许多有时更好的解决方案,但可靠更好的完全零解决方案。

【讨论】:

“存在很多有时更好的解决方案,但确实是零解决方案确实更好。”然后写一个可靠更好的。如果作者可以写一篇,你也可以。如果你不能写出一个满足每个人的需求,那么你就会明白为什么它不在 Lua 中。 Lua 被设计为主机应用程序的配置/扩展语言,主机提供特定领域的库。标准库是可选的并且故意最小化,主要是对一些 ANSI C 库的精简包装。 @Mud 你没抓住重点。每个算法都可以用图灵完备的语言实现,所以任何人都可以只移植 JS 的 split()phpexplode() 或其他任何东西。但是由于 Lua 作者拒绝为 Lua 标准化一个解决方案,每个人都必须这样做。这是数十年来积累的成千上万的程序员小时。而且只有 LUA 作者可以标准化解决方案! 你说有“完全为零的解决方案比咬紧牙关和迭代字符可靠更好”。现在你要么说split() 或PHP 的explode() 可靠更好,要么推荐一些不可靠的东西。 “这是数十年来积累的成千上万的程序员小时”对于任何没有“包括厨房水槽”库的语言都是如此,包括 ANSI C,地球上最流行的语言,以及 Lua 故意最小化库的基础.这基本上是一个论点,即任何语言都不应该包含一个庞大的库。 “你没抓住重点。” Lua 被设计为一个,用于向宿主应用程序添加脚本/配置。它是故意最小的。你似乎没有明白这一点。 我认为这个答案有点苛刻和拖钓,但实际上是真的。对“16 屏解释(…)”感兴趣的读者:Split Join.【参考方案6】:

函数如下:

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】:

因为给猫剥皮的方法不止一种,所以这是我的方法:

代码

#!/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 获取所有字符,直到找到分隔符。

【讨论】:

【参考方案8】:

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

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

【讨论】:

这是我最喜欢的,因为它又短又简单。我不太明白会发生什么,有人能给我解释一下吗? 当使用点作为分隔符(或任何其他模式魔术字符)时失败【参考方案9】:

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

这里有两个函数,gsplitsplit,改编自 Scribunto MediaWiki extension 中的 code,用于 Wikipedia 等 wiki。该代码在GPL v2 下获得许可。我更改了变量名称并添加了 cmets 以使代码更易于理解,并且我还更改了代码以使用常规 Lua 字符串模式而不是 Scribunto 的 Unicode 字符串模式。原代码有测试用例here。

-- 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

【讨论】:

【参考方案10】:

你可以使用这个方法:

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) 

【讨论】:

【参考方案11】:

其他人看不到的方式

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

【讨论】:

【参考方案12】:

只需坐在分隔符上

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

【讨论】:

【参考方案13】:

您可以使用penlight library。这具有使用分隔符拆分字符串的功能,该分隔符输出列表。

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

这是使用它的示例。

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

【讨论】:

【参考方案14】:

我使用上面的例子来制作我自己的函数。但对我来说缺少的部分是自动逃脱魔法字符。

这是我的贡献:

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

【讨论】:

这也是我的大问题。这对魔法角色很有效,很好【参考方案15】:

这个问题太晚了,但如果有人想要一个版本来处理你想要得到的拆分数量.....

-- 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

【讨论】:

【参考方案16】:

根据用例,这可能很有用。它会剪切标志两侧的所有文本:

b = "This is a string used for testing"

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

print (c)

输出:

string

【讨论】:

以上是关于在Lua中拆分字符串?的主要内容,如果未能解决你的问题,请参考以下文章

Lua拆分字符串并将输出放入表中

LUA,多个数字字符串到数字

Lua - util_server.lua:440 尝试索引本地“自我”(零值)

lua入门笔记7 字符串库

lua脚本中怎么对比字符串

在lua中从一个字符串中移除空间源码