Geteilte Saite in Lua?

160

Ich muss einen einfachen String teilen, aber es scheint keine Funktion dafür zu geben, und die manuelle Methode, die ich getestet habe, schien nicht zu funktionieren. Wie würde ich das machen?

RCIX
quelle
Bitte sehen Sie Splitting Strings
Andrew Hare

Antworten:

96

Hier ist meine wirklich einfache Lösung. Verwenden Sie die Funktion gmatch, um Zeichenfolgen zu erfassen, die mindestens ein Zeichen von etwas anderem als dem gewünschten Trennzeichen enthalten. Das Trennzeichen ist standardmäßig ** ein beliebiges * Leerzeichen (% s in Lua):

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

.

Adrian Mole
quelle
1
Vielen Dank. Genau das, wonach ich gesucht habe.
Nicholas
3
Wow, die erste Antwort in dieser ganzen Frage, die tatsächlich eine Funktion hat, die eine Tabelle zurückgibt. Beachten Sie jedoch, dass t und ich den Modifikator "local" benötigen, da Sie Globals überschreiben. :)
cib
3
Wie andere bereits betont haben, können Sie dies vereinfachen, indem Sie table.insert (t, str) anstelle von t [i] = str verwenden. Dann benötigen Sie nicht i = 1 oder i = i +1
James Newton
2
Funktioniert nicht, wenn der String leere Werte enthält, z. 'foo,,bar'. Sie erhalten {'foo','bar'}statt{'foo', '', 'bar'}
andras
5
Das stimmt. Die nächste Version funktioniert in diesem Fall: 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

Wenn Sie eine Zeichenfolge in Lua aufteilen, sollten Sie die Methoden string.gmatch () oder string.sub () ausprobieren. Verwenden Sie die Methode string.sub (), wenn Sie den Index kennen, bei dem Sie die Zeichenfolge teilen möchten, oder verwenden Sie string.gmatch (), wenn Sie die Zeichenfolge analysieren, um die Position zu finden, an der die Zeichenfolge aufgeteilt werden soll.

Beispiel mit string.gmatch () von Lua 5.1 Referenzhandbuch :

 t = {}
 s = "from=world, to=Lua"
 for k, v in string.gmatch(s, "(%w+)=(%w+)") do
   t[k] = v
 end
gut
quelle
Ich habe mir trotzdem eine Implementierung von dieser Lua-Benutzer-Seite "ausgeliehen"
RCIX
24

Wenn Sie nur über die Token iterieren möchten, ist dies ziemlich ordentlich:

line = "one, two and 3!"

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

Ausgabe:

einer,

zwei

und

3!

Kurze Erklärung: Das Muster "[^% s] +" stimmt mit jeder nicht leeren Zeichenfolge zwischen Leerzeichen überein.

Hugo
quelle
2
Das Muster %Sist gleich dem, das Sie erwähnt haben, ebenso %Swie die Negation von %s, ebenso wie %Ddie Negation von %d. Ist außerdem %wgleich [A-Za-z0-9_](je nach Gebietsschema werden möglicherweise andere Zeichen unterstützt).
Lars Gyrup Brink Nielsen
14

So wie string.gmatchfindet Muster in einem String, wird diese Funktion , um die Dinge finden zwischen Mustern:

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

Standardmäßig wird alles zurückgegeben, was durch Leerzeichen getrennt ist.

Norman Ramsey
quelle
6
+1. Hinweis für alle anderen Lua-Anfänger: Dies gibt einen Iterator zurück, und 'zwischen Mustern' enthält den Anfang und das Ende der Zeichenfolge. (Als Neuling musste ich es versuchen, um diese Dinge herauszufinden.)
Darius Bacon
12

Hier ist die Funktion:

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

Nennen Sie es wie:

list=split(string_to_split,pattern_to_match)

z.B:

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


Weitere Informationen finden Sie hier:
http://lua-users.org/wiki/SplitJoin

Faisal Hanif
quelle
7

Ich mag diese kurze Lösung

function split(s, delimiter)
    result = {};
    for match in (s..delimiter):gmatch("(.-)"..delimiter) do
        table.insert(result, match);
    end
    return result;
end
Ivo Beckers
quelle
Dies ist mein Favorit, da es so kurz und einfach ist. Ich verstehe nicht ganz, was passiert, könnte mir jemand erklären?
Sechseck
2
Dies schlägt fehl, wenn Punkt als Trennzeichen (oder möglicherweise ein anderes magisches Musterzeichen) verwendet wird
TurboHz
6

Da es mehr als einen Weg gibt, eine Katze zu häuten, ist hier mein Ansatz:

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

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

Erklärung :

Die gmatchFunktion arbeitet als Iterator und ruft alle übereinstimmenden Zeichenfolgen ab regex. Das regexnimmt alle Zeichen, bis es ein Trennzeichen findet.

Diego Pino
quelle
5

Sie können diese Methode verwenden:

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) 
krsk9999
quelle
5

Viele dieser Antworten akzeptieren nur Trennzeichen mit einem Zeichen oder behandeln Randfälle nicht gut (z. B. leere Trennzeichen), daher dachte ich, ich würde eine endgültigere Lösung anbieten.

Hier sind zwei Funktionen, gsplitund splitaus dem Code in der angepasst Scribunto MediaWiki - Erweiterung , die auf Wikis wie Wikipedia verwendet wird. Der Code ist unter der GPL v2 lizenziert . Ich habe die Variablennamen geändert und Kommentare hinzugefügt, um den Code ein wenig verständlicher zu machen, und ich habe den Code so geändert, dass anstelle von Scribuntos Mustern für Unicode-Zeichenfolgen reguläre Lua-Zeichenfolgenmuster verwendet werden. Der ursprüngliche Code hat Testfälle hier .

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

Einige Beispiele für die verwendete splitFunktion:

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
Jack Taylor
quelle
5

ein Weg, den man bei anderen nicht sieht

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
Hohenheim
quelle
4

Einfach auf einem Begrenzer sitzen

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

Ich habe die obigen Beispiele verwendet, um meine eigene Funktion zu erstellen. Aber das fehlende Stück für mich entkam automatisch magischen Charakteren.

Hier ist mein Beitrag:

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
unerschrockener Held
quelle
Dies war auch mein großes Problem. Dies funktioniert großartig mit magischen Charakteren, nett
Andrew White
1

Sie könnten die Taschenlampenbibliothek verwenden . Dies hat eine Funktion zum Teilen von Zeichenfolgen mithilfe eines Trennzeichens, das eine Liste ausgibt.

Es hat viele der Funktionen implementiert, die wir möglicherweise beim Programmieren benötigen und die in Lua fehlen.

Hier ist das Beispiel für die Verwendung.

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

quelle
0

Dies kann je nach Anwendungsfall hilfreich sein. Es schneidet den gesamten Text auf beiden Seiten der Flags ab:

b = "This is a string used for testing"

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

print (c)

Ausgabe:

string
Grün
quelle
0

Super spät zu dieser Frage, aber für den Fall, dass jemand eine Version möchte, die die Anzahl der Splits verarbeitet, die Sie erhalten möchten .....

-- 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
Benjamin Vison
quelle
0

Wenn Sie in Lua programmieren, haben Sie hier kein Glück. Lua ist DIE einzige Programmiersprache, die notorisch berüchtigt ist, weil ihre Autoren "die" Split-Funktion nie in der Standardbibliothek implementiert haben und stattdessen 16 Bildschirme mit Erklärungen und lahmen Ausreden geschrieben haben, warum sie es nicht taten und nicht taten. durchsetzt mit zahlreichen halbarbeitenden Beispielen, die praktisch für fast jeden funktionieren, aber in Ihrem Eckkoffer brechen . Dies ist nur der Stand der Technik bei Lua, und jeder, der in Lua programmiert, beißt einfach die Zähne zusammen und iteriert über Charaktere. Es gibt viele Lösungen, die manchmal besser sind, aber genau null Lösungen, die zuverlässig besser sind.

Szczepan Hołyszewski
quelle