8

いくつかの空白行を含む複数行の文字列が与えられた場合、空白行を含むLua の行を反復処理するにはどうすればよいですか?

local s = "foo\nbar\n\njim"
for line in magiclines(s) do
  print( line=="" and "(blank)" or line)
end
--> foo
--> bar
--> (blank)
--> jim

このコードには空白行が含まれていません。

for line in string.gmatch(s,'[^\r\n]+') do print(line) end
--> foo
--> bar
--> jim

このコードには余分な偽の空白行が含まれています。

for line in string.gmatch(s,"[^\r\n]*") do
  print( line=="" and "(blank)" or line)
end
--> foo
--> (blank)
--> bar
--> (blank)
--> (blank)
--> jim
--> (blank)
4

6 に答える 6

9

これを試して:

function magiclines(s)
        if s:sub(-1)~="\n" then s=s.."\n" end
        return s:gmatch("(.-)\n")
end
于 2013-10-12T01:40:41.280 に答える
4

lPeg私はphgと同時に書いていたようですので、ここに別の解決策があります。でも文法はもっときれいなので、まだあげます!

local lpeg = require "lpeg"
local C, V, P = lpeg.C, lpeg.V, lpeg.P

local g = P({ "S",
    S = (C(V("C")^0) * V("N"))^0 * C(V("C")^0),
    C = 1 - V("N"),
    N = P("\r\n") + "\n\r" + "\n" + "\r",
})

次のように使用します。

local test = "Foo\n\nBar\rfoo\r\n\n\n\rbar"
for k,v in pairs({g:match(test)}) do
    print(">", v);
end

またはprint(g:match(test))もちろん

于 2013-10-12T12:30:44.440 に答える
4

LPEGを利用したソリューションは次のとおりです。

local lpeg      = require "lpeg"
local lpegmatch = lpeg.match
local P, C      = lpeg.P, lpeg.C

local iterlines
do
  local eol  = P"\r\n" + P"\n\r" + P"\n" + P"\r"
  local line = (1 - eol)^0
  iterlines = function (str, f)
    local lines = ((line / f) * eol)^0 * (line / f)
    return lpegmatch (lines, str)
  end
end

得られるのは、反復子の代わりに使用できる関数です。最初の引数は繰り返したい文字列で、2 番目の引数は各マッチのアクションです:

--- print each line
iterlines ("foo\nbar\n\njim\n\r\r\nbaz\rfoo\n\nbuzz\n\n\n\n", print)

--- count lines while printf
local n = 0
iterlines ("foo\nbar\nbaz", function (line)
  n = n + 1
  io.write (string.format ("[%2d][%s]\n", n, line))
end)
于 2013-10-12T12:13:26.850 に答える
3

このmagiclines実装があなたの法案に合っているかどうかを確認してください。

local function magiclines( str )
    local pos = 1;
    return function()
        if not pos then return nil end
        local  p1, p2 = string.find( str, "\r?\n", pos )
        local line
        if p1 then
            line = str:sub( pos, p1 - 1 )
            pos = p2 + 1
        else
            line = str:sub( pos )
            pos = nil
        end
        return line
    end
end

次のコードでテストできます。

local text = [[
foo
bar

jim

woof
]]


for line in magiclines( text ) do
    print( line=="" and "(blank)" or line)
end

出力:

ふー
バー
(空欄)
ジム
(空欄)
横糸
(空欄)
于 2013-10-11T20:59:57.130 に答える
2

次のパターンは、空白行を含む各行と一致する必要がありますが、注意点が 1 つありCRますLF

local s = "foo\nbar\n\njim\n" -- added terminating \n

for line in s:gmatch("([^\r\n]*)[\r\n]") do
   print(line == "" and "(blank)" or line)
end

--> foo
--> bar
--> (blank)
--> jim

末尾を必要としない、CRまたはLF最後の行として空白行を生成する代替パターン (何もキャプチャしないことが許容されるため)。

local s = "foo\nbar\n\njim"

for line in s:gmatch("([^\r\n]*)[\r\n]?") do
   print(line == "" and "(blank)" or line)
end

--> foo
--> bar
--> (blank)
--> jim
--> (blank)
于 2013-10-11T21:42:55.850 に答える
-1

少し最適化された@lhfの答え:

function magiclines(s)
    return s:gmatch("(.-)$")
end
于 2019-11-14T11:02:30.517 に答える