Frage Lua: Split String in Worte, wenn nicht zitiert


So habe ich den folgenden Code, um eine Zeichenfolge zwischen Leerzeichen zu teilen:

text = "I am 'the text'"
for string in text:gmatch("%S+") do
    print(string)
end

Das Ergebnis:

I
am
'the
text'

Aber ich muss das tun:

I
am
the text --[[yep, without the quotes]]

Wie kann ich das machen?

Bearbeiten: nur um die Frage zu ergänzen, besteht die Idee darin, Parameter von einem Programm zu einem anderen Programm zu übertragen. Hier ist die Pull-Anfrage, an der ich gerade arbeite: https://github.com/mpv-player/mpv/pull/1619


6
2018-02-22 22:35


Ursprung


Antworten:


Es mag Wege geben, dies mit cleverem Parsing zu tun, aber ein alternativer Weg könnte darin bestehen, einen einfachen Zustand zu verfolgen und Fragmente basierend auf der Erkennung von zitierten Fragmenten zusammenzuführen. So etwas kann funktionieren:

local text = [[I "am" 'the text' and "some more text with '" and "escaped \" text"]]
local spat, epat, buf, quoted = [=[^(['"])]=], [=[(['"])$]=]
for str in text:gmatch("%S+") do
  local squoted = str:match(spat)
  local equoted = str:match(epat)
  local escaped = str:match([=[(\*)['"]$]=])
  if squoted and not quoted and not equoted then
    buf, quoted = str, squoted
  elseif buf and equoted == quoted and #escaped % 2 == 0 then
    str, buf, quoted = buf .. ' ' .. str, nil, nil
  elseif buf then
    buf = buf .. ' ' .. str
  end
  if not buf then print((str:gsub(spat,""):gsub(epat,""))) end
end
if buf then print("Missing matching quote for "..buf) end

Dies wird gedruckt:

I
am
the text
and
some more text with '
and
escaped \" text

Aktualisiert, um gemischte und maskierte Anführungszeichen zu verarbeiten. Aktualisiert, um Zitate zu entfernen. Aktualisiert, um mit zitierten Wörtern umzugehen.


6
2018-02-22 23:29



Versuche dies:

text = [[I am 'the text' and '' here is "another text in quotes" and this is the end]]

local e = 0
while true do
    local b = e+1
    b = text:find("%S",b)
    if b==nil then break end
    if text:sub(b,b)=="'" then
        e = text:find("'",b+1)
        b = b+1
    elseif text:sub(b,b)=='"' then
        e = text:find('"',b+1)
        b = b+1
    else
        e = text:find("%s",b+1)
    end
    if e==nil then e=#text+1 end
    print("["..text:sub(b,e-1).."]")
end

1
2018-02-23 01:27



Lua Patterns sind nicht leistungsstark, um diese Aufgabe richtig zu bewältigen. Hier ist ein LPeg Lösung angepasst von der Lua Lexer. Es behandelt sowohl einfache als auch doppelte Anführungszeichen.

local lpeg = require 'lpeg'

local P, S, C, Cc, Ct = lpeg.P, lpeg.S, lpeg.C, lpeg.Cc, lpeg.Ct

local function token(id, patt) return Ct(Cc(id) * C(patt)) end

local singleq = P "'" * ((1 - S "'\r\n\f\\") + (P '\\' * 1)) ^ 0 * "'"
local doubleq = P '"' * ((1 - S '"\r\n\f\\') + (P '\\' * 1)) ^ 0 * '"'

local white = token('whitespace', S('\r\n\f\t ')^1)
local word = token('word', (1 - S("' \r\n\f\t\""))^1)

local string = token('string', singleq + doubleq)

local tokens = Ct((string + white + word) ^ 0)


input = [["This is a string" 'another string' these are words]]
for _, tok in ipairs(lpeg.match(tokens, input)) do
  if tok[1] ~= "whitespace" then
     if tok[1] == "string" then
        print(tok[2]:sub(2,-2)) -- cut off quotes
     else
       print(tok[2])
     end
  end
end

Ausgabe:

This is a string
another string
these
are
words

1
2018-02-23 13:14