Chia chuỗi trong Lua?


160

Tôi cần thực hiện một phân chia đơn giản của một chuỗi, nhưng dường như không có chức năng nào cho việc này và cách thủ công mà tôi đã kiểm tra dường như không hoạt động. Làm thế nào tôi sẽ làm điều đó?


Câu trả lời:


96

Đây là giải pháp thực sự đơn giản của tôi. Sử dụng chức năng gmatch để chụp các chuỗi chứa ít nhất một ký tự của bất kỳ ký tự nào ngoài dấu phân cách mong muốn. Dấu phân cách là ** any * khoảng trắng (% s trong Lua) theo mặc định:

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
Cảm ơn. Chỉ là những gì tôi đang tìm kiếm.
Nicholas

3
Wow, câu trả lời đầu tiên trong toàn bộ câu hỏi này thực sự có chức năng trả về một bảng. Tuy nhiên, xin lưu ý rằng tôi và công cụ sửa đổi "cục bộ", vì bạn đang ghi đè lên toàn cầu. :)
cib

3
Như những người khác đã chỉ ra, bạn có thể đơn giản hóa điều này bằng cách sử dụng bảng.insert (t, str) thay vì t [i] = str và sau đó bạn không cần i = 1 hoặc i = i +1
James Newton

2
Không hoạt động nếu chuỗi chứa các giá trị trống, ví dụ: 'foo,,bar'. Bạn nhận được {'foo','bar'}thay vì{'foo', '', 'bar'}
andras

5
Đúng rồi. Phiên bản tiếp theo sẽ hoạt động trong trường hợp đó: 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

Nếu bạn đang tách một chuỗi trong Lua, bạn nên thử các phương thức string.gmatch () hoặc string.sub (). Sử dụng phương thức string.sub () nếu bạn biết chỉ mục bạn muốn tách chuỗi tại hoặc sử dụng chuỗi.gmatch () nếu bạn sẽ phân tích chuỗi để tìm vị trí để phân tách chuỗi tại.

Ví dụ sử dụng string.gmatch () từ Tài liệu tham khảo Lua 5.1 :

 t = {}
 s = "from=world, to=Lua"
 for k, v in string.gmatch(s, "(%w+)=(%w+)") do
   t[k] = v
 end

Dù sao tôi cũng đã "mượn" một trang thực hiện từ trang lua-users đó
RCIX

24

Nếu bạn chỉ muốn lặp lại các mã thông báo, thì điều này khá gọn gàng:

line = "one, two and 3!"

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

Đầu ra:

một,

hai

3!

Giải thích ngắn: mẫu "[^% s] +" khớp với mọi chuỗi không trống ở giữa các ký tự khoảng trắng.


2
Mẫu %Stương đương với mẫu bạn đã đề cập, cũng như %Sphủ định %s, giống như %Dphủ định %d. Ngoài ra, %wbằng [A-Za-z0-9_](các ký tự khác có thể được hỗ trợ tùy thuộc vào ngôn ngữ của bạn).
Lars Gyrup Brink Nielsen

14

Cũng như string.gmatchsẽ tìm thấy các mẫu trong một chuỗi, hàm này sẽ tìm thấy những thứ giữa các mẫu:

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

Theo mặc định, nó trả về bất cứ thứ gì được phân tách bằng khoảng trắng.


6
+1. Lưu ý cho bất kỳ người mới bắt đầu Lua nào khác: điều này trả về một trình vòng lặp và 'giữa các mẫu' bao gồm phần đầu và phần cuối của chuỗi. (Là một người mới, tôi đã phải thử nó để tìm ra những điều này.)
Darius Bacon

12

Đây là chức năng:

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

Gọi nó như:

list=split(string_to_split,pattern_to_match)

ví dụ:

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


Để biết thêm chi tiết tại đây:
http://lua-users.org/wiki/SplitJoin


7

Tôi thích giải pháp ngắn này

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

Đây là sở thích của tôi, vì nó rất ngắn và đơn giản. Tôi không hiểu chuyện gì xảy ra, ai đó có thể giải thích cho tôi không?
hexagonest

2
Điều này không thành công khi sử dụng dấu chấm làm dấu phân cách (hoặc có khả năng là bất kỳ nhân vật ma thuật mẫu nào khác)
TurboHz

6

Bởi vì có nhiều hơn một cách để lột da một con mèo, đây là cách tiếp cận của tôi:

Mã số :

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

Đầu ra : 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.

Giải thích :

Các gmatchchức năng hoạt động như một iterator, rồi nó lấy tất cả các chuỗi trận đấu regex. Việc regexlấy tất cả các ký tự cho đến khi nó tìm thấy một dấu phân cách.


5

Bạn có thể sử dụng phương pháp này:

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

Rất nhiều câu trả lời trong số này chỉ chấp nhận các dấu phân cách một ký tự hoặc không xử lý tốt các trường hợp cạnh (ví dụ: các dấu tách trống), vì vậy tôi nghĩ rằng tôi sẽ cung cấp một giải pháp dứt khoát hơn.

Đây là hai chức năng gsplitsplitđược điều chỉnh từ trong phần mở rộng Scribunto MediaWiki , được sử dụng trên các wiki như Wikipedia. Mã được cấp phép theo GPL v2 . Tôi đã thay đổi tên biến và thêm nhận xét để làm cho mã dễ hiểu hơn một chút và tôi cũng đã thay đổi mã để sử dụng các mẫu chuỗi Lua thông thường thay vì các mẫu của Scribunto cho chuỗi Unicode. Mã ban đầu có các trường hợp thử nghiệm ở đây .

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

Một số ví dụ về splitchức năng được sử dụng:

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

một cách không nhìn thấy ở người khác

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

Chỉ đơn giản là ngồi trên một dấu phân cách

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

3

Tôi đã sử dụng các ví dụ trên để chế tạo chức năng của riêng tôi. Nhưng mảnh còn thiếu đối với tôi đã tự động thoát khỏi các nhân vật ma thuật.

Đây là đóng góp của tôi:

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

Đây cũng là vấn đề lớn của tôi. Điều này hoạt động tuyệt vời với các nhân vật ma thuật, một nhân vật tuyệt vời
Andrew White

1

Bạn có thể sử dụng thư viện penlight . Điều này có chức năng phân tách chuỗi bằng cách sử dụng dấu phân cách mà danh sách đầu ra.

Nó đã thực hiện nhiều chức năng mà chúng ta có thể cần trong khi lập trình và thiếu trong Lua.

Đây là mẫu để sử dụng nó.

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

0

Tùy thuộc vào trường hợp sử dụng, điều này có thể hữu ích. Nó cắt tất cả văn bản ở hai bên của các cờ:

b = "This is a string used for testing"

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

print (c)

Đầu ra:

string

0

Rất muộn cho câu hỏi này, nhưng trong trường hợp bất cứ ai cũng muốn một phiên bản xử lý số lượng chia tách bạn muốn nhận .....

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

Nếu bạn lập trình ở Lua, bạn sẽ hết may mắn ở đây. Lua là ngôn ngữ lập trình nổi tiếng khét tiếng bởi vì các tác giả của nó không bao giờ thực hiện "chức năng phân tách" trong thư viện tiêu chuẩn, và thay vào đó đã viết 16 màn hình giải thích và lý do khập khiễng về lý do tại sao họ không và sẽ không, xen kẽ với nhiều ví dụ nửa hoạt động gần như được đảm bảo để làm việc cho hầu hết mọi người nhưng phá vỡ trong trường hợp góc của bạn . Đây chỉ là trạng thái nghệ thuật của Lua và tất cả những người lập trình ở Lua chỉ đơn giản là nghiến răng và lặp đi lặp lại qua các nhân vật. Có rất nhiều giải pháp tồn tại đôi khi tốt hơn, nhưng chính xác là không có giải pháp nào tốt hơn đáng tin cậy .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.