Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterate over lines including blank lines

Given a multiline string with some blank lines, how can I iterate over lines in Lua including the blank lines?

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

This code does not include blank lines:

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

This code includes extra spurious blank lines:

for line in string.gmatch(s,"[^\r\n]*") do
  print( line=="" and "(blank)" or line)
end
--> foo
--> (blank)
--> bar
--> (blank)
--> (blank)
--> jim
--> (blank)
like image 438
Phrogz Avatar asked Oct 11 '13 20:10

Phrogz


People also ask

How do you grep for blank lines?

To match empty lines, use the pattern ' ^$ '. To match blank lines, use the pattern ' ^[[:blank:]]*$ '. To match no lines at all, use the command ' grep -f /dev/null '.

How do I ignore an empty line in Linux?

“^$” will match with all free spaces in the text or blank lines. The output shows the complete removal of extra space between the lines present in the data file. In this example, we have seen that in the command that ”^#” comes first, which means the text is matched first.

How do you skip blank lines in Python?

In Python 2 use itertools. ifilter if you want a generator and in Python 3, just pass the whole thing to list if you want a list. +1 for nonblank_lines function. This should be first.

How do you check for blank lines in Python?

To check an empty string in Python, use the len() function; if it returns 0, that means the string is empty; otherwise, it is not. So, if the string has something, it will count as a non-empty string; otherwise, it is an empty string.


4 Answers

Try this:

function magiclines(s)
        if s:sub(-1)~="\n" then s=s.."\n" end
        return s:gmatch("(.-)\n")
end
like image 52
lhf Avatar answered Oct 31 '22 23:10

lhf


Here’s a solution utilizing 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

What you get is a function that can be used in place of an iterator. Its first argument is the string you want to iterate, the second is the action for each match:

--- 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)
like image 45
Philipp Gesang Avatar answered Oct 31 '22 23:10

Philipp Gesang


Here is another lPeg solution because it seems I was writing it at the same time as phg. But since grammars are prettier, I'll still give it to you!

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",
})

Use it like this:

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

Or just print(g:match(test)) of course

like image 39
dualed Avatar answered Nov 01 '22 01:11

dualed


See if this magiclines implementation suits your bill:

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

You can test it with the following code:

local text = [[
foo
bar

jim

woof
]]


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

Output:

foo
bar
(blank)
jim
(blank)
woof
(blank)
like image 44
Lorenzo Donati -- Codidact.com Avatar answered Nov 01 '22 01:11

Lorenzo Donati -- Codidact.com