2009-05-06 3 views
67

Mam ciąg w Lua i chcę iterować poszczególne znaki w nim. Ale żaden kod Próbowałem prace i oficjalna instrukcja pokazuje tylko, jak znaleźć i zastąpić podciągi :(jak iterować poszczególne znaki w ciągi lua?

str = "abcd" 
for char in str do -- error 
    print(char) 
end 

for i = 1, str:len() do 
    print(str[ i ]) -- nil 
end 

Odpowiedz

101

w Lua 5.1, można iteracyjne z bohaterów ciąg tego w kilku sposobów

podstawowa pętla będzie:.

 
for i = 1, #str do 
    local c = str:sub(i,i) 
    -- do something with c 
end 

Ale może to być bardziej efektywne w użyciu wzoru z string.gmatch() dostać iterator ciągu znaków:

 
for c in str:gmatch"." do 
    -- do something with c 
end 

Albo nawet do korzystania string.gsub() wywołać funkcję dla każdego char:

 
str:gsub(".", function(c) 
    -- do something with c 
end) 

We wszystkich z powyższego, skorzystałem z faktu, że moduł string jest ustawiany jako metatabilny dla wszystkich wartości łańcuchowych, więc jego funkcje mogą być wywoływane jako elementy przy użyciu notacji :. Użyłem również (nowy w 5.1, IIRC) #, aby uzyskać długość łańcucha.

Najlepsza odpowiedź dla aplikacji zależy od wielu czynników, a testy porównawcze to znajomość, jeśli wydajność ma znaczenie.

Możesz chcieć oceniać dlaczego trzeba iteracyjne ciągu znaków, a spojrzeć na jednym z regularnych modułów ekspresyjnych, które zostały zobowiązane do Lua, lub do nowoczesnego podejścia spojrzeć lpeg modułu Roberto, który implementuje parsowania Wyrażenie Grammers dla Lua.

+0

Dzięki. O module lpeg, o którym wspomniałeś - czy zapisuje pozycje tokenów w oryginalnym tekście po tokenizacji? Zadanie, które muszę wykonać, polega na podświetleniu składni specyficznego prostego języka w scite za pośrednictwem lua (bez skompilowanego parsera C++). Również, jak zainstalować LPG? Wydaje się, że ma .c źródło w dystrybucji - czy musi być skompilowane razem z lua? – grigoryvp

+0

Building lpeg utworzy bibliotekę DLL (lub .so), która powinna być przechowywana tam, gdzie jest to wymagane. (np. gdzieś zidentyfikowane przez zawartość globalnego pakietu.cpath w instalacji lua). Musisz także zainstalować jego moduł pomocniczy re.lua, jeśli chcesz użyć jego uproszczonej składni. Z gramatyki lpeg można uzyskać wywołania zwrotne i przechwytywać tekst na wiele sposobów, a na pewno można użyć przechwytywania, aby po prostu zapisać lokalizację dopasowania do późniejszego wykorzystania. Jeśli celem jest podświetlanie składni, to PEG nie jest złym wyborem narzędzia. – RBerteig

+2

Nie wspominając już o [najnowszych wydaniach SciTE] (http: //www.scintilla.org/SciTEDownload.html) (od 2.22) to Scintillua, lexer na bazie LPEG, co oznacza, że ​​może działać od razu po wyjęciu z pudełka, bez konieczności ponownego kompilowania. –

10

Jeśli używasz Lua 5, spróbuj:

for i = 1, string.len(str) do 
    print(string.sub(str, i, i)) 
end 
4

W zależności od wykonywanego zadania może być łatwiej używać string.byte. Jest to również najszybszy sposób, ponieważ pozwala uniknąć tworzenia nowego podciągu, który jest dość drogi w Lua dzięki hashowaniu każdego nowego ciągu i sprawdzeniu, czy jest już znany. Możesz wstępnie obliczyć kod symboli, których szukasz z tym samym string.byte, aby zachować czytelność i przenośność.

local str = "ab/cd/ef" 
local target = string.byte("/") 
for idx = 1, #str do 
    if str:byte(idx) == target then 
     print("Target found at:", idx) 
    end 
end 
-1

Wszyscy ludzie sugerują mniej optymalną metodę

będzie najlepiej:

function chars(str) 
     strc = {} 
     for i = 1, #str do 
      table.insert(strc, string.sub(str, i, i)) 
     end 
     return strc 
    end 

    str = "Hello world!" 
    char = chars(str) 
    print("Char 2: "..char[2]) -- prints the char 'e' 
    print("-------------------\n") 
    for i = 1, #str do -- testing printing all the chars 
     if (char[i] == " ") then 
      print("Char "..i..": [[space]]") 
     else 
      print("Char "..i..": "..char[i]) 
     end 
    end 
+0

"Mniej optymalny" do jakiego zadania? "Najlepszy" do jakiego zadania? –