calculating string length causes confustion - lua

I am confused by the following output:
local a = "string"
print(a.len) -- function: 0xc8a8f0
print(a.len(a)) -- 6
print(len(a))
--[[
/home/pi/test/wxlua/wxLua/ZeroBraneStudio/bin/linux/armhf/lua: /home/pi/Desktop/untitled.lua:4: attempt to call global 'len' (a nil value)
stack traceback:
/home/pi/Desktop/untitled.lua:4: in main chunk
[C]: ?
]]
What is the proper way to calculate a string length in Lua?
Thank you in advance,

You can use:
a = "string"
string.len(a)
Or:
a = "string"
a:len()
Or:
a = "string"
#a
EDIT: your original code is not idiomatic but is also working
> a = "string"
> a.len
function: 0000000065ba16e0
> a.len(a)
6
The string a is linked to a table (named metatable) containing all the methods, including len.
A method is just a function, taking the string as the first parameter.
function a.len (string) .... end
You can call this function, a.len("test") just like a normal function. Lua has a special syntax to make it easier to write. You can use this special syntax and write a:len(), it will be equivalent to a.len(a).

print(a.len) -- function: 0xc8a8f0
This prints a string representation of a.len which is a function value. All strings share a common metatable.
From Lua 5.4 Reference Manual: 6.4 String Manipulation:
The string library provides all its functions inside the table string.
It also sets a metatable for strings where the __index field points to
the string table. Therefore, you can use the string functions in
object-oriented style. For instance, string.byte(s,i) can be written
as s:byte(i).
So given that a is a string value, a.len actually refers to string.len
For the same reason
print(a.len(a))
is equivalent to print(string.len(a)) or print(a:len()). This time you called the function with argument a instead of printing its string representation so you print its return value which is the length of string a.
print(len(a))
on the other hand causes an error because you attempt to call a global nil value. len does not exist in your script. It has never been defined and is hence nil. Calling nil values doesn't make sense so Lua raises an error.
According to Lua 5.4 Reference Manual: 3.4.7 Length Operator
The length of a string is its number of bytes. (That is the usual
meaning of string length when each character is one byte.)
You can also call print(#a) to print a's length.
The length operator was introduced in Lua 5.1,

Related

What's the , Lua equivalent of pythons endswith()?

I want to convert this python code to lua .
for i in range(1000,9999):
if str(i).endswith('9'):
print(i)
I've come this far ,,
for var=1000,9000 then
if tostring(var).endswith('9') then
print (var)
end
end
but I don't know what's the lua equivalent of endswith() is ,,, im writing an nmap script,,
working 1st time with lua so pls let me know if there are any errors ,, on my current code .
The python code is not great, you can get the last digit by using modulo %
# python code using modulo
for i in range(1000,9999):
if i % 10 == 9:
print(i)
This also works in Lua. However Lua includes the last number in the loop, unlike python.
-- lua code to do this
for i=1000, 9998 do
if i % 10 == 9 then
print(i)
end
end
However in both languages you could iterate by 10 each time
for i in range(1009, 9999, 10):
print(i)
for i=9, 9998, 10 do
print(i)
for var = 1000, 9000 do
if string.sub(var, -1) == "9" then
-- do your stuff
end
end
XY-Problem
The X problem of how to best port your code to Lua has been answered by quantumpro already, who optimized it & cleaned it up.
I'll focus on your Y problem:
What's the Lua equivalent of Python endswith?
Calling string functions, OOP-style
In Lua, strings have a metatable that indexes the global string library table. String functions are called using str:func(...) in Lua rather than str.func(...) to pass the string str as first "self" argument (see "Difference between . and : in Lua").
Furthermore, if the argument to the call is a single string, you can omit the parentheses, turning str:func("...") into str:func"...".
Constant suffix: Pattern Matching
Lua provides a more powerful pattern matching function that can be used to check whether a string ends with a suffix: string.match. str.endswith("9") in Python is equivalent to str:match"9$" in Lua: $ anchors the pattern at the end of the string and 9 matches the literal character 9.
Be careful though: This approach doesn't work with arbitrary, possibly variable suffices since certain characters - such as $ - are magic characters in Lua patterns and thus have a special meaning. Consider str.endswith("."); this is not equivalent to string:match".$" in Lua, since . matches any character.
I'd say that this is the lua-esque way of checking whether a string ends with a constant suffix. Note that it does not return a boolean, but rather a match (the suffix, a truthy value) if successful or nil (a falsey value) if unsuccessful; it can thus safely be used in ifs. To convert the result into a boolean, you could use not not string:match"9$".
Variable suffix: Rolling your own
Lua's standard library is very minimalistic; as such, you often need to roll your own functions even for basic things. There are two possible implementations for endswith, one using pattern matching and another one using substrings; the latter approach is preferable because it's shorter, possibly faster (Lua uses a naive pattern matching engine) and doesn't have to take care of pattern escaping:
function string:endswith(suffix)
return self:sub(-#suffix) == suffix
end
Explanation: self:sub(-#suffix) returns the last suffix length characters of self, the first argument. This is compared against the suffix.
You can then call this function using the colon (:) syntax:
str = "prefixsuffix"
assert(str:endswith"suffix")
assert(not str:endswith"prefix")

Lua/print table error : ( attempt to concatenate a table value)

I got a simple code like:
table = {}
print(table.."hello")
then got a error like the title. I know i need to use tostring(table) to fix it . Why table or other types can't convert to string to concatenate a String automatically except number type ?
print(table) is available But print(table.."hello") is not .
Does lua have some rules?
Thanks you.
Why table or other types can't convert to string to concatenate a String automatically except number type?
This is a deliberate choice made by the Lua language designers. Strings and numbers are coerced: Every operation that expects a string will also accept a number and tostring it; every operation that expects a number will also accept a string and tonumber it.
Coercion is an operation applied to strings. Numbers will be tostringed. Any other type won't. For other primitive types like bools and nils this is somewhat questionable, since they can be converted to string without issue. For tables it's reasonable though since they are a reference type.
Unlike other languages which make such decisions for you, Lua is highly metaprogrammable: You can simply override the decision! In this case, metatables are the solution, specifically the __concat metamethod which gets called if concatenation (..) is applied to two values of which one has the metamethod (and is neither a string or number):
table = setmetatable({}, {
__concat = function(left, right)
if type(left) == "string" then
return left .. tostring(right)
end
return tostring(left) .. tostring(right)
end
})
print(table .. "hello") -- hellotable: 0x563eb139bea0
You could even extend this to primitive types (nils, booleans), some other reference types (functions, coroutines) using debug.setmetatable, but I'd advise against this.
The declaration of table = {} destroying the table library
The datatype table is not a string or number so concat with .. must fail
Try this instead...
mytab = {}
table.insert(mytab, "hello")
print(table.concat(mytab))
For the table library functions look: https://www.lua.org/manual/5.4/manual.html#6.6

Unpacking table in a function call

Without giving too much details, this sample snippet demonstrates the problem:
-- Add an extra predefined argument
function one_more_arg(...)
local args = {...}
return function()
print(table.unpack(args), "c")
end
end
local my_new_print = one_more_arg("a", "b")
my_new_print() -- "a c"
Apparently unpacking a table does not work in this scenario. Any ideas on how to make this work, ie print will receive "a", "b", "c"? I'm trying to avoid modifying args, unless it's the only way to achieve it.
When you place table.unpack() as an argument to function there should be no other arguments or it should be the last one. Otherwise only first value from table will be passed.
Lua always adjusts the number of results from a function to the
circumstances of the call. When we call a function as a statement, Lua
discards all of its results. When we use a call as an expression, Lua
keeps only the first result. We get all results only when the call is
the last (or the only) expression in a list of expressions. These
lists appear in four constructions in Lua: multiple assignment,
arguments to function calls, table constructors, and return
statements.
From http://www.lua.org/pil/5.1.html
So you can try to put unpack at the end if it is ok for you:
print("c", table.unpack(args))
Or modify args.
table.concat (list [, sep [, i [, j]]])
Given a list where all elements are strings or numbers, returns the string list[i]..sep..list[i+1] ยทยทยท sep..list[j]. The default value for sep is the empty string, the default for i is 1, and the default for j is #list. If i is greater than j, returns the empty string.

Stuck on a basic Lua writeInteger function

I am a newcomer to coding in general and I want to learn basic Lua scripting for my own hobby.
After working on a Lua script, the syntax all seems to be without error but I have come across one issue that I don't understand, I broke it down to this basic function:
{$lua}
ID1 = "10"
ID2 = "0"
if (ID1 ~= nil and ID1 == "10") then
writeInteger(ID2,"25")
end
print(ID2)
The issue is that the writeInteger does not seem to work at all, ID2 remains at value "0" while it should become "25".
Any help would be greatly appreciated.
This is not valid Lua, or at least it isn't valid vanilla (out-of-the-box) Lua, and since you have not specified anything else, there is not much we can do to help. I will assume writeInteger is a valid function (since your interpreter isn't complaining about a call to a nil value), but I don't think it works as you expect.
If you want to set the ID2 variable to 25, simply write:
ID2 = 25
Lua will convert the string type to an integer type automatically. You can run print(type(ID2)) to confirm this
If you are using cheat engine (as a quick google search suggests) the writeInteger function requires an address and a value.
function writeInteger(Address, Value): Boolean - Returns true on success.
I am not sure if ID2, a Lua variable, is a valid address, but I am sure that "25" is not an integer. You should remove the quotation marks to start, and since the function returns a boolean you can see if the function was successful by doing:
print(writeInteger(ID2, 25))
Lua uses pass by value for primitive types like numbers, booleans and strings. So if you pass a number to a function like writeInteger, it creates a local copy within the function. The function can alter this copy but it will have no effect on caller (of writeInteger in this case). I don't know how writeInteger is supposed to work but if you want to call a function which alters its argument you can create a table and pass that. Tables are still passed by value but the "value" of a table is its memory address (so in effect tables are passed by reference and you can alter the contents of a table by passing it to a function).
See more here
Function/variable scope (pass by value or reference?)

Conversion of sequence of bytes to ASCII string in lua

I am trying to write custom dissector for Wireshark, which will change byte/hex output to ASCII string.
I was able to write the body of this dissector and it works. My only problem is conversion of this data to ASCII string.
Wireshark declares this data to be sequence of bytes.
To Lua the data type is userdata (tested using type(data)).
If I simply convert it to string using tostring(data) my dissector returns 24:50:48, which is the exact hex representation of bytes in an array.
Is there any way to directly convert this byte sequence to ascii, or can you help me convert this colon separated string to ascii string? I am totally new to Lua. I've tried something like split(tostring(data),":") but this returns Lua Error: attempt to call global 'split' (a nil value)
Using Jakuje's answer I was able to create something like this:
function isempty(s)
return s == nil or s == ''
end
data = "24:50:48:49:4A"
s = ""
for i in string.gmatch(data, "[^:]*") do
if not isempty( i ) then
print(string.char(tonumber(i,16)))
s = s .. string.char(tonumber(i,16))
end
end
print( s )
I am not sure if this is effective, but at least it works ;)
There is no such function as split in Lua (consulting reference manual is a good start). You should use probably string.gmatch function as described on wiki:
data = "24:50:48"
for i in string.gmatch(data, "[^:]*") do
print(i)
end
(live example)
Further you are searching for string.char function to convert bytes to ascii char.
You need to mark range of bytes in the buffer that you're interested in and convert it to the type you want:
data:range(offset, length):string()
-- or just call it, which works the same thanks to __call metamethod
data(offset, length):string()
See TvbRange description in https://wiki.wireshark.org/LuaAPI/Tvb for full list of available methods of converting buffer range data to different types.

Resources