2015-02-22 22 views
6

yüzden beyaz alanlara arasında bir dize bölmek için aşağıdaki kodu var:Lua: alıntılanan sürece kelimelere bölünmüş dize

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

sonucu:

I 
am 
'the 
text' 

Ama bunu yapmak gerek:

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

Bunu nasıl yapabilirim?

Düzenle: Sadece soruları tamamlamak için, fikir bir programdan başka bir programa parametre aktarmaktır. İşte şu anda gözden geçirme isteğim: Şu anda inceleme: https://github.com/mpv-player/mpv/pull/1619

cevap

6

Bunu akıllı ayrıştırma ile yapmanın bazı yolları olabilir, ancak alternatif bir durum, basit bir durumu takip etmek ve parçaları algılamaya göre birleştirmek olabilir. alıntılanan parçalar. Böyle bir şey işe yarayabilir:

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 

Bu yazdırır: karışık ve kaçan tırnak işlemek için Güncelleme

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

. Teklifleri kaldırmak için güncellendi. Alıntı yapılan kelimeleri işlemek için güncellendi.

+0

Ben dize ayrıştırma kullanarak bir şey tercih ediyorum. Her neyse, postda söylemedim, hem tek hem de çift tırnak ile çalışmak için bir şeye ihtiyacım var, çünkü bu kodun fikri kabuktan parametreleri ayrıştırmaktır. – m45t3r

+0

Tek ve çift tırnak ile çalışmasını sağlamak için bu çözümü güncellemek kolaydır; ''^'' '' i [[^ ["']]]' ve '" $ $ 'ile" [[[' "] $]]' ile değiştirin. Ayrıca açılış teklifinin kapanış ile eşleştiğini kontrol etmeniz gerekebilir. –

+0

Dize ayrıştırmasıyla birlikte yapmak mümkündür, ancak çözümün daha karmaşık olması olasıdır (Lua kalıpları ihtiyacınız olan şeyi ifade edecek kadar güçlü olmadığından bir ifadeyle değil). –

1

bu deneyin:

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

Hem tek hem de çift tırnak ve boş alıntılanan metni işlemek için sabit. – lhf

1

Lua Desenler düzgün bu görevi işlemek için güçlü değil. İşte, Lua Lexer'dan uyarlanmış bir LPeg çözümü. Hem tek hem de çift tırnakları işler.

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 

Çıktı:

This is a string 
another string 
these 
are 
words