5

I'm trying to learn how patterns (implemented in string.gmatch, etc.) do work in Lua 5.3, from the reference manual.

(Thanks @greatwolf for correcting my interpretation about the pattern item using *.)

What I'm trying to do is to match '(%(.*%))*' (substrings enclosed by ( and ); for example, '(grouped (etc))'), so that it logs

(grouped (etc))
(etc)

or

grouped (etc)
etc

But it does nothing (online compiler).

local test = '(grouped (etc))'

for sub in test:gmatch '(%(.*%))*' do
    print(sub)
end
  • Why do you write `*.` instead of `.*`? – Egor Skriptunoff Mar 11 '17 at 23:16
  • @EgorSkriptunoff I've wanted to match everything that is between ( and ), and by the manual, this is a pattern item, where a character class must be following \* (in this "following" term I understood, "declared after \*"). I think `.\*` ends up using the next character class (in the question example, `%`, at `%))`, same as `.*%`, I guess. –  Mar 11 '17 at 23:26
  • 1
    You're mistaken here, all those repetition characters `*`, `-`, `+` etc. comes *after* the char class you want to match. For example to match letters use `%a*`, `.*` will greedy match any character. Your example just uses `*` kleene star but nothing precedes it so it's not well-formed. – greatwolf Mar 11 '17 at 23:37
  • @greatwolf Thanks for the correction, English isn't my primary language, so I may noy read it properly. Though Portuguese is similiar sometimes! –  Mar 11 '17 at 23:39
  • For your example, you could try `%a+%s(%(.-%))`, which means match 1 or more letters(case insensitive) followed by optional space followed by any characters in `(` `)`. On match capture the stuff in the parenthesis. – greatwolf Mar 11 '17 at 23:43
  • @greatwolf I wasn't caring too much about the containing characters as it's a test, but thanks for the idea. Your example printed `(etc)`, just missed `(grouped (etc))` at first. (I've tried grouping the entire character classes into the pattern item *, but it did then nothing :/.) –  Mar 11 '17 at 23:52

3 Answers3

1

Another possibility -- using recursion:

function show(s)
  for s in s:gmatch '%b()' do
    print(s)
    show(s:sub(2,-2))
  end
end

show '(grouped (etc))'
tonypdmtr
  • 3,037
  • 2
  • 17
  • 29
0

I don't think you can do this with gmatch but using %b() along with the while loop may work:

local pos, _, sub = 0
while true do
  pos, _, sub  = ('(grouped (etc))'):find('(%b())', pos+1)
  if not sub then break end
  print(sub)
end

This prints your expected results for me.

Paul Kulchenko
  • 25,884
  • 3
  • 38
  • 56
  • Thanks for the idea, I've also did something like this while manipulating a little thing. I'm kinda confused why it'd not work with * :/ in gmatch(), however –  Mar 11 '17 at 22:47
0
local test = '(grouped (etc))'

print( test:match '.+%((.-)%)' )

Here:

. +%( catch the maximum number of characters until it %( ie until the last bracket including it, where %( just escapes the bracket.

(.-)%) will return your substring to the first escaped bracket %)

Mike V.
  • 2,077
  • 8
  • 19
  • Unfortunately it doesn't match `'grouped (etc)'` or `'(grouped (etc))'` :/, but thanks anyways (I've tried grouping it). Also, I've changed **.+** to **.\***. –  Mar 12 '17 at 12:19
  • why not, you need catch 'etc'? – Mike V. Mar 12 '17 at 12:24
  • I did want to match every group in the string (which would be a substring enclosed by **(** and **)**), even nested. My last try using your pattern along with `gmatch()` was `for sub in ('(grouped (etc))'):gmatch '.*%((.-)%)' do print(sub) end`, and when grouping the entire character classes into a pattern item **\*** it does nothing: `'(.*%((.-)%))*'`, and when just grouped without pattern items, it only prints exactly `'(grouped (etc)'`, but I don't care very much about the parenthesis as I'm learning (for keeping: `'(.*%((.*)%))'`). –  Mar 12 '17 at 12:35
  • show full example ( your text) please, then get a full answer – Mike V. Mar 12 '17 at 12:43
  • see [code online](http://www.tutorialspoint.com/execute_lua_online.php?PID=0Bw_CjBb95KQManFhY1c5dGlDRnc) , it that you need? – Mike V. Mar 12 '17 at 13:14
  • Near, but it's not inclusively printing `'grouped(etc1)'` (should print it because `'grouped(etc1)'` is enclosed by parenthesis). –  Mar 12 '17 at 13:33
  • may be all groups in [this example](http://www.tutorialspoint.com/execute_lua_online.php?PID=0Bw_CjBb95KQMSnNidmlsU2xSVlk) ? – Mike V. Mar 12 '17 at 13:55
  • Almost there, but it doesn't print >= 3rd inner-nested groups (i.e. `'(grouped(etc3(etc4))'`) (it doesn't print `'etc4'`). I'm having some troubles with different outputs, so I can't be exact... thus I'm trying to avoid **.+**. A group doesn't need to contain characters. –  Mar 12 '17 at 14:44
  • Thanks for the time anyways ! I think what I've wanted to do is not directly possible with only one pattern at `gmatch()` (but should be!), both of your answers were helpful –  Mar 12 '17 at 14:46
  • for etc4 and another recursive group [try this example](http://www.tutorialspoint.com/execute_lua_online.php?PID=0Bw_CjBb95KQMbUMyT05iWmkyQ3c) and with one gmatch I think it's impossible to do this ^-) – Mike V. Mar 12 '17 at 15:20