2009-09-15 2 views
123

Мне нужно сделать простое разделение строки, но для этого не существует функции, и ручной метод, который я тестировал, не работает. Как мне это сделать?Сплит-струна в Луа?

ответ

76

Пожалуйста см Splitting Strings:

Здесь находятся различные способы расщепления строку в список подстрок, нарушающих исходную строку на вхождений некоторого сепаратор (символы, набора символов или шаблона). Обычно это называется функцией разделения строк [2] .

+2

К сожалению, страница была отредактирована с тех пор (хотя это на одной и той же теме), и прохождение цитируете не происходит на странице , Вот почему это идеальное решение, чтобы избежать ответов только на ссылки и фактически включать соответствующую информацию в сам ответ. – ShreevatsaR

27

Если вы разделили строку в Lua, вы должны попробовать методы string.gmatch() или string.sub(). Используйте метод string.sub(), если вам известен индекс, который вы хотите разбить на строку, или используйте string.gmatch(), если вы проанализируете строку, чтобы найти местоположение для разделения строки на.

Пример использования string.gmatch() из 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

Я «заимствовал» реализацию с этой страницы lua-users спасибо в любом случае – RCIX

10

Вот функция:

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 

Называйте это нравится:

list=split(string_to_split,pattern_to_match) 

например:

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


Для больше идти здесь:
http://lua-users.org/wiki/SplitJoin

14

Подобно тому, как string.gmatch найти паттерны в строке, эта функция будет найти вещи между узорами:

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 

По умолчанию это возвращает все, что разделено пробелами.

+5

+1. Обратите внимание на других начинающих Lua: это возвращает итератор, а «между шаблонами» включает начало и конец строки. (Как новичок, я должен был попытаться понять это.) –

22

Если вы просто хотите перебрать лексемы, это довольно опрятно:

line = "one, two and 3!" 

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

Выход:

один,

два

и

3!

Краткое описание: шаблон «[^% s] +» соответствует каждой непустой строке между символами пробела.

+0

Образец '% S' равен тому, который вы упомянули, так как'% S' является отрицанием '% s', например'% D' является отрицанием '% d'. Кроме того, '% w' равно' [A-Za-z0-9_] '(другие символы могут поддерживаться в зависимости от вашей локали). –

4

Вы можете использовать этот метод:

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

Вот мой очень простое решение. Используйте функцию gmatch для захвата строк, которые содержат по крайней мере один символ НИЧЕГО, кроме желаемого разделителя. Сепаратор пробельный (% s в Lua) по умолчанию:

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

Спасибо. ** Просто **, что я искал. – Nicholas

+3

Вау, первый ответ во всем этом вопросе, который фактически имеет функцию, возвращающую таблицу. Обратите внимание, что мне нужен и «локальный» модификатор, так как это вы переписываете глобальные переменные. :) – cib

+1

Это сработало. Это просто для одиночных разделителей символов. Чтобы разделить на строки, например теги XML, измените шаблон соответствия на «(.-) (« .. sep .. »)». Примечание. Если строка заканчивается на sep, последнее совпадение не будет выполнено. Чтобы исправить это, добавьте новую строку или любой символ в конец строки ввода. –

6

Мне нравится этот короткий Раствор

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

Это мой любимый, так как он настолько короткий и просто. Я не совсем понимаю, что происходит, может кто-нибудь объяснить мне? – hexagonest

+1

Это не удается при использовании точки в качестве разделителя (или, возможно, любого другого символа магии) – TurboHz

5

Потому что есть более чем один способ кожи кошки, вот мой подход:

Код:

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

Выход: 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.

Объяснение:

gmatch функция работает в качестве итератора, она извлекает все строки, которые соответствуют regex. regex принимает все символы, пока не найдет разделитель.

1

Я использовал приведенные выше примеры для создания собственной функции. Но недостающая часть для меня автоматически ускользала от волшебных персонажей.

Вот мой вклад:

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

Это была моя большая проблема. Это отлично работает с волшебными персонажами, красивыми –

0

Просто сидит на разделителе

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

Многих из этих ответов смиритесь сепараторами односимвольных, или не иметь дело с крайними случаями хорошо (например, пустые разделители), поэтому я подумал, что дам более решительное решение.

Вот две функции, gsplit и split, адаптированные из code в Scribunto MediaWiki extension, который используется на вики как Википедия. Код лицензируется по лицензии GPL v2. Я изменил имена переменных и добавил комментарии, чтобы сделать код немного понятным, и я также изменил код, чтобы использовать обычные строковые шаблоны Lua вместо шаблонов Scribunto для строк Unicode. Исходный код имеет тестовые примеры 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 

Некоторые примеры функции split в использовании:

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