Dividi la stringa in Lua?


160

Ho bisogno di fare una semplice divisione di una stringa, ma non sembra esserci una funzione per questo, e il modo manuale che ho testato non sembra funzionare. Come lo farei?


Si prega di vedere Splitting Strings
Andrew Hare,

Risposte:


96

Ecco la mia soluzione davvero semplice. Utilizzare la funzione gmatch per acquisire stringhe che contengono almeno un carattere di qualsiasi cosa diversa dal separatore desiderato. Il separatore è ** qualsiasi * spazio bianco (% s in Lua) per impostazione predefinita:

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
Grazie. Proprio quello che stavo cercando.
Nicholas,

3
Wow, la prima risposta in tutta questa domanda che in realtà ha una funzione che restituisce una tabella. Nota però che io e te abbiamo bisogno del modificatore "locale", dato che stai sovrascrivendo i globi. :)
cib

3
Come altri hanno sottolineato, puoi semplificarlo usando table.insert (t, str) invece di t [i] = str e quindi non hai bisogno di i = 1 o i = i +1
James Newton,

2
Non funziona se la stringa contiene valori vuoti, ad es. 'foo,,bar'. Si ottiene {'foo','bar'}, invece di{'foo', '', 'bar'}
Andras

5
Giusto. La prossima versione funzionerà in tal caso: 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

Se stai dividendo una stringa in Lua, dovresti provare i metodi string.gmatch () o string.sub (). Utilizzare il metodo string.sub () se si conosce l'indice in cui si desidera dividere la stringa oppure utilizzare string.gmatch () se si analizzerà la stringa per trovare la posizione in cui dividere la stringa.

Esempio usando string.gmatch () dal Manuale di riferimento di Lua 5.1 :

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

Ho "preso in prestito" un'implementazione da quella pagina degli utenti lua grazie comunque
RCIX,

24

Se vuoi semplicemente scorrere i token, questo è abbastanza pulito:

line = "one, two and 3!"

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

Produzione:

uno,

Due

e

3!

Breve spiegazione: il modello "[^% s] +" corrisponde a ogni stringa non vuota tra caratteri spaziali.


2
Lo schema %Sè uguale a quello che hai menzionato, come %Sè la negazione di %s, come %Dè la negazione di %d. Inoltre, %wè uguale a [A-Za-z0-9_](altri caratteri potrebbero essere supportati a seconda delle impostazioni internazionali).
Lars Gyrup Brink Nielsen,

14

Proprio come string.gmatchtroverà i pattern in una stringa, questa funzione troverà le cose tra i pattern:

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

Di default restituisce tutto ciò che è separato da spazi bianchi.


6
+1. Nota per tutti gli altri principianti di Lua: questo restituisce un iteratore e "tra i pattern" include l'inizio e la fine della stringa. (Come principiante, ho dovuto provarlo per capire queste cose.)
Darius Bacon,

12

Ecco la funzione:

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

Chiamalo come:

list=split(string_to_split,pattern_to_match)

per esempio:

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


Per di più vai qui:
http://lua-users.org/wiki/SplitJoin


7

Mi piace questa soluzione breve

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

Questo è il mio preferito, poiché è così breve e semplice. Non capisco bene cosa succede, qualcuno potrebbe spiegarmi?
esagonale il

2
Ciò fallisce quando si usa il punto come delimitatore (o potenzialmente qualsiasi altro personaggio magico)
TurboHz

6

Perché ci sono più di un modo per scuoiare un gatto, ecco il mio approccio:

Codice :

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

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

Spiegazione :

La gmatchfunzione funziona come iteratore, recupera tutte le stringhe corrispondenti regex. La regexprende tutti i caratteri fino a quando trova un separatore.


5

Puoi usare questo metodo:

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

Molte di queste risposte accettano solo separatori a carattere singolo o non trattano bene i casi limite (ad es. Separatori vuoti), quindi ho pensato di fornire una soluzione più definitiva.

Qui sono due funzioni, gsplite split, adattato dal codice nella estensione Scribunto MediaWiki , che è usato su wiki come Wikipedia. Il codice è concesso in licenza in base alla GPL v2 . Ho cambiato i nomi delle variabili e aggiunto commenti per rendere il codice un po 'più semplice da capire, e ho anche cambiato il codice per usare i normali schemi di stringa Lua invece dei modelli di Scribunto per le stringhe Unicode. Il codice originale contiene casi di test qui .

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

Alcuni esempi della splitfunzione in uso:

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

un modo non visto negli altri

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

Semplicemente seduto su un delimitatore

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

3

Ho usato gli esempi sopra per creare la mia funzione. Ma il pezzo mancante per me stava automaticamente sfuggendo ai personaggi magici.

Ecco il mio contributo:

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

Anche questo è stato il mio grosso problema. Funziona benissimo con personaggi magici, simpatico
Andrew White

1

È possibile utilizzare la libreria penlight . Questo ha una funzione per dividere la stringa usando il delimitatore che restituisce l'elenco.

Ha implementato molte delle funzioni di cui potremmo avere bisogno durante la programmazione e la mancanza in Lua.

Ecco l'esempio per usarlo.

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

0

A seconda del caso d'uso, questo potrebbe essere utile. Taglia tutto il testo su entrambi i lati delle bandiere:

b = "This is a string used for testing"

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

print (c)

Produzione:

string

0

Super in ritardo a questa domanda, ma nel caso qualcuno voglia una versione che gestisca la quantità di divisioni che vuoi ottenere .....

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

Se programmi a Lua, sei sfortunato qui. Lua è L'unico linguaggio di programmazione che è notoriamente famigerato perché i suoi autori non hanno mai implementato "la" funzione divisa nella libreria standard, e invece hanno scritto 16 schermate di spiegazioni e scuse scuse sul perché non lo facessero e non lo avrebbero fatto, intervallati da numerosi esempi a metà lavoro che sono virtualmente garantito il funzionamento per quasi tutti, ma pausa nel vostro caso d'angolo. Questo è solo lo stato dell'arte di Lua e tutti coloro che programmano in Lua finiscono semplicemente per stringere i denti e iterare sui personaggi. Esistono molte soluzioni che a volte sono migliori, ma esattamente zero soluzioni che sono attendibilmente migliori.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.