Lua string.format options - string

This may seem like a stupid question, but what are the symbols used for string replacement in string.format? can someone point me to a simple example of how to use it?

string.format in Lua follows the same patterns as Printf in c:
https://cplusplus.com/reference/cstdio/printf/
There are some exceptions, for those see here:
http://pgl.yoyo.org/luai/i/string.format

Chapter 20 of PiL describes string.format near the end:
The function string.format is a
powerful tool when formatting strings,
typically for output. It returns a
formatted version of its variable
number of arguments following the
description given by its first
argument, the so-called format string.
The format string has rules similar to
those of the printf function of
standard C: It is composed of regular
text and directives, which control
where and how each argument must be
placed in the formatted string.
The Lua Reference says:
The format string follows the same
rules as the printf family of standard
C functions. The only differences are
that the options/modifiers *, l, L, n,
p, and h are not supported and that
there is an extra option, q.
The function is implemented by str_format() in strlib.c which itself interprets the format string, but defers to the C library's implementation of sprintf() to actually format each field after determining what type of value is expected (string or number, essentially) to correspond to each field.

There should be "Lua Quick Reference" html file in your hard disk, if you used an installation package.
(for example: ../Lua/5.1/docs/luarefv51.html)
There you'll find, among other things,
string.format (s [, args ])
Formatting directives
Formatting field types
Formatting flags
Formatting examples

To add to the other answers: Lua does have a boolean data type, where C does not. C uses numbers for that, where 0 is false and everything else is true.
However, to format a boolean in a String in Lua,
local text = string.format("bool is %d", truth)
gets (at least in Hammerspoon):
bad argument #2 to 'format' (number expected, got boolean)
You can instead use %s for booleans (as for strings):
local text = string.format("bool is %s", truth)

Related

Can I get scape characters still behave as such for a string provided by f:read() in Lua?

I'm working on a simple localization function for my scripts and, although it's starting to work quite well so far, I don't know how to avoid scape/special characters to be shown in UI as part of the text after feeding the widgets with the strings returned by f:read().
For example, if in a certain Strings.ES.txt's line I have: Ignorar \"Etiquetas de capa\", I'd expect backslashes didn't end showing up just like when I feed the widget with a normal string between doble quotes like: "Ignorar \"Etiquetas de capa\"", or at least have a way to avoid it. I've been trial-and-erroring with tostring() and load() functions and different (surely nonsense 🙄) concatenations like: load(tostring("[[" .. f:read()" .. ]]")) and such without any success, so here I'm again...
Do someone know if there is a way to get scape characters in a string returned by f:read() still behave as special as when they are found in a regular one?
I don't know how to avoid [e]scape/special characters to be shown in UI as part of the text
What you want is to "unescape" or "unquote" a string to interpret escape sequences as if it were parsed as a quoted string by Lua.
[...] with the strings returned by f:read() [...]
The fact that this string was obtained using f:read() can be ignored; all that matters is that it is a string literal without quotes using quoted string escapes.
I've been trial-and-erroring with tostring() and load() functions and different [...] concatenations like: load(tostring("[[" .. f:read()" .. ]]")) and such without any success [...]
This is almost how to do it, except you chose the wrong string literal type: "Long" strings using pairs square brackets ([ and ]) do not interpret escape sequences at all; they are intended for including long, raw, possibly multiline strings in Lua programs and often come in handy when you need to represent literal strings with backslashes (e.g. regular expressions - not to be confused with Lua patterns, which use % for escapes, and lack the basic alternation operator of regular expressions).
If you instead use single or double quotes to wrap the string, it will work fine:
local function unescape_string(escaped)
return assert(load(('return "%s"'):format(escaped)))()
end
this will produce a tiny Lua program (a "chunk") for each string, which just consists of return "<contents>". Recall that Lua chunks are just functions. Thus you can simply call the function to obtain the value of the string it returns. That way, Lua will interpret the escape sequences for us. The same approach is often used to use Lua for reading data serialized as Lua code.
Note also the use of assert for error handling: load returns nil, err if there is a syntax error. To deal with this gracefully, we can wrap the call to load in assert: assert returns its first argument (the chunk returned by load) if it is truthy; otherwise, if it is falsy (e.g. nil in this case), assert errors, using its second argument as an error message. If you omit the assert and your input causes a syntax error, you will instead get a cryptic "attempt to call a nil value" error.
You probably want to do additional validation, especially if these escaped strings are user-provided - otherwise a malicious string like str"; os.execute("...") can trivially invoke a remote code execution (RCE) vulnerability, allowing it to both execute Lua e.g. to block (while 1 do end), slow down or hijack your application, as well as shell commands using os.execute. To guard against this, searching for an unescaped closing quote should be sufficient (syntax errors e.g. through invalid escapes will still be possible, but RCE should not be possible excepting Lua interpreter bugs):
local function unescape_string(escaped)
-- match start & end of sequences of zero or more backslashes followed by a double quote
for from, to in escaped:gmatch'()\\*()"' do
-- number of preceding backslashes must be odd for the double quote to be escaped
assert((to - from) % 2 ~= 0, "unescaped double quote")
end
return assert(load(('return "%s"'):format(escaped)))()
end
Alternatively, a more robust (but also more complex) and presumably more efficient way of unescaping this would be to manually implement escape sequences through string.gsub; that way you get full control, which is more suitable for user-provided input:
-- Single-character backslash escapes of Lua 5.1 according to the reference manual: https://www.lua.org/manual/5.1/manual.html#2.1
local escapes = {a = '\a', b = '\b', f = '\b', n = '\n', r = '\r', t = '\t', v = '\v', ['\\'] = '\\', ["'"] = "'", ['"'] = '"'}
local function unescape_string(escaped)
return escaped:gsub("\\(.)", escapes)
end
you may implement escapes here as you see fit; for example, this misses decimal escapes, which could easily be implemented as escaped:gsub("\\(%d%d?%d?)", string.char) (this uses coercion of strings to numbers in string.char and a replacement function as second argument to string.gsub).
This function can finally be used straightforwardly as unescape_string(f:read()).

How to change a string into a variable

I want to write out some data into a file. I saved the filename as a variable. I wan to use % mode to substitude the variable to the text, but it gives an error:
IndentationError: unindent does not match any outer indentation level
writeafile = open('N:\myfile\%s.txt' , "a") % (variable)
Assuming we are talking about Python here, you should move variable next to the
'N:\\myfile\\%s.txt' string for correct syntax, like so:
writeafile = open("N:\\myfile\\%s.txt" % variable, "a")
However, using this style of formatting is not recommended by Pydocs:
The formatting operations described here exhibit a variety of quirks that lead to a number of common errors (such as failing to display tuples and dictionaries correctly). Using the newer formatted string literals, the str.format() interface, or template strings may help avoid these errors. Each of these alternatives provides their own trade-offs and benefits of simplicity, flexibility, and/or extensibility.
Source
So, I'd suggest using f-strings, which have been available in Python since 3.6. The double \\ is intentional here, otherwise Python will treat it as an escape character and you'll get undesired results.
writeafile = open(f"N:\\myfile\\{variable}.txt", "a")
Alternatively, you could also use str.format():
writeafile = open("N:\\myfile\\{name}.txt".format(name=variable), "a")

What is %s+ or %s used for in lua and how do you use it?

How do i use %s in lua, or a better question would be how is it used?
so here is what i have tried before assuming this is how it is used and how it works.
local arg1 = 'lmao'
print('fav string is %arg1')
at first i thought it was something used to reference a string or numeral inside of a string without doing like
print('hello '..name..'!')
Can someone provide me some examples or a explanation on how this is used and what for?
A % in a string has no meaning in Lua syntax, but does mean something to certain functions in the string library.
In string.format, % is used to make a format specifier that converts another argument to a string. It's documented at string.format, but that refers to Output Conversion Syntax and Table of Output Conversions to explain almost all of the specifier syntax.
The % is also used to designate a character class in the pattern syntax used with some string functions.
Here is your code using string.format:
local arg1 = 'lmao'
print(string.format('fav string is %s', arg1))
Or, taking advantage of the string metatable:
local arg1 = 'lmao'
print(('fav string is %s'):format(arg1))
Lua uses %s in patterns (Lua's version of regular expressions) to mean "whitespace". %s+ means "one or more whitespace characters".
Ref: https://www.lua.org/manual/5.3/manual.html#6.4.1

String formatting in python 3 without print function

Trying to understand how "%s%s" %(a,a) is working in below code I have only seen it inside print function thus far.Could anyone please explain how it is working inside int()?
a=input()
b=int("%s%s" %(a,a))
this "%s" format has been borrowed from C printf format, but is much more interesting because it doesn't belong to print statement. Note that it involves just one argument passed to print (or to any function BTW):
print("%s%s" % (a,a))
and not (like C) a variable number of arguments passed to some functions that accept & understand them:
printf("%s%s,a,a);
It's a standalone way of creating a string from a string template & its arguments (which for instance solves the tedious issue of: "I want a logger with formatting capabilities" which can be achieved with great effort in C or C++, using variable arguments + vsprintf or C++11 variadic recursive templates).
Note that this format style is now considered legacy. Now you'd better use format, where the placeholders are wrapped in {}.
One of the direct advantages here is that since the argument is repeated you just have to do:
int("{0}{0}".format(a))
(it references twice the sole argument in position 0)
Both legacy and format syntaxes are detailed with examples on https://pyformat.info/
or since python 3.6 you can use fstrings:
>>> a = 12
>>> int(f"{a}{a}")
1212
% is in a way just syntactic sugar for a function that accepts a string and a *args (a format and the parameters for formatting) and returns a string which is the format string with the embedded parameters. So, you can use it any place that a string is acceptable.
BTW, % is a bit obsolete, and "{}{}".format(a,a) is the more 'modern' approach here, and is more obviously a string method that returns another string.

Single-quote notation for characters in Coq?

In most programming languages, 'c' is a character and "c" is a string of length 1. But Coq (according to its standard ascii and string library) uses "c" as the notation for both, which requires constant use of Open Scope to clarify which one is being referred to. How can you avoid this and designate characters in the usual way, with single quotes? It would be nice if there is a solution that only partially overrides the standard library, changing the notation but recycling the rest.
Require Import Ascii.
Require Import String.
Check "a"%char.
Check "b"%string.
or this
Program Definition c (s:string) : ascii :=
match s with "" => " "%char | String a _ => a end.
Check (c"A").
Check ("A").
I am quite confident that there is no smart way of doing this, but there is a somewhat annoying one: simply declare one notation for each character.
Notation "''c''" := "c" : char_scope.
Notation "''a''" := "a" : char_scope.
Check 'a'.
Check 'c'.
It shouldn't be too hard to write a script for automatically generating those declarations. I don't know if this has any negative side-effects on Coq's parser, though.

Resources