Luaで文字列を分割しますか?


160

文字列を単純に分割する必要がありますが、このための関数はないようで、手動でテストした方法ではうまくいかないようです。どうすればいいですか?


回答:


96

これが私の本当に簡単な解決策です。少なくとも含む文字列キャプチャするgmatch機能を使用して1つの文字は何も希望区切り以外を。セパレーターは、デフォルトで**任意*の空白(Luaでは%s)です。

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とiには「ローカル」修飾子が必要です。:)
cib

3
他の人が指摘したように、t [i] = strの代わりにtable.insert(t、str)を使用することでこれを簡略化でき、i = 1やi = i +1は不要
James Newton

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
バート

33

Luaで文字列を分割する場合は、string.gmatch()またはstring.sub()メソッドを試してください。文字列を分割するインデックスがわかっている場合はstring.sub()メソッドを使用し、文字列を解析して文字列を分割する場所を見つける場合はstring.gmatch()を使用します。

Lua 5.1リファレンスマニュアルの string.gmatch()の使用例:

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

とにかく、そのlua-usersページから実装を「借りました」
RCIX

24

トークンを繰り返し処理したい場合は、これはかなり便利です。

line = "one, two and 3!"

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

出力:

1、

そして

3!

簡単な説明: "[^%s] +"パターンは、スペース文字の間の空でないすべての文字列に一致します。


2
パターン%S%S、の否定と%s同様に、あなたが言及したものと同じ%Dです%d。さらに、%wと等しい[A-Za-z0-9_](ロケールによっては、他の文字がサポートされる場合があります)。
Lars Gyrup Brink Nielsen、2014

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初心者への注意:これはイテレータを返し、「betweenパターン」には文字列の最初と最後が含まれます。(初心者として、私はこれらのことを理解するためにそれを試さなければなりませんでした。)
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

これはとても短くてシンプルなので、私のお気に入りです。何が起こるかよくわかりません。誰かに説明してもらえますか?
六角形2013年

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イテレータとしての機能の作品は、それが一致するすべての文字列を取り出しますregexregexそれは、セパレータを見つけるまで、すべての文字を取ります。


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

これらの回答の多くは単一文字のセパレーターしか受け入れないか、エッジのケース(たとえば空のセパレーター)を適切に処理しないため、より確実な解決策を提供すると思いました。

ここでは2つの機能があり、gsplitそしてsplit、から適応コードScribunto MediaWikiの拡張ウィキペディアのようなウィキで使用され、。コードはGPL v2の下でライセンスされてます。変数名を変更し、コメントを追加してコードを少しわかりやすくしました。また、Unicode文字列のScribuntoのパターンの代わりに通常のLua文字列パターンを使用するようにコードを変更しました。元のコードには、ここにテストケースがあります

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

これも私の大きな問題でした。これは魔法のキャラクターとうまく機能します。素敵なものです
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スクリーンフルの説明と、なぜそうしないのか、そうしないのかについての不完全な言い訳を書いたためです。ほぼすべての人のために動作することが実質的に保証されているが、あなたのコーナーケースで壊れる多数のハーフワーキングの例が点在しています。これは単なるLuaの最先端技術であり、Luaでプログラムする人は皆、歯を食いしばり、キャラクターを繰り返し処理するだけです。時にはより良いソリューションがたくさんありますが、確実に優れているソリューションはまったくありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.