2009-09-15 16 views
123

Necesito hacer una división simple de una cadena, pero no parece haber una función para esto, y la forma manual que probé no pareció funcionar. ¿Cómo lo haría?¿Cuerda partida en Lua?

Respuesta

76

Por favor, vea Splitting Strings:

Aquí varias maneras de dividir una cadena en una lista de subcadenas, rompiendo la cadena original en ocurrencias de algún separador (carácter, juego de caracteres, o patrón) Esto se llama comúnmente una función de división de cuerdas .

+2

Por desgracia, la página ha sido editado desde entonces (aunque es sobre el mismo tema), y el paso que usted cita no se produce en la página . Esta es la razón por la que es ideal para evitar respuestas de solo enlace, y realmente incluir información relevante en la respuesta misma. – ShreevatsaR

27

Si está dividiendo una cadena en Lua, debe probar los métodos string.gmatch() o string.sub(). Utilice el método string.sub() si conoce el índice en el que desea dividir la cadena, o use el string.gmatch() si analizará la cadena para encontrar la ubicación donde dividir la cadena.

Ejemplo utilizando string.gmatch() desde 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

"Tomé prestada" una implementación de esa página de lua-users gracias de todos modos – RCIX

10

Aquí es la función:

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 

llamar así:

list=split(string_to_split,pattern_to_match) 

por ejemplo:

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


Para más ir aquí:
http://lua-users.org/wiki/SplitJoin

14

Así como string.gmatch encontrará patrones en una cadena, esta función encontrará las cosas entre patrones:

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 

Por defecto devuelve lo que está separado por espacios en blanco.

+5

+1. Nota para cualquier otro principiante Lua: esto devuelve un iterador, y 'entre patrones' incluye el comienzo y el final de la cadena. (Como novato, tuve que intentarlo para resolver estas cosas.) –

22

Si lo que desea es iterar sobre las fichas, esto es bastante limpio:

line = "one, two and 3!" 

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

Salida:

uno,

dos

y

3!

Breve explicación: el patrón "[^% s] +" coincide con cada cadena no vacía entre los caracteres espaciales.

+0

El patrón '% S' es igual al que usted mencionó, ya que'% S' es la negación de '% s', como'% D' es la negación de '% d'. Además, '% w' es igual a' [A-Za-z0-9_] '(otros caracteres pueden ser compatibles según su configuración regional). –

4

Usted puede utilizar este método:

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

Aquí está mi solución muy simple. Use la función de coincidencia para capturar cadenas que contengan al menos UN carácter de CUALQUIER COSA que no sea el separador deseado. El separador es cualquier espacio en blanco (% s en Lua) por defecto:

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

Gracias. **Justo lo que estaba buscando. – Nicholas

+3

Guau, la primera respuesta en toda esta pregunta que en realidad tiene una función que devuelve una tabla. Sin embargo, tenga en cuenta que t y yo necesitamos el modificador "local", ya que está sobrescribiendo globales. :) – cib

+1

Esto funcionó. Es solo para delimitadores de caracteres individuales. Para dividir por cadenas, como etiquetas XML, cambie el patrón de coincidencia a "(.-) (" .. sep .. ")" en su lugar. Nota: si la cadena termina con sep, la última coincidencia fallará. Agregue una nueva línea o cualquier carácter al final de la cadena de entrada para solucionar esto. –

6

me gusta este breve solución

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

Este es mi favorito, ya que es muy corto y sencillo. No entiendo muy bien qué sucede, ¿podría alguien explicarme? – hexagonest

+1

Esto falla al usar punto como delimitador (o potencialmente cualquier otro carácter mágico de patrón) – TurboHz

5

Debido a que hay más de una manera de pelar un gato, aquí está mi enfoque:

Código:

#!/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 

salida: 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.

Explicación:

La función gmatch funciona como un repetidor, se obtiene todas las cadenas que coinciden con regex. El regex toma todos los caracteres hasta que encuentra un separador.

1

He utilizado los ejemplos anteriores para crear mi propia función. Pero la pieza que faltaba para mí escapaba automáticamente de los personajes mágicos.

Aquí es mi contribución:

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

Este fue mi gran problema también. Esto funciona muy bien con personajes mágicos, uno agradable –

0

Simplemente sentado en un delimitador

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

Muchas de estas respuestas sólo aceptan separadores de un solo carácter, o no se ocupan de casos extremos también (por ejemplo, separadores vacíos), así que pensé en ofrecer una solución más definitiva.

Éstos son dos funciones, gsplit y split, adaptado del code en el Scribunto MediaWiki extension, que se utiliza en wikis como Wikipedia. El código está licenciado bajo GPL v2. Cambié los nombres de las variables y agregué los comentarios para hacer que el código sea un poco más fácil de entender, y también he cambiado el código para usar patrones regulares de Lua en lugar de los patrones de Scribunto para cadenas Unicode. El código original tiene casos de prueba 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 

Algunos ejemplos de la función split en uso:

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