En lua 5.1, puede iterar los caracteres de una cadena de varias formas.
El bucle básico sería:
para i = 1, #str do
local c = str: sub (i, i)
- haz algo con c
fin
Pero puede ser más eficiente usar un patrón con string.gmatch()
para obtener un iterador sobre los caracteres:
para c en str: gmatch "." hacer
- haz algo con c
fin
O incluso para usar string.gsub()
para llamar a una función para cada carácter:
str: gsub (".", función (c)
- haz algo con c
fin)
En todo lo anterior, aproveché el hecho de que el string
módulo está configurado como una metatabla para todos los valores de cadena, por lo que sus funciones se pueden llamar como miembros usando la :
notación. También he usado (nuevo en 5.1, IIRC) #
para obtener la longitud de la cadena.
La mejor respuesta para su aplicación depende de muchos factores, y los puntos de referencia son sus amigos si el rendimiento va a importar.
Es posible que desee evaluar por qué necesita iterar sobre los caracteres y mirar uno de los módulos de expresión regular que se han vinculado a Lua, o para un enfoque moderno, busque en el módulo lpeg de Roberto que implementa Parsing Expression Grammers para Lua.
Si está utilizando Lua 5, intente:
for i = 1, string.len(str) do print( string.sub(str, i, i) ) end
fuente
Dependiendo de la tarea en cuestión, podría ser más fácil de usar
string.byte
. También es la forma más rápida porque evita la creación de una nueva subcadena que resulta ser bastante cara en Lua gracias al hash de cada nueva cadena y al comprobar si ya se conoce. Puede calcular previamente el código de los símbolos que busca con el mismostring.byte
para mantener la legibilidad y la portabilidad.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
fuente
Ya hay muchos buenos enfoques en las respuestas proporcionadas ( aquí , aquí y aquí ). Si la velocidad es lo que busca principalmente , definitivamente debería considerar hacer el trabajo a través de la API C de Lua, que es muchas veces más rápida que el código Lua sin formato. Cuando se trabaja con fragmentos precargados (por ejemplo , función de carga ), la diferencia no es tan grande, pero sigue siendo considerable.
En cuanto a las soluciones Lua puras , permítanme compartirles este pequeño punto de referencia que hice. Cubre todas las respuestas proporcionadas hasta esta fecha y agrega algunas optimizaciones. Aún así, lo básico a considerar es:
¿Cuántas veces necesitará iterar sobre caracteres en una cadena?
Aquí está el código completo:
-- Setup locals local str = "Hello World!" local attempts = 5000000 local reuses = 10 -- For the second part of benchmark: Table values are reused 10 times. Change this according to your needs. local x, c, elapsed, tbl -- "Localize" funcs to minimize lookup overhead local stringbyte, stringchar, stringsub, stringgsub, stringgmatch = string.byte, string.char, string.sub, string.gsub, string.gmatch print("-----------------------") print("Raw speed:") print("-----------------------") -- Version 1 - string.sub in loop x = os.clock() for j = 1, attempts do for i = 1, #str do c = stringsub(str, i) end end elapsed = os.clock() - x print(string.format("V1: elapsed time: %.3f", elapsed)) -- Version 2 - string.gmatch loop x = os.clock() for j = 1, attempts do for c in stringgmatch(str, ".") do end end elapsed = os.clock() - x print(string.format("V2: elapsed time: %.3f", elapsed)) -- Version 3 - string.gsub callback x = os.clock() for j = 1, attempts do stringgsub(str, ".", function(c) end) end elapsed = os.clock() - x print(string.format("V3: elapsed time: %.3f", elapsed)) -- For version 4 local str2table = function(str) local ret = {} for i = 1, #str do ret[i] = stringsub(str, i) -- Note: This is a lot faster than using table.insert end return ret end -- Version 4 - function str2table x = os.clock() for j = 1, attempts do tbl = str2table(str) for i = 1, #tbl do -- Note: This type of loop is a lot faster than "pairs" loop. c = tbl[i] end end elapsed = os.clock() - x print(string.format("V4: elapsed time: %.3f", elapsed)) -- Version 5 - string.byte x = os.clock() for j = 1, attempts do tbl = {stringbyte(str, 1, #str)} -- Note: This is about 15% faster than calling string.byte for every character. for i = 1, #tbl do c = tbl[i] -- Note: produces char codes instead of chars. end end elapsed = os.clock() - x print(string.format("V5: elapsed time: %.3f", elapsed)) -- Version 5b - string.byte + conversion back to chars x = os.clock() for j = 1, attempts do tbl = {stringbyte(str, 1, #str)} -- Note: This is about 15% faster than calling string.byte for every character. for i = 1, #tbl do c = stringchar(tbl[i]) end end elapsed = os.clock() - x print(string.format("V5b: elapsed time: %.3f", elapsed)) print("-----------------------") print("Creating cache table ("..reuses.." reuses):") print("-----------------------") -- Version 1 - string.sub in loop x = os.clock() for k = 1, attempts do tbl = {} for i = 1, #str do tbl[i] = stringsub(str, i) -- Note: This is a lot faster than using table.insert end for j = 1, reuses do for i = 1, #tbl do c = tbl[i] end end end elapsed = os.clock() - x print(string.format("V1: elapsed time: %.3f", elapsed)) -- Version 2 - string.gmatch loop x = os.clock() for k = 1, attempts do tbl = {} local tblc = 1 -- Note: This is faster than table.insert for c in stringgmatch(str, ".") do tbl[tblc] = c tblc = tblc + 1 end for j = 1, reuses do for i = 1, #tbl do c = tbl[i] end end end elapsed = os.clock() - x print(string.format("V2: elapsed time: %.3f", elapsed)) -- Version 3 - string.gsub callback x = os.clock() for k = 1, attempts do tbl = {} local tblc = 1 -- Note: This is faster than table.insert stringgsub(str, ".", function(c) tbl[tblc] = c tblc = tblc + 1 end) for j = 1, reuses do for i = 1, #tbl do c = tbl[i] end end end elapsed = os.clock() - x print(string.format("V3: elapsed time: %.3f", elapsed)) -- Version 4 - str2table func before loop x = os.clock() for k = 1, attempts do tbl = str2table(str) for j = 1, reuses do for i = 1, #tbl do -- Note: This type of loop is a lot faster than "pairs" loop. c = tbl[i] end end end elapsed = os.clock() - x print(string.format("V4: elapsed time: %.3f", elapsed)) -- Version 5 - string.byte to create table x = os.clock() for k = 1, attempts do tbl = {stringbyte(str,1,#str)} for j = 1, reuses do for i = 1, #tbl do c = tbl[i] end end end elapsed = os.clock() - x print(string.format("V5: elapsed time: %.3f", elapsed)) -- Version 5b - string.byte to create table + string.char loop to convert bytes to chars x = os.clock() for k = 1, attempts do tbl = {stringbyte(str, 1, #str)} for i = 1, #tbl do tbl[i] = stringchar(tbl[i]) end for j = 1, reuses do for i = 1, #tbl do c = tbl[i] end end end elapsed = os.clock() - x print(string.format("V5b: elapsed time: %.3f", elapsed))
Salida de ejemplo (Lua 5.3.4, Windows) :
----------------------- Raw speed: ----------------------- V1: elapsed time: 3.713 V2: elapsed time: 5.089 V3: elapsed time: 5.222 V4: elapsed time: 4.066 V5: elapsed time: 2.627 V5b: elapsed time: 3.627 ----------------------- Creating cache table (10 reuses): ----------------------- V1: elapsed time: 20.381 V2: elapsed time: 23.913 V3: elapsed time: 25.221 V4: elapsed time: 20.551 V5: elapsed time: 13.473 V5b: elapsed time: 18.046
Resultado:
En mi caso, los
string.byte
ystring.sub
fueron los más rápidos en términos de velocidad bruta. Al usar la tabla de caché y reutilizarla 10 veces por ciclo, lastring.byte
versión fue la más rápida incluso al convertir los códigos de caracteres de nuevo a caracteres (lo que no siempre es necesario y depende del uso).Como probablemente haya notado, hice algunas suposiciones basadas en mis puntos de referencia anteriores y las apliqué al código:
tbl[idx] = value
quetable.insert(tbl, value)
.for i = 1, #tbl
es un poco más rápido quefor k, v in pairs(tbl)
.Espero eso ayude.
fuente
Todas las personas sugieren un método menos óptimo.
Será mejor:
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
fuente
Iterando para construir una cadena y devolviendo esta cadena como una tabla con load () ...
itab=function(char) local result for i=1,#char do if i==1 then result=string.format('%s','{') end result=result..string.format('\'%s\'',char:sub(i,i)) if i~=#char then result=result..string.format('%s',',') end if i==#char then result=result..string.format('%s','}') end end return load('return '..result)() end dump=function(dump) for key,value in pairs(dump) do io.write(string.format("%s=%s=%s\n",key,type(value),value)) end end res=itab('KOYAANISQATSI') dump(res)
Pone fuera...
1=string=K 2=string=O 3=string=Y 4=string=A 5=string=A 6=string=N 7=string=I 8=string=S 9=string=Q 10=string=A 11=string=T 12=string=S 13=string=I
fuente