web-dev-qa-db-fra.com

Corde fendue à Lua?

J'ai besoin de faire une simple division d'une chaîne, mais il ne semble pas y avoir de fonction pour cela, et la méthode manuelle que j'ai testée ne semble pas fonctionner. Comment pourrais-je le faire?

146
RCIX

Voici ma solution très simple. Utilisez la fonction gmatch pour capturer des chaînes contenant au moins UN caractère de ANALYSE autre que le séparateur souhaité. Le séparateur est TOUT ESPACE (% s en Lua) par défaut:

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

Si vous divisez une chaîne en Lua, vous devriez essayer les méthodes string.gmatch () ou string.sub (). Utilisez la méthode string.sub () si vous connaissez l'index sur lequel vous souhaitez scinder la chaîne, ou utilisez string.gmatch () si vous souhaitez analyser la chaîne pour rechercher l'emplacement où diviser la chaîne.

Exemple utilisant string.gmatch () de Manuel de référence de Lua 5.1 :

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

Si vous voulez juste parcourir les jetons, c'est très joli:

line = "one, two and 3!"

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

Sortie:

un,

deux

et

3!

Explication brève: le modèle "[^% s] +" correspond à chaque chaîne non vide située entre les espaces.

23
Hugo

Tout comme string.gmatch trouvera patterns dans une chaîne, cette fonction trouvera les choses entre patterns:

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

Par défaut, il retourne tout ce qui est séparé par des espaces.

14
Norman Ramsey

Voici la fonction:

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

Appelez ça comme:

list=split(string_to_split,pattern_to_match)

par exemple.:

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


Pour plus, allez ici:
http://lua-users.org/wiki/SplitJoin

11
Faisal Hanif

J'aime cette courte solution

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

Parce qu'il y a plus d'une façon de peler un chat, voici mon approche:

Code:

#!/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

Sortie: 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.

Explication:

La fonction gmatch fonctionne comme un itérateur, elle extrait toutes les chaînes qui correspondent à regex. La regex prend tous les caractères jusqu'à trouver un séparateur.

6
Diego Pino

Vous pouvez utiliser cette méthode:

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
krsk9999

Simplement assis sur un délimiteur

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

Un grand nombre de ces réponses n'acceptent que les séparateurs à un caractère ou ne traitent pas bien les cas Edge (séparateurs vides, par exemple). J'ai donc pensé proposer une solution plus définitive.

Voici deux fonctions, gsplit et split, adaptées du code dans le extension Scribunto MediaWiki , qui est utilisé sur des wikis tels que Wikipedia. Le code est sous licence GPL v2 . J'ai changé les noms des variables et ajouté des commentaires pour rendre le code un peu plus facile à comprendre. J'ai également modifié le code pour qu'il utilise des modèles de chaînes Lua classiques au lieu des modèles de Scribunto pour les chaînes Unicode. Le code original a des tests élémentaires ici .

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

Quelques exemples de la fonction split utilisée:

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
4
Jack Taylor

une voie qu'on ne voit pas chez les autres

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
Hohenheim

J'ai utilisé les exemples ci-dessus pour créer ma propre fonction. Mais la pièce manquante pour moi échappait automatiquement aux personnages magiques.

Voici ma contribution:

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

Vous pouvez utiliser bibliothèque de penlight . Cela a une fonction pour diviser une chaîne en utilisant un délimiteur qui affiche la liste.

Il a mis en œuvre de nombreuses fonctions dont nous pourrions avoir besoin lors de la programmation et manquantes dans Lua.

Voici l'exemple pour l'utiliser.

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

Selon le cas d'utilisation, cela pourrait être utile. Il coupe tout le texte de chaque côté des drapeaux:

b = "This is a string used for testing"

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

print (c)

Sortie:

string
0
greenage