1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
--
-- A string.format wrapper that gracefully handles invalid arguments
--
local tostring = tostring;
local select = select;
local assert = assert;
local unpack = unpack;
local type = type;
local function format(formatstring, ...)
local args, args_length = { ... }, select('#', ...);
-- format specifier spec:
-- 1. Start: '%%'
-- 2. Flags: '[%-%+ #0]'
-- 3. Width: '%d?%d?'
-- 4. Precision: '%.?%d?%d?'
-- 5. Option: '[cdiouxXaAeEfgGqs%%]'
--
-- The options c, d, E, e, f, g, G, i, o, u, X, and x all expect a number as argument, whereas q and s expect a string.
-- This function does not accept string values containing embedded zeros, except as arguments to the q option.
-- a and A are only in Lua 5.2+
-- process each format specifier
local i = 0;
formatstring = formatstring:gsub("%%[^cdiouxXaAeEfgGqs%%]*[cdiouxXaAeEfgGqs%%]", function(spec)
if spec ~= "%%" then
i = i + 1;
local arg = args[i];
if arg == nil then -- special handling for nil
arg = "<nil>"
args[i] = "<nil>";
end
local option = spec:sub(-1);
if option == "q" or option == "s" then -- arg should be string
args[i] = tostring(arg);
elseif type(arg) ~= "number" then -- arg isn't number as expected?
args[i] = tostring(arg);
spec = "[%s]";
end
end
return spec;
end);
-- process extra args
while i < args_length do
i = i + 1;
local arg = args[i];
if arg == nil then
args[i] = "<nil>";
else
args[i] = tostring(arg);
end
formatstring = formatstring .. " [%s]"
end
return formatstring:format(unpack(args));
end
local function test()
assert(format("%s", "hello") == "hello");
assert(format("%s") == "<nil>");
assert(format("%s", true) == "true");
assert(format("%d", true) == "[true]");
assert(format("%%", true) == "% [true]");
end
return {
format = format;
test = test;
};
|