4

Let's say I have lines of the form:

int[4] height
char c
char[50] userName 
char[50+foo("bar")] userSchool 

As you see, the bracketed expression is optional.

Can I parse these strings using Lua's string.match() ?

The following pattern works for lines that contain brackets:

line = "int[4] height"
print(line:match('^(%w+)(%b[])%s+(%w+)$'))

But is there a pattern that can handle also the optional brackets? The following does not work:

line = "char c"
print(line:match('^(%w+)(%b[]?)%s+(%w+)$'))

Can the pattern be written in another way to solve this?

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
Niccolo M.
  • 3,363
  • 2
  • 22
  • 39

2 Answers2

4

Unlike regular expressions, ? in Lua pattern matches a single character.

You can use the or operator to do the job like this:

line:match('^(%w+)(%b[])%s+(%w+)$') or line:match('^(%w+)%s+(%w+)$')

A little problem with it is that Lua only keeps the first result in an expression. It depends on your needs, use an if statement or you can give the entire string the first capture like this

print(line:match('^((%w+)(%b[])%s+(%w+))$') or line:match('^((%w+)%s+(%w+))$'))
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • Thanks. I know about this solution, of calling `match()` twice. The problem is that I actually need to alter the string (`gsub()`, not `match()`; I left it out of the question for simplicity's sake) and I don't want the second call to gsub() to see the changes made by the first. – Niccolo M. Dec 18 '13 at 09:37
  • @NiccoloM. Why not ask a new question about using `string.gsub` to solve your original problem? – Yu Hao Dec 19 '13 at 07:32
3

LPeg may be more appropriate for your case, especially if you plan to expand your grammar.

local re = require're'

local p = re.compile( [[
    prog <- stmt* -> set
    stmt <- S { type } S { name }
    type <- name bexp ?
    bexp <- '[' ([^][] / bexp)* ']'
    name <- %w+
    S    <- %s*
]], {set = function(...)
    local t, args = {}, {...}
    for i=1, #args, 2 do t[args[i+1]] = args[i] end
    return t
end})

local s = [[
int[4] height
char c
char[50] userName
char[50+foo("bar")] userSchool
]]

for k, v in pairs(p:match(s)) do print(k .. ' = ' .. v) end

--[[
c = char
userSchool = char[50+foo("bar")]
height = int[4]
userName = char[50]
--]]
Ryan Stein
  • 7,930
  • 3
  • 24
  • 38