Skip to content

Instantly share code, notes, and snippets.

@Buy-One
Last active April 28, 2022 10:14
Show Gist options
  • Save Buy-One/e83d00a782c2429474c178a0b52aec25 to your computer and use it in GitHub Desktop.
Save Buy-One/e83d00a782c2429474c178a0b52aec25 to your computer and use it in GitHub Desktop.
Replace Nth capture in a string (versatile)
function replace_Nth_capture(src_str, patt, repl_str, N) -- patt is either a literal string or a pattern; N is ordinal number of the capture to be replaced, if not N or 0 then N is 1
local N = N and tonumber(N) and math.abs(math.floor(N))
if not N or N == 0 then N = 1 end
local i = 1
local st, fin, capt
local capt_cnt = 0
while i < #src_str do
-- OR
--repeat
st, fin, capt = src_str:find('('..patt..')', i)
if capt then capt_cnt = capt_cnt + 1 end
if capt_cnt == N then break end
i = fin + 1
--OR
--until i > #src_str -- > because of fin + 1, doesn't happen with 'while' operator
end
return N > capt_cnt and src_str or src_str:sub(1, fin-#capt)..repl_str..src_str:sub(fin+1) -- if N is greater than the number of captrures the original string is returned otherwis the one with substitutiones
end
-- USE CASES
local src_str = 'test one test one one test'
local repl_str = 'ffsds'
--1)
for _, v in ipairs({1,6}) do -- replaces 1st and 6th captures of any word
src_str = replace_Nth_capture(src_str, '%a+', repl_str, v)
end
-- result: 'ffsds one test one one ffsds'
--2)
for _, v in ipairs({{1,2}}) do -- replaces 1st and 3d instances of the word 'test' // every next instance number must be 1 less (2 instead of 3) because their number is being reduced as replacement continues, e.g. to replace 1st and 2nd instances {1,1} must be used
src_str = replace_Nth_capture(src_str, 'test', repl_str, v)
end
-- result: 'ffsds one test one one ffsds'
--3)
for patt, repl_str in pairs({test = 'test1', one = 'one1'}) do -- replaces 3d instance of 'test' with 'test1' and 3d instance of 'one' with 'one1'
src_str = replace_Nth_capture(src_str, patt, repl_str, 3)
end
-- result: 'test one test one one1 test1'
--4)
for patt, v in pairs({test = {[2] = 'test1'}, one = {[3] = 'one1'}}) do -- replaces 2d instance of 'test' with 'test1' and 3d instance of 'one' with 'one1'
for N, repl_str in pairs(v) do
src_str = replace_Nth_capture(src_str, patt, repl_str, N)
end
end
-- result: 'test one test1 one one1 test'
--5)
for _, t in ipairs({ {one1 = 1}, {one2 = 1} }) do -- raplaces 1st instance of 'test' with 'one1' and 2nd instance of 'test' with 'one2'; for N values see use case 2) above
for repl_str, N in pairs(t) do
src_str = replace_Nth_capture(src_str, 'test', repl_str, N)
end
end
-- result: 'one1 one one2 one one test'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment