4

Let's say I want to match any sequence of the hash sign # at the start of a string; so I'd want to match ## here:

local mystr = "##First line\nSecond line\nThird line"

... and ### here:

local mystr = "First line\nSecond line\n### Third line"

... and nothing here:

local mystr = "First line\nSecond line\nThird line"

I guess, the pattern ^(%#+) could have worked here if the caret ^ meant start of a (multiline) line - however, as far as I can see, e.g. in How to match the start or end of a string with string.match in Lua?

^ at the start of a pattern anchors it to the start of the string. $ at the end of a pattern anchors it to the end of the string.

... the caret here would only match at the start of the multiline string (mystr) itself.

How could I go about matching a pattern that starts with "line start" in Lua?

4 Answers 4

3

You want to match either the start of the string ^ or after any newline \n character:

mystr:match("^(%#+)") or mystr:match("\n(%#+)")

I don't think you can combine it into one match. Logical 'or' in Lua patterns?

Sign up to request clarification or add additional context in comments.

Comments

3

An option would be to just add a \n to the start of the string:

string.match("\n" .. s, "\n(#+)")

^ can only be used as the first character of a pattern, and [charsets] only allow for single characters rather than sets of groups, so I don't think there exists a pattern that will match a string of any length (even with multiple captures).

(Edit: I tried with frontier patterns but couldn't get it working, see tehtmi's answer for a pattern that works with a single capture.)

It's also possible with a loop and multiple string.match() calls. This function matches every sequence of #s at the start of a line:

local function match(s)
    local matches = {}
    for _, v in ipairs(string.split(s, "\n")) do
        local m = string.match(v, "^#+")
        if m then
            table.insert(matches, m)
        end
    end
    return matches
end

Comments

2

It's a little more esoteric, but (if you aren't worried about null characters / embedded zeroes in your string), you could use the frontier pattern to do it directly with one pattern and no additional processing, like "%f[^\0\n](%#+)"

The frontier pattern matches a position where the next character belongs to the indicated set and the previous character doesn't -- and outside the string is treated as the null character '\0' which is useful if your string doesn't otherwise use the null character. In this case, "%f[^\0\n]" matches a position at the start of the string or after a newline and followed by any other character (including '#').

2 Comments

It is worth to note that frontier pattern only exists since lua 5.2. Thus, in particular, it won't work with luajit.
@QuenticC: Actually, it does exist in Lua 5.1 as an undocumented feature, but note that Lua 5.1 patterns aren't allowed to contain embedded zeroes, so you need to use %z instead of \0.
0

Be aware, # is not a special character, you do not need to escape it with %

The correct answer for your first question is lehtmi's, Using frontier pattern is the way to go, and yes it does work on latest 5.1 and luajit to make a match using string.match

string.match(str, "%f[^\n\r\0]###?[^#\r\n\0]+")

Should yield ##First line

How could I go about matching a pattern that starts with "line start" in Lua?

By matching everything that is not a line, you can divide using string.gmatch.

for line in str:gmatch"[^\r\n]*[^\n]?" do
 if line:find"^###?.+" then -- stuff here
 end
end

Should be enough for your use case.

A cool little trick is also using io.lines

local H = io.tmpfile()
H:write(str)
for line in H:lines() do
 if line:match then -- ... Same as above.
end
H:close()

This does sacrifice performance but it does allow for whatever io.lines does, which means it is less multiplatform.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.