Module:Escape
Lua error in package.lua at line 80: module 'Module:Yesno' not found. Script error: No such module "High-use".
Usage
This module is designed as an way to escape strings in a customized and efficient manner. It works by replacing characters that are preceded by your escape char (or phrase) There are two ways to call this module:
From another module:
Template:Codett esc:char(Template:Green) Template:Codett(Template:Green) Template:Green Template:Codett
From a template:
{{#invoke:Escape|main|mode=Template:Green|char=Template:Green|Template:Green}}
In a template, the most useful function is <syntaxhighlight lang="text" class="" style="" inline="1">kill</syntaxhighlight>.
This module is primarily intended to be used by other modules. However all functions can be called in template space using |mode=the function you want to call
followed by arguments.
All module functions (i.e. any func. other than <syntaxhighlight lang="text" class="" style="" inline="1">main()</syntaxhighlight>) should be called using a colon (Template:Char), e.g. <syntaxhighlight lang="lua" class="" style="" inline="1">esc:char('%')</syntaxhighlight> or <syntaxhighlight lang="lua" class="" style="" inline="1">esc:kill{'{{example|\\}}}', '}'} == '{{example|}'</syntaxhighlight>
Template:TOC tab | This function takes only one argument: A string. All characters in this string which are preceded by the sequence set by <syntaxhighlight lang="text" class="" style="" inline="1">escape:char()</syntaxhighlight> will be replaced with placeholders that can be converted back into that char by escape:undo() |
---|---|
Template:TOC tab | Takes two arguments:
|
Template:TOC tab | This is basically equivalent to calling <syntaxhighlight lang="text" class="" style="" inline="1">string.gsub()</syntaxhighlight> on the string returned by <syntaxhighlight lang="text" class="" style="" inline="1">escape:text()</syntaxhighlight> and feeding that result into <syntaxhighlight lang="text" class="" style="" inline="1">escape:undo()</syntaxhighlight> in a single step. Takes three arguments:
|
Template:TOC tab | This function's primary use is to initialize the patterns to scan a string for an escape/escaped sequence. It takes two arguments, the first being the escape character and the second being a table of arguments (optional). By default, this module will escape the <syntaxhighlight lang="text" class="" style="" inline="1">\</syntaxhighlight> char. To escape the <syntaxhighlight lang="text" class="" style="" inline="1">{</syntaxhighlight> char instead, you can do <syntaxhighlight lang="lua" class="" style="" inline="1">require('Module:Escape'):char('{')</syntaxhighlight> (or <syntaxhighlight lang="lua" class="" style="" inline="1">esc:char('{')</syntaxhighlight> (presuming you stored the table returned by this module in the local variable <syntaxhighlight lang="text" class="" style="" inline="1">esc</syntaxhighlight>).
When called without the second argument, char() will return a table containing the functions. This allows, for example, <syntaxhighlight lang="lua" class="" style="" inline="1">escape:char('*'):kill('1*23', '%d')</syntaxhighlight> which would return 'Template:Samp'. For the most part, there is very little reason to set ShortcutIf provided a second argument that is a table containing a Note that if multiple key-value pairs are provided, only one may execute. <syntaxhighlight lang="text" class="" style="" inline="1">kill</syntaxhighlight> is ignored if either <syntaxhighlight lang="text" class="" style="" inline="1">text</syntaxhighlight> or <syntaxhighlight lang="text" class="" style="" inline="1">undo</syntaxhighlight> are present. <syntaxhighlight lang="text" class="" style="" inline="1">undo</syntaxhighlight> is ignored if <syntaxhighlight lang="text" class="" style="" inline="1">text</syntaxhighlight> is present. |
Caveats
- When using a multi-character escape sequence, this module only marks it using the byte value of the first character. Thus, <syntaxhighlight lang="lua" class="" style="" inline="1">escape:undo()</syntaxhighlight> will unescape, for example, all characters escaped with <syntaxhighlight lang="text" class="" style="" inline="1">'e'</syntaxhighlight> and <syntaxhighlight lang="text" class="" style="" inline="1">'esc'</syntaxhighlight> if both were used. In practice however this shouldn't be a problem as multiple escape sequences are pretty rare unless you're transitioning between multiple code languages. (Multiple multi-char escape sequences beginning with the same character are simply bad practice anyhow.)
- Since byte values are stored as numbers, it is not recommended for you to use a number as an escape sequence (though it may work just fine).
- Placeholder byte values separated with return (<syntaxhighlight lang="text" class="" style="" inline="1">'\r'</syntaxhighlight>) characters--chosen because they are seldom used at all, and virtually never used unpaired with <syntaxhighlight lang="text" class="" style="" inline="1">'\n'</syntaxhighlight>; moreover, it is distinct from the markers generated by
<nowiki>...</nowiki>
or <syntaxhighlight lang="text" class="" style="" inline="1">mw.text.nowiki()</syntaxhighlight> (which use the delete char). To set a different separator char, include the key-value pair{safeChr = Template:Green}
in the table that you pass to escape:char().
Speed
The following are benchmarks...
when executing the following module function: <syntaxhighlight lang="lua">
function p.test_kill500(frame) local esc = require('Module:Escape') for k = 1, 500 do local v = esc:kill(p.test_string2(), 'test') end return os.clock(esc) end
</syntaxhighlight> 0.024
when repeating the following line 500 times in a template:
<syntaxhighlight lang="wikitext" class="" style="" inline="1">{{#invoke:Escape|main|mode=kill|{{#invoke:Escape/testcases|test_string2}}|test}}</syntaxhighlight>
0.767
All times in seconds. The module time x500 was calculated when you loaded this doc page (normally between 0.02 and 0.07). The template time x500 was recorded on Jan 15, 2015.
Examples
Template
Module
Here's some sample output from the debug console below the module editor:
Template:Blue
test, \test, \7b 044 7btest\\ \\ \\\\ Template:Blue
test, 5c 0116 5cest, 5c 055 5cb 044 7btest5c 092 5c 5c 092 5c 5c 092 5c5c 092 5c Template:Blue
test, 5c 0116 5cest, 5c 055 5cb 044 7btest5c 092 5c 5c 092 5c 5c 092 5c5c 092 5c Template:Blue
test, test, 7b 044 7btest\ \ \\ Template:Blue
true Template:BlueTemplate:Green
test, 5c 0116 5cest, 5c 055 5cb 044 7btest5c 092 5c 5c 092 5c 5c 092 5c5c 092 5c Template:Blue
test, \test, \,test\\ \\ \\\\ Template:Blue
test, test, 7b 044 7btest\ \ \\ Template:Blue
test, test, {,test\ \ \\ Template:Blue
false Template:Blue
true Template:Blue
test { test {\{ test, \test, \{,test\ \ \ {\ Template:Blue
test test { test, test, {,test \ Template:Blue
true
local escape = {
char = function(self, chr, args)
args = args or {}
local safe = args.safeChr or string.char(13)
chr = tostring(chr or '\\')
self[1] = ('%s0%%s%s'):format(
('%x%s%s'):format(chr:byte(), safe, safe),
('%s%x'):format(safe, chr:byte())
)
if not self[self[1]] then
self[self[1]] = {
char = chr,
text = ('%s(.)'):format(chr),
undo = self[1]:format'(%d+)'
}
end
return args.text and self:text(args.text)
or args.undo and self:undo(args.undo, chr)
or args.kill and self:kill(args.kill)
or self
end,
exec = function(self, text, mode, newEscape)
local target = self[self[1] or self:char() and self[1]]
for v in text:gfind(target[mode]) do
text = text:gsub(
mode == 'text' and
('%s%s'):format(target.char, v:gsub('%W', '%%%1'))
or self[1]:format(v),
mode == 'text' and
self[1]:format(v:byte())
or (newEscape or '') .. v:char()
)
end
return text
end,
text = function(self, text)
return self:exec(type(text) == 'table' and text[1] or text, 'text')
end,
undo = function(self, text, newEscape)
if type(text) == 'table' then
text, newEscape = unpack(text)
end
return self:exec(text, 'undo', newEscape)
end,
kill = function(self, text, chars, newEscape)
if type(text) == 'table' then
text, chars, newEscape = unpack(text)
end
return self:undo(self:text(text):gsub(chars or '', ''), newEscape)
end
}
function escape.main(frame)
local args, family = {}, {frame:getParent(), frame}
for f = 1, 2 do
for k, v in pairs(family[f] and family[f].args or {}) do
args[k] = args[k] or v:match('^%s*(.-)%s*$')
end
end
if args.mode == 'char' then
return escape:char(args.char or args[2], args)
end
return escape[args.mode](escape:char(args.char), args)
end
return escape