Розділити рядок у Луї?


160

Мені потрібно зробити простий розбиття рядка, але це не здається функцією для цього, і ручний спосіб, який я протестував, здавалося, не працює. Як би я це зробив?


Будь ласка, дивіться Розщеплення струн
Ендрю Заєць

Відповіді:


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
Вау, перша відповідь у всьому цьому питанні, яка насправді має функцію, яка повертає таблицю. Зауважте, що мені потрібен "локальний" модифікатор, оскільки ви перезаписуєте глобальні точки. :)
cib

3
Як зазначали інші, ви можете спростити це, використовуючи table.insert (t, str) замість t [i] = str, і тоді вам не потрібно i = 1 або i = i +1
Джеймс Ньютон,

2
Не працює, якщо рядок містить порожні значення, наприклад. 'foo,,bar'. Ви отримаєте {'foo','bar'}замість{'foo', '', 'bar'}
andras

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
барт

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

Я "запозичив" реалізацію на цій сторінці користувачів lua завдяки будь-якому випадку
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_](інші символи можуть підтримуватися залежно від вашої мови).
Lars Gyrup Brink Nielsen

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

Це мій улюблений, оскільки він такий короткий і простий. Я не зовсім розумію, що трапляється, може хтось мені пояснить?
шестикутник

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) 

5

Багато з цих відповідей приймають лише розділові символи або не справляються з кращими справами (наприклад, порожні роздільники), тому я подумав, що запропоную більш чітке рішення.

Ось дві функції, gsplitіsplit , адаптовані з коду в розширенні Scribunto MediaWiki , який використовується на вікі, як Wikipedia. Код ліцензований відповідно до 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

Це було і моє велике питання. Це чудово працює з магічними персонажами, приємний
Ендрю Уайт

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

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 - Єдина мова програмування, яка, як відомо, є сумно відомою, оскільки її автори ніколи не реалізовували "розділену" функцію в стандартній бібліотеці, а натомість написали 16 скриншотів пояснень та кульгавих виправдань, чому вони цього не зробили, а що ні, переплетені з численними напівробочими прикладами, які практично гарантовано працюють майже для всіх, але впадають у ваш кутовий випадок. Це просто сучасний стан Луа, і кожен, хто програмує в Луї, просто закінчує стискати зуби і перебирати символи. Існує безліч рішень, які часом кращі, але точно нульові рішення, які надійно кращі.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.