Reputation: 943
I am trying to replace some text with some other text. Simple, right? Heh.
So first off, I have a string of text:
local str = "This is some >>1234 text. This is some >>>/other/1234 text."
You will note the funny looking formatting within the text. I need to replace those with HTML. But there is a catch: I need to access a database using the data within that formatting. I am using the following formats to grab data:
local pattern1 = ">>(%d+)"
local pattern2 = ">>>/(%w+)/(%d*)"
In both patterns, I need to use the %d
section to check the database. The reason for this is that depending on the data, I need to format the link differently. Ultimately, I want to have something like this:
local formatted = "This is some <a href='website.com/a/1220#1234'>>>1234</a> text. This is some <a href='website.com/other/1156#1234'>>>>/other/1234</a> text."
So my first attempt at this was to run a function on each instance of a match in string.gsub. This caused C-yield errors because I was trying to access C junk (database driver) inside a coroutine, which is, as I learned, a no-no.
I'm not really sure what my second attempt should be. I'm thinking that I need to iterate over the text with string.match to pull out the indices of the places I want to grab, then use gsub to get the data I need to access the database and store that somewhere, then rebuild the string from scratch.
Is that correct, or is there a better way?
Error
attempt to yield across C-call boundary
Traceback
stack traceback:
[C]: in function 'receive'
/home/karai/.luarocks/share/lua/5.1/pgmoon/init.lua:419: in function 'receive_message'
/home/karai/.luarocks/share/lua/5.1/pgmoon/init.lua:233: in function 'query'
/usr/share/lua/5.1/lapis/db/postgres.lua:64: in function 'select'
./src/text_formatter.lua:39: in function <./src/text_formatter.lua:24>
[C]: in function 'gsub'
./src/text_formatter.lua:55: in function 'quote'
./src/board.lua:58: in function 'handler'
/usr/share/lua/5.1/lapis/application.lua:399: in function 'resolve'
/usr/share/lua/5.1/lapis/application.lua:408: in function </usr/share/lua/5.1/lapis/application.lua:406>
[C]: in function 'xpcall'
/usr/share/lua/5.1/lapis/application.lua:406: in function 'dispatch'
/usr/share/lua/5.1/lapis/nginx.lua:205: in function 'serve'
content_by_lua(nginx.conf.compiled:27):2: in function <content_by_lua(nginx.conf.compiled:27):1>
Upvotes: 2
Views: 71
Reputation: 473222
It seems that the core of your problem is that you want to yield at each match (presumably until the database query is finished), then continue processing.
To do this, you should use gmatch
first. It does what gsub
does, but without the substitution; it returns an iterator that you can loop over that returns matches. So use this to generate your list of queries. This should be stored in an array:
local matches = {}
for match in my_string:gmatch(pattern) do
matches[#matches + 1] = match
end
Then just walk the array, doing your database/yield stuff.
local repls = {}
for i, match in ipairs(matches) do
--Do database query&yield stuff with `match`.
repls[i] = --Generate the data you want to replace this match with.
end
After that, just do gsub
to replace the string. The order of matches with gmatch
and gsub
are identical, so you don't need to care about the arguments:
local i = 0 --Not zero-based; keep reading
local fixed_string = my_string:gsub(pattern,
function() --Don't care about the arguments.
i = i + 1
return repls[i] --Started at zero, so that this would be correct.
end
)
Upvotes: 4