Split string dalam Lua?


160

Saya perlu melakukan pemisahan sederhana dari string, tetapi sepertinya tidak ada fungsi untuk ini, dan cara manual yang saya uji sepertinya tidak berhasil. Bagaimana saya melakukannya?


Jawaban:


96

Inilah solusi saya yang sangat sederhana. Gunakan fungsi gmatch untuk menangkap string yang mengandung setidaknya satu karakter apapun selain pemisah yang diinginkan. Separator adalah ** any * spasi putih (% s dalam Lua) secara default:

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
Terima kasih. Apa yang saya cari.
Nicholas

3
Wow, jawaban pertama dalam seluruh pertanyaan ini yang sebenarnya memiliki fungsi yang mengembalikan tabel. Perhatikan bahwa, t dan saya memerlukan pengubah "lokal", karena Anda menimpa global. :)
cib

3
Seperti yang telah ditunjukkan orang lain, Anda dapat menyederhanakan ini dengan menggunakan table.insert (t, str) daripada t [i] = str dan kemudian Anda tidak perlu i = 1 atau i = i +1
James Newton

2
Tidak berfungsi jika string berisi nilai kosong, mis. 'foo,,bar'. Anda {'foo','bar'}bukannya{'foo', '', 'bar'}
andras

5
Betul sekali. Versi berikutnya akan berfungsi dalam hal ini: 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

Jika Anda memisahkan string dalam Lua, Anda harus mencoba metode string.gmatch () atau string.sub (). Gunakan metode string.sub () jika Anda tahu indeks yang ingin Anda pisahkan stringnya, atau gunakan string.gmatch () jika Anda akan menguraikan string untuk menemukan lokasi untuk membagi string di.

Contoh menggunakan string.gmatch () dari 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

Saya "meminjam" implementasi dari halaman lua-pengguna terima kasih
RCIX

24

Jika Anda hanya ingin mengulangi token, ini cukup rapi:

line = "one, two and 3!"

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

Keluaran:

satu,

dua

dan

3!

Penjelasan singkat: pola "[^% s] +" cocok dengan setiap string yang tidak kosong di antara karakter spasi.


2
Polanya %Ssama dengan yang Anda sebutkan, seperti %Snegasi %s, seperti %Dnegasi %d. Selain itu, %wsama dengan [A-Za-z0-9_](karakter lain mungkin didukung tergantung pada lokal Anda).
Lars Gyrup Brink Nielsen

14

Sama seperti string.gmatchakan menemukan pola dalam string, fungsi ini akan menemukan hal-hal di antara pola:

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

Secara default mengembalikan apa pun yang dipisahkan oleh spasi.


6
+1. Catatan untuk pemula Lua lainnya: ini mengembalikan iterator, dan 'antara pola' termasuk awal dan akhir string. (Sebagai seorang pemula, saya harus mencobanya untuk mencari tahu hal-hal ini.)
Darius Bacon

12

Inilah fungsinya:

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

Sebut saja seperti:

list=split(string_to_split,pattern_to_match)

misalnya:

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


Untuk lebih lanjut, buka di sini:
http://lua-users.org/wiki/SplitJoin


7

Saya suka solusi singkat ini

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

Ini adalah favorit saya, karena sangat pendek dan sederhana. Saya tidak mengerti apa yang terjadi, bisakah seseorang menjelaskan kepada saya?
segi enam

2
Ini gagal ketika menggunakan dot sebagai pembatas (atau berpotensi karakter sulap pola lainnya)
TurboHz

6

Karena ada lebih dari satu cara menguliti kucing, inilah pendekatan saya:

Kode :

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

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

Penjelasan :

The gmatchkarya berfungsi sebagai iterator, itu mengambil semua string yang cocok regex. Yang regexmengambil semua karakter sampai menemukan pemisah.


5

Anda dapat menggunakan metode ini:

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

Banyak jawaban ini hanya menerima pemisah satu karakter, atau tidak menangani kasus tepi dengan baik (misalnya pemisah kosong), jadi saya pikir saya akan memberikan solusi yang lebih pasti.

Berikut adalah dua fungsi, gsplitdan split, diadaptasi dari kode di ekstensi Scribunto MediaWiki , yang digunakan pada wiki seperti Wikipedia. Kode ini dilisensikan di bawah GPL v2 . Saya telah mengubah nama variabel dan menambahkan komentar untuk membuat kode sedikit lebih mudah dimengerti, dan saya juga mengubah kode untuk menggunakan pola string Lua biasa, bukan pola Scribunto untuk string Unicode. Kode asli memiliki kasus uji di sini .

-- 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

Beberapa contoh splitfungsi yang digunakan:

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

cara yang tidak terlihat pada orang lain

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

Cukup duduk di pembatas

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

3

Saya menggunakan contoh di atas untuk menyusun fungsi saya sendiri. Tetapi bagian yang hilang bagi saya secara otomatis keluar dari karakter sihir.

Ini kontribusi saya:

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

Ini juga masalah besar saya. Ini berfungsi baik dengan karakter sihir, bagus
Andrew White

1

Anda dapat menggunakan perpustakaan penalight . Ini memiliki fungsi untuk memisahkan string menggunakan pembatas yang menampilkan daftar.

Ini telah mengimplementasikan banyak fungsi yang mungkin kita perlukan saat pemrograman dan hilang di Lua.

Ini adalah contoh untuk menggunakannya.

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

0

Tergantung pada kasus penggunaan, ini bisa bermanfaat. Ini memotong semua teks di kedua sisi bendera:

b = "This is a string used for testing"

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

print (c)

Keluaran:

string

0

Sangat terlambat untuk pertanyaan ini, tetapi siapa tahu ada versi yang menangani jumlah pemisahan yang ingin Anda dapatkan .....

-- 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

Jika Anda memprogram di Lua, Anda kurang beruntung di sini. Lua adalah satu bahasa pemrograman yang terkenal terkenal karena pengarangnya tidak pernah mengimplementasikan fungsi pemisahan "" di perpustakaan standar, dan sebaliknya menulis 16 layar penuh penjelasan dan alasan lemah mengapa mereka tidak dan tidak mau, diselingi dengan banyak contoh setengah kerja yang hampir dijamin untuk bekerja untuk hampir semua orang tetapi tidak sesuai dengan keinginan Anda . Ini hanya seni Lua, dan semua orang yang memprogram dalam Lua hanya mengepalkan gigi mereka dan beralih ke karakter. Ada banyak solusi yang ada yang kadang-kadang lebih baik, tapi persis nol solusi yang andal baik.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.