Lua Memo

string.gsub ... パターンを置き換え

string.gsub (s, pattern, repl [, n])

パターン pattern をすべて repl によって指定された置換文字列に置き換えた s のコピーを返す。 repl は文字列、テーブル、または関数でもよい。 gsub は二番目の値として、置換が行われた回数も返す。

repl が文字列であれば、その値が置換に使われる。文字 % はエスケープ文字として機能する。 repl 内に現れる %n は (n は1から9)、 n 番目にキャプチャされた部分文字列を表す (以下を見よ)。 シーケンス %0 はマッチ全体を表す。シーケンス は1個の % を表す。

repl がテーブルであれば、そのテーブルは最初のキャプチャをキーとしてマッチのたびに問い合わせられる。パターンにキャプチャがなければ、マッチ全体がキーとして使われる。

repl が関数であれば、マッチが現れるたびにこの関数が呼ばれる。関数にはキャプチャされた部分文字列が順番にすべて渡される。パターンにキャプチャが指定されていなければ、マッチした全体が唯一の引数として渡される。テーブル問い合わせまたは関数呼び出しから返された値が文字列か数値であれば、それが置換文字列として使われる。そうでなくて false か nil であれば、置換は行われない (つまり、文字列中の元のマッチが維持される)。

省略可能な最後の引数 n は置換が行われる最大回数を制限する。例えば、n が1なら最初に現れる pattern だけが置換される。

sample

   x = string.gsub("hello world", "(%w+)", "%1 %1")
   --> x="hello hello world world"

   x = string.gsub("hello world", "%w+", "%0 %0", 1)
   --> x="hello hello world"

   x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
   --> x="world hello Lua from"

   x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)
   --> x="home = /home/roberto, user = roberto"

   x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
         return loadstring(s)()
       end)
   --> x="4+5 = 9"

   local t = {name="lua", version="5.1"}
   x = string.gsub("$name%-$version.tar.gz", "%$(%w+)", t)
   --> x="lua-5.1.tar.gz"

cgilua.urlcode.lua より、クエリのパースを行う例。エレガント!

function parsequery (query, args)
	if type(query) == "string" then
		local insertfield, unescape = insertfield, unescape
		string.gsub (query, "([^&=]+)=([^&=]*)&?",
			function (key, val)
				insertfield (args, unescape(key), unescape(val))
			end)
	end
end

そして、URLエンコード

function escape (str)
	str = string.gsub (str, "\n", "\r\n")
	str = string.gsub (str, "([^0-9a-zA-Z ])", -- locale independent
		function (c) return string.format ("%%%02X", string.byte(c)) end)
	str = string.gsub (str, " ", "+")
	return str
end