string.gsub - possible enhancement

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

string.gsub - possible enhancement

Shmuel Zeigerman-2
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.

--
Shmuel
Reply | Threaded
Open this post in threaded view
|

Re: string.gsub - possible enhancement

Mark Edgar
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
Reply | Threaded
Open this post in threaded view
|

Re: string.gsub - possible enhancement

Shmuel Zeigerman-2
Mark Edgar wrote:

> For an arbitrarily complicated pattern, this function will do what you
> want:
>
[snip]
Thanks for the excellent code which I intend to make use of. Your
solution is in fact more generic than that I was proposing. But still,
it'd be nice to have this functionality "out of the box".

Yet another thing that I miss in string.gsub is the ability to break the
process after arbitrary match (when the `repl' function returns some
dedicated value that means "no further replaces are needed").

--
Shmuel
Reply | Threaded
Open this post in threaded view
|

Re: string.gsub - possible enhancement

Mark Edgar
Shmuel Zeigerman wrote:

> Mark Edgar wrote:
>
>> For an arbitrarily complicated pattern, this function will do what you
>> want:
>>
> [snip]
> Thanks for the excellent code which I intend to make use of. Your
> solution is in fact more generic than that I was proposing. But still,
> it'd be nice to have this functionality "out of the box".
>
> Yet another thing that I miss in string.gsub is the ability to break the
> process after arbitrary match (when the `repl' function returns some
> dedicated value that means "no further replaces are needed").
>

To solve this, you could write a loop based on string.find, making use
of its first two return values and its third parameter to find each
match in turn.

                                        -Mark