แยกสตริงใน Lua หรือไม่


160

ฉันต้องแยกสตริงอย่างง่าย ๆ แต่ดูเหมือนจะไม่มีฟังก์ชั่นสำหรับเรื่องนี้และวิธีที่ฉันทดสอบด้วยตนเองดูเหมือนจะไม่ทำงาน ฉันจะทำอย่างไร


โปรดดูSplitting Strings
Andrew Hare

คำตอบ:


96

นี่คือทางออกที่ง่ายจริงๆของฉัน ใช้ฟังก์ชั่น gmatch เพื่อสตริงการจับภาพที่มีอย่างน้อยหนึ่งตัวละครอะไรอื่นที่ไม่ใช่ตัวคั่นที่ต้องการ ตัวคั่นคือ ** whitespace ใด ๆ (% 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
ขอบคุณ เพียงแค่สิ่งที่ผมกำลังมองหา
Nicholas

3
ว้าวคำตอบแรกของคำถามนี้ทั้งหมดที่มีฟังก์ชั่นที่ส่งกลับตาราง โปรดทราบว่า t และฉันต้องการตัวแก้ไข "local" เนื่องจากคุณกำลังเขียนทับ globals :)
cib

3
คุณสามารถทำให้สิ่งนี้ง่ายขึ้นโดยใช้ table.insert (t, str) แทน t [i] = str จากนั้นคุณไม่ต้องการ i = 1 หรือ i = i +1
James Newton

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 อื่น ๆ : สิ่งนี้จะส่งคืนตัววนซ้ำและ 'ระหว่างรูปแบบ' จะรวมจุดเริ่มต้นและจุดสิ้นสุดของสตริง (ในฐานะที่เป็นมือใหม่ฉันต้องลองคิดดูว่าสิ่งเหล่านี้เป็นอย่างไร)
Darius Bacon

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ฟังก์ชั่นการทำงานเป็น iterator 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 รหัสที่ได้รับใบอนุญาตภายใต้v2 GPL ฉันได้เปลี่ยนชื่อตัวแปรและเพิ่มความคิดเห็นเพื่อให้โค้ดเข้าใจง่ายขึ้นและฉันได้เปลี่ยนรหัสเพื่อใช้รูปแบบสตริง 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


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

นี่เป็นปัญหาใหญ่ของฉันเช่นกัน วิธีนี้ใช้งานได้ดีกับตัวละครเวทมนต์คนดี
Andrew White

1

คุณสามารถใช้ไลบรารี่ไลบรารี่ นี่มีฟังก์ชั่นสำหรับการแยกสตริงโดยใช้ตัวคั่นซึ่งแสดงรายการผลลัพธ์

มันใช้งานฟังก์ชั่นมากมายที่เราอาจต้องใช้ในขณะที่เขียนโปรแกรมและขาดหายไปใน 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 คุณโชคไม่ดีที่นี่ Lua เป็นภาษาโปรแกรมหนึ่งที่เพิ่งเกิดขึ้นกับความอับอายขายหน้าเพราะผู้เขียนไม่เคยใช้ "ฟังก์ชั่น" แยก "ในห้องสมุดมาตรฐานและเขียนคำอธิบายและแก้ตัวอ่อนแอ 16 ข้อแทนเพราะเหตุใดพวกเขาจึงไม่ทำ สลับกับตัวอย่างครึ่งการทำงานมากมายที่รับรองว่าจะทำงานได้เกือบทุกคน แต่แตกหักในมุมของคุณ นี่เป็นเพียงศิลปะของลัวะและทุกคนที่ลงโปรแกรมในลัวะก็สามารถฟันและย้ำตัวละครได้ มีโซลูชั่นจำนวนมากที่มีอยู่ซึ่งบางครั้งก็ดีกว่า แต่ก็ไม่มีทางแก้ปัญหาที่ดีกว่าอย่างน่าเชื่อถือ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.