It is currently October 1st, 2022, 7:53 am

Lua frontier pattern - undocumented feature

Tips and Tricks from the Rainmeter Community
User avatar
killall-q
Posts: 299
Joined: August 14th, 2009, 8:04 am

Lua frontier pattern - undocumented feature

Post by killall-q »

When doing pattern matching on strings in Lua (equivalent to regex captures in Rainmeter), the Lua 5.1 reference manual has always been my final authority on what I can and can't do.

However, I just discovered an incredibly useful undocumented pattern available in Lua 5.1: the frontier pattern.

I was trying to match elements in a CSV (comma-separated value) string, but I encountered difficulty matching elements at the beginning and end of the string.

Example: Check if "1" is an element in "5,12,13" or "1,2,3"

Code: Select all

local csv = '5,12,13'
local element = '1'
local hasElement = csv:find(element) ~= nil
This will return a false positive, because it will match the "1" in "12".

Ok, so let's match the delimiters to isolate the element.

Code: Select all

local csv = '1,2,3'
local element = '1'
local hasElement = csv:find(','..element..',') ~= nil
This will fail because there is no comma before "1".

Can we match commas OR the beginning/end of a string? With regex, we could do something like: (?:,|^)(1)(?:,|$)
Alas, alternation is not available in Lua patterns, and even if it was, ^ and $ only match the beginning/end of strings if they are at the beginning/end of a pattern.

A basic solution is to bookend the CSV with commas to eliminate edge cases.

Code: Select all

local csv = '1,2,3'
local element = '1'
local hasElement = (','..csv..','):find(','..element..',') ~= nil
I could have stopped here, but I found the bookending inelegant. Then, I discovered the frontier pattern.

Code: Select all

%f[%d]
This detects the transition between characters not in a set to characters in a set. The [%d] following the %f tells the frontier pattern what is "in the set" (in this case, any numeric digit).

So, this solution requires no alteration of the input string.

Code: Select all

local csv = '1,2,3'
local element = '1'
local hasElement = csv:find('%f[%d]'..element..'%f[%D]') ~= nil
The %D at the end is an inversion of %d, which means that any non-digit character is in the set, to detect the transition from number to non-number.
User avatar
ikarus1969
Posts: 505
Joined: February 28th, 2011, 3:20 pm
Location: Vienna, Austria

Re: Lua frontier pattern - undocumented feature

Post by ikarus1969 »

I too find that feature very useful. For me there's a "but" here. As it is an undocumented feature it may vanish in later vesions of lua as 5.1 (http://lua-users.org/lists/lua-l/2006-12/msg00536.html) which is the one used by rainmeter. I personally don't want to look for an error, maybe in some months or so, in one of my skins if it doesn't work anymore just because an undocumented feature isn't available anymore. I'm not sure if i would remember it. That would cost me too much time i guess.

But, that's a personal decision - the feature itself would deserve it to become an offical one imho.
User avatar
killall-q
Posts: 299
Joined: August 14th, 2009, 8:04 am

Re: Lua frontier pattern - undocumented feature

Post by killall-q »

ikarus1969 wrote: September 8th, 2022, 4:54 amAs it is an undocumented feature it may vanish in later vesions of lua as 5.1
Lua 5.1 is frozen in time. There have been no updates to Lua 5.1 since 2012, and never will be. (Rainmeter is using the last version, 5.1.5.) Moreover, the frontier pattern has been in the Lua reference manual as an official feature since Lua 5.2 and all subsequent versions.