String 迭代行,包括空行 给出了一个带有多行空行的多行字符串,如何遍历Lua中的行,包括空行?< /P> local s=“foo\nbar\n\njim” magiclines(s)do中的行 打印(行==”和“(空白)”或行) 结束 -->福 -->酒吧 -->(空白) -->吉姆

String 迭代行,包括空行 给出了一个带有多行空行的多行字符串,如何遍历Lua中的行,包括空行?< /P> local s=“foo\nbar\n\njim” magiclines(s)do中的行 打印(行==”和“(空白)”或行) 结束 -->福 -->酒吧 -->(空白) -->吉姆,string,lua,string-matching,lua-patterns,String,Lua,String Matching,Lua Patterns,此代码不包括空行: 用于字符串中的行。gmatch,[^\r\n]+')是否打印(行)结束 -->福 -->酒吧 -->吉姆 此代码包括额外的伪空行: 用于字符串中的行。gmatch(“[^\r\n]*”)do 打印(行==”和“(空白)”或行) 结束 -->福 -->(空白) -->酒吧 -->(空白) -->(空白) -->吉姆 -->(空白) 查看此magiclines实施是否符合您的要求: local function magiclines( str ) local pos =

此代码不包括空行:

用于字符串中的行。gmatch,[^\r\n]+')是否打印(行)结束
-->福
-->酒吧
-->吉姆
此代码包括额外的伪空行:

用于字符串中的行。gmatch(“[^\r\n]*”)do
打印(行==”和“(空白)”或行)
结束
-->福
-->(空白)
-->酒吧
-->(空白)
-->(空白)
-->吉姆
-->(空白)

查看此
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
输出:

foo bar (blank) jim (blank) woof (blank) 福 酒吧 (空白) 吉姆 (空白) 汪汪 (空白)
以下模式应与包括空行在内的每一行匹配,但有一个警告:字符串必须包含终止的
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
的备用模式将生成一个空行作为最后一行(因为不捕获任何内容是可以接受的)

试试这个:

function magiclines(s)
        if s:sub(-1)~="\n" then s=s.."\n" end
        return s:gmatch("(.-)\n")
end

下面是一个利用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
您得到的是一个可以用来代替迭代器的函数。 它的第一个参数是要迭代的字符串,第二个参数是 是针对每个匹配的操作:

--- 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)
这里是另一个解决方案,因为它似乎是我写它的同时,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

或者只是打印(g:match(test))
当然

稍微优化一下@lhf的答案:

function magiclines(s)
    return s:gmatch("(.-)$")
end

现在匹配
\r
仅仅是一种形式,imho.
对于(s..'\n'):gmatch'(.-)\r?\n'do。。。结束
@hjpotter92有时这个字符会出现并把一切都搞砸。。。例如,一些控制台应用程序可能会给人一个惊喜:@dualed这是不明确的,我删除了这个句子。我指的是“循环体可能接受空字符串”错误。有没有可能重写模式,使其接受空行而无需解决方案?我遇到了这个错误,但我不确定您在那里做了什么,作为解决方案,您必须实际“捕获”它,否则我认为lpeg将丢弃它--请参阅我的解决方案:)@dualed在分析您的解决方案时,它发出了咔嗒声,现在解决办法已经不存在了。谢谢我知道你在那里做了什么。我一直在寻找
C()
capture,当然它也必须与函数capture一起工作……我喜欢这个解决方案
;-)
但我认为第一条规则应该是
S=(C(V(“C”)^0)*V(“N”)^0*C(V(“C”)^0),
,这样它就可以接受没有换行符的单行。顺便说一句,你不需要语法。是的,我认为你在第一行是对的。当然你不需要语法,但我认为它。。。写和读起来更方便——至少如果你习惯于阅读正式的语法定义的话。在任何情况下,lPeg中的“语法”只是用局部(甚至全局)变量编写相同内容的语法糖。优雅且是迭代器。完全正确
function magiclines(s)
    return s:gmatch("(.-)$")
end