2009-09-15 12 views
123

Ich muss eine einfache Teilung einer Zeichenfolge tun, aber es scheint keine Funktion dafür zu sein, und die manuelle Art, die ich getestet habe, schien nicht zu funktionieren. Wie würde ich es tun?Split-Saite in Lua?

Antwort

76

Bitte sehen Splitting Strings:

Hier sind verschiedene Möglichkeiten, eine Zeichenfolge in eine Liste von Teil Aufspalten die ursprüngliche Zeichenfolge auf Vorkommen einiger Separator (Zeichen, Zeichensatz zu brechen, oder Muster). Dies wird üblicherweise als String Split [2] -Funktion bezeichnet.

+2

Leider ist die Seite seitdem bearbeitet worden ist (obwohl es zum gleichen Thema ist), und die Passage du nicht auf der Seite auftritt zitiert wird . Daher ist es ideal, Link-Only-Antworten zu vermeiden und relevante Informationen in die Antwort selbst aufzunehmen. – ShreevatsaR

27

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

Beispiel unter Verwendung von string.gmatch() von Lua 5.1 Reference Manual:

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

Ich "geliehen" eine Implementierung von diesem lua-Benutzer Seite trotzdem – RCIX

10

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 es mag:

list=split(string_to_split,pattern_to_match) 

Beispiel:

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


Weitere gehen hier:
http://lua-users.org/wiki/SplitJoin

14

Wie string.gmatch wird Muster in einem String finden, wird diese Funktion, um die Dinge finden zwischen Muster:

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 es gibt zurück, was durch Leerzeichen getrennt ist.

+5

+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.) –

22

Wenn Sie nur über die Token iterieren wollen, ist dies recht ordentlich:

line = "one, two and 3!" 

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

Ausgang:

ein,

zwei

und

3!

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

+0

Das Muster '% S' ist gleich dem, das Sie erwähnt haben, da'% S' die Negation von '% s' ist, wie'% D' die Negation von '% d' ist. Zusätzlich ist '% w' gleich' [A-Za-z0-9_] '(andere Zeichen können abhängig von Ihrem Gebietsschema unterstützt werden). –

4

können Sie 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) 
64

Hier meine wirklich einfache Lösung ist. Verwenden Sie die gmatch-Funktion, um Zeichenfolgen zu erfassen, die mindestens EINEN anderen Buchstaben als das gewünschte Trennzeichen enthalten. Der Separator ist ANY Leerzeichen (% s in Lua) standardmäßig:

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

Danke. ** Nur ** was 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

+1

Das hat funktioniert. Es ist nur für einzelne Zeichen Trennzeichen. Um nach Zeichenfolgen wie XML-Tags zu trennen, ändern Sie stattdessen das Übereinstimmungsmuster in "(.-) (" .. sep .. ")". Hinweis: Wenn die Zeichenfolge mit sep endet, schlägt die letzte Übereinstimmung fehl. Fügen Sie am Ende der Eingabezeichenfolge eine neue Zeile oder ein beliebiges Zeichen ein, um dies zu beheben. –

6

Ich mag dieses kurze Lösung

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

Das ist mein Favorit, da es so kurz ist und einfach. Ich verstehe nicht ganz, was passiert, könnte mir jemand erklären? – hexagonest

+1

Das scheitert bei der Verwendung von Punkt als Trennzeichen (oder möglicherweise eines anderen magischen Zeichens) – TurboHz

5

Weil es mehr als einen Weg gibt die Haut eine Katze, hier ist 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 

Ausgang: 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 gmatch Funktion als Iterator arbeitet, holt er die Saiten alles, was regex entsprechen. Das regex nimmt alle Zeichen, bis es ein Trennzeichen findet.

1

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

Dies war mein großes Problem auch. Das funktioniert gut mit magischen Charakteren, nett –

0

einfach auf ein Trennzeichen sitzt

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

Viele dieser Antworten nur einzelne Zeichen Separatoren übernehmen, oder handeln nicht mit Rand Fällen gut (zB leere Trennzeichen), also dachte ich, ich würde eine definitive Lösung anbieten.

Hier sind zwei Funktionen, gsplit und split vom code im Scribunto MediaWiki extension angepasst, 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 auch den Code geändert, um reguläre Lua-String-Muster anstelle von Scribuntos Mustern für Unicode-Strings zu verwenden. Der ursprüngliche Code enthält Testfälle 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 

Einige Beispiele für die split Funktion im Einsatz:

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