lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Shmuel Zeigerman wrote:
I'd like to propose the following extension for future versions of string.gsub (it is described below in the form of an indented insertion into the Manual text):

------------------------------------------------------------
If the value returned by the table query or by  the function
call  is  a  string  or  a number,  then it  is used  as the
replacement string
    (if the function returns a second  value and  that value
    is  true,  then  the  first  return  value  is  not used
    directly  but rather as if it was the `repl' parameter);
otherwise,  if  it  is  false  or  nil,  then  there  is  no
replacement  (that  is, the  original match  is kept  in the
string).
------------------------------------------------------------

Such a change may be helpful for interactive use, say, in text editor Replace operation, when the user specifies the `repl' string (e.g. "%2%1") and wants to make (or not to make) replacements individually for every match.

IMHO, the interface is generic enough as it is. For your specific example of replacing the match with "%2%1", you can simply use this function as the repl parameter:

function repl(capture1, capture2)
  return capture2 .. capture1
end


For an arbitrarily complicated pattern, this function will do what you want:

local trynum = {}
function trynum:__index(k)
  return self[tonumber(k)]
end
function generate_replace(repl_func)
  return function(...)
    local repl = repl_func(...)
    if type(repl) == "string" then
      repl = string.gsub(repl, "%%(.)",
        setmetatable({["%"] = "%", ...}, trynum))
    end
    return repl
  end
end


The generate_replace function takes a function which returns replacement strings like "%2%1" and returns a transformation of that function which is compatible with string.gsub().

An example:

-- replace letter-digit pairs
function sample(let,dig)
    if let == "a" then
        return false
    elseif let == "b" then
        return "%2"
    elseif let == "c" then
        return "%%%2%1%%"
    else
        return "%2%1"
    end
end

for line in io.lines() do
    -- match all letter-digit pairs
    line = string.gsub(line, "(%l)(%d)", generate_replace(sample))
    io.write(line, '\n')
end


And running it:

$ echo :a1:b2:c3:d4: |lua51 repl.lua
:a1:2:%3c%:4d:


Note that this method can't handle %0 replacements, as string.gsub does not pass the whole match to the function, only the captures.

					-Mark