Home Ask Login Register

Developers Planet

Your answer is one click away!

Quiloos39 February 2016

Lua string pattern

Here is my code:

local code = [[
    local a = 1

    local b = 2

local y = 0

for Paragraph in string.gmatch(code,"[^\n]+") do
    for Word in string.gmatch(Paragraph, "[^ ]+") do        

    y = y + 1

The problem is pattern doesn't recognize my empty paragraphs how can i fix this ?

If you run the code you will what i mean

Output is:

local a = 1
local b = 2

Instead it should be:

local a = 1
local b = 2


EinsteinK February 2016

This should do the trick:

local y,code = 0,[[

local a = 123

local b = 456

local c = "too much newlines because we're cool"

local i = 1
-- Why would you start with newlines? Oh well
local sigh = code:match("\n+")
y = y + #sigh
-- debug printing of newlines
for i=1,y do print() end
while true do
    local start,stop = code:find("[^\n]+",i)
    if not start then break end
    local Paragraph = code:sub(start,stop)

    -- Do your Paragraph parsing and stuff

    start,stop = code:find("\n+",stop+1)
    if not stop then break end
    y,i = y + stop - start + 1,stop+1
    -- printing newlines to get the desired effect in output
    for i=2,stop-start+1 do print() end
    -- starting from 2 since the print(code:sub(...)) already prints one \n
-- reached end of the string

It gives you this nice output:

PARAGRAPH:      local a = 123

PARAGRAPH:      local b = 456

PARAGRAPH:      local c = "too much newlines because we're cool"

Tested at http://www.lua.org/cgi-bin/demo

Piglet February 2016

You don't get the empty line because you look for the complement of \n. If you only have \n in your line, there is no complement and you get no match.

You could use this pattern: "[^\n]*\n?" to get what you want. This pattern matches any line. So everything or nothing that is not a \n which is followed by 0 or 1 instances of \n

Nick Gammon February 2016

Instead it should be:

    local a = 1

You won't get that first space because Lua long strings discard the first newline.

Your problem is that your match on "[^\n]+" matches at least one character which is not a newline. An empty line won't match (there are no characters between the newlines) and thus they don't get shown.

Now you can change that to "[^\n]*" like this:

for Paragraph in string.gmatch(code,"[^\n]*") do
    print("Line=", Paragraph)
    for Word in string.gmatch(Paragraph, "[^ ]+") do        
      print ("Word=", Word)

But that has a different problem:

Line=     local a = 1
Word= local
Word= a
Word= =
Word= 1
Line=     local b = 2
Word= local
Word= b
Word= =
Word= 2

Blank lines appear twice!

A handy function for iterating through a string, a line at a time, is this:

function getlines (str)

  local pos = 0

  -- the for loop calls this for every iteration
  -- returning nil terminates the loop
  local function iterator (s)

    if not pos then
      return nil
    end -- end of string, exit loop

    local oldpos = pos + 1  -- step past previous newline
    pos = string.find (s, "\n", oldpos) -- find next newline

    if not pos then  -- no more newlines, return rest of string
      return string.sub (s, oldpos)
    end -- no newline

    return string.sub (s, oldpos, pos - 1)

  end -- iterator

  return iterator, str
end -- getlines

That handles empty lines. Now you can write your code like this (assuming the function above precedes your code):

for Paragraph in getlines (code) do
    print("Line=", Paragraph)
    for Word in string.gmatch(Paragraph, "[^ ]+") do        
      print ("Word=", Word)



Post Status

Asked in February 2016
Viewed 3,448 times
Voted 4
Answered 3 times


Leave an answer

Quote of the day: live life