Разделить строку в Lua?

160

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

RCIX
источник
Пожалуйста, смотрите разделение строк
Эндрю Харе

Ответы:

96

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

function mysplit (inputstr, sep)
        if sep == nil then
                sep = "%s"
        end
        local t={}
        for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
                table.insert(t, str)
        end
        return t
end

,

Адриан Моул
источник
1
Спасибо. Как раз то, что я искал.
Николай
3
Вау, первый ответ во всем этом вопросе, который на самом деле имеет функцию, которая возвращает таблицу. Обратите внимание, что t и мне нужен модификатор "local", так как вы перезаписываете глобальные переменные. :)
Cib
3
Как уже отмечали другие, вы можете упростить это, используя table.insert (t, str) вместо t [i] = str, и тогда вам не нужно i = 1 или i = i +1
Джеймс Ньютон,
2
Не работает, если строка содержит пустые значения, например. 'foo,,bar', Вы получаете {'foo','bar'}вместо{'foo', '', 'bar'}
Андрас
5
Это правильно. Следующая версия будет работать в этом случае: function split(inputstr, sep) sep=sep or '%s' local t={} for field,s in string.gmatch(inputstr, "([^"..sep.."]*)("..sep.."?)") do table.insert(t,field) if s=="" then return t end end end
Bart
33

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

Пример использования string.gmatch () из справочного руководства Lua 5.1 :

 t = {}
 s = "from=world, to=Lua"
 for k, v in string.gmatch(s, "(%w+)=(%w+)") do
   t[k] = v
 end
gwell
источник
В любом случае, я «позаимствовал» реализацию на этой странице lua-users
RCIX
24

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

line = "one, two and 3!"

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

Вывод:

один,

два

и

3!

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

Хьюго
источник
2
Образец %Sравен тому, который вы упомянули, как %Sи отрицание %s, как %Dи отрицание %d. Кроме того, %wравно [A-Za-z0-9_](другие символы могут поддерживаться в зависимости от вашей локали).
Ларс Гируп Бринк Нильсен
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

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

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

Вот функция:

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

Фейсал Ханиф
источник
7

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

function split(s, delimiter)
    result = {};
    for match in (s..delimiter):gmatch("(.-)"..delimiter) do
        table.insert(result, match);
    end
    return result;
end
Иво Беккерс
источник
Это мой любимый, потому что он такой короткий и простой. Я не совсем понимаю, что происходит, кто-то может мне объяснить?
hexagonest
2
Это не удается при использовании точки в качестве разделителя (или, возможно, любого другого магического персонажа)
TurboHz
6

Поскольку существует более одного способа снятия шкуры с кошки, вот мой подход:

Код :

#!/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принимает все символы, пока не найдет разделитель.

Диего Пино
источник
5

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

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) 
krsk9999
источник
5

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

Вот две функции, gsplitи split, адаптированная из кода в расширении Scribunto MediaWiki , который используется на вики как Википедия. Код распространяется по лицензии GPL v2 . Я изменил имена переменных и добавил комментарии, чтобы немного облегчить понимание кода, а также изменил код, чтобы использовать обычные строковые шаблоны Lua вместо шаблонов Scribunto для строк Unicode. Оригинальный код имеет тестовые случаи здесь .

-- 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
Джек Тейлор
источник
5

путь не виден в других

function str_split(str, sep)
    if sep == nil then
        sep = '%s'
    end 

    local res = {}
    local func = function(w)
        table.insert(res, w)
    end 

    string.gsub(str, '[^'..sep..']+', func)
    return res 
end
Хоэнхайм
источник
4

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

local str = 'one,two'
local regxEverythingExceptComma = '([^,]+)'
for x in string.gmatch(str, regxEverythingExceptComma) do
    print(x)
end
Джером Энтони
источник
3

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

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

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
intrepidhero
источник
Это было моей большой проблемой тоже. Это прекрасно работает с магическими персонажами, хороший
Эндрю Уайт
1

Вы можете использовать библиотеку Penlight . У этого есть функция для разделения строки, используя разделитель, который выводит список.

В нем реализованы многие функции, которые могут нам понадобиться при программировании и отсутствовать в Lua.

Вот пример для его использования.

> 
> stringx = require "pl.stringx"
> 
> str = "welcome to the world of lua"
> 
> arr = stringx.split(str, " ")
> 
> arr
{welcome,to,the,world,of,lua}
> 

источник
0

В зависимости от варианта использования это может быть полезно. Он обрезает весь текст по обе стороны от флагов:

b = "This is a string used for testing"

--Removes unwanted text
c = (b:match("a([^/]+)used"))

print (c)

Вывод:

string
greenage
источник
0

Супер поздно на этот вопрос, но в случае, если кто-то хочет версию, которая обрабатывает количество расколов, которые вы хотите получить .....

-- Split a string into a table using a delimiter and a limit
string.split = function(str, pat, limit)
  local t = {}
  local fpat = "(.-)" .. pat
  local last_end = 1
  local s, e, cap = str:find(fpat, 1)
  while s do
    if s ~= 1 or cap ~= "" then
      table.insert(t, cap)
    end

    last_end = e+1
    s, e, cap = str:find(fpat, last_end)

    if limit ~= nil and limit <= #t then
      break
    end
  end

  if last_end <= #str then
    cap = str:sub(last_end)
    table.insert(t, cap)
  end

  return t
end
Бенджамин Визон
источник
0

Если вы программируете на Lua, вам здесь не повезло. Lua - это единственный язык программирования, который просто печально известен своей печально известной репутацией, потому что его авторы никогда не реализовывали функцию «разделения» в стандартной библиотеке, а вместо этого написали 16 скриншотов с объяснениями и неубедительными оправданиями того, почему они этого не сделали и не будут вкраплен многочисленными полуработающими примерами, которые практически гарантированно сработают почти для всех, но не сработают в вашем угловом деле. Это просто уровень Lua, и каждый, кто программирует на Lua, просто сжимает зубы и перебирает персонажей. Существует множество решений, которые иногда лучше, но ровно нулевых решений, которые надежно лучше.

Щепан Холышевский
источник