I want to make sure players can't put letters or symbols in the value, how do I check if it is a number only?
function seed1()
ESX.UI.Menu.CloseAll()
ESX.UI.Menu.Open('dialog', GetCurrentResourceName(), 'amountseed1', {
title = 'Shop'
}, function(data, menu)
local amount = tostring(data.value)
if amount == nil then
...
else
[[What should i put here to check its only contain number ?]]
end
end, function(data, menu)
menu.close()
end)
end
I can put something like this, but maybe this isn't a good way to do that:
else
if amount > 0 and amount < 9999 then
...
else
print('Invalid amount or amount higher than 9999')
end
end
Since you only care about the number, there is no need to convert the value to string:
local amount = tostring(data.value)
-- ^^^^^^^^ partially useless
Instead, go for the number right away:
local amount = tonumber(data.value)
if amount == nil then
-- Not a number
else
-- A number
end
In the end, remember that tonumber attempts to convert the value to a number and returns nil in case of a failure.
Simply replace tostring with tonumber. This will turn strings into numbers if possible, and return nil if it can't.
Keep in mind: tonumber won't just take the largest valid prefix of a string, so tonumber("20 foo") will return nil and not 20. It also supports all ways to write number literals in Lua, so tonumber("2.3e2") will return 230 and tonumber("0xff") will return 255.
Related
Hello guys i please need your help.
I have values, most of them are numbers but some of them are strings.
How can i check if value is string or number?
I already tried this code but when it reach string value i get error " attempt to perform arithmetic on local 'numberValue' (a nil value)"
function Config:IsNumber(value)
if value ~=nill or value ~=nil then
local numberValue = tonumber(value)
if numberValue/numberValue ==1 then
return true
else
return false
end
end
end
end
end
First of all let's start with errors in your code.
You have 2 ends to many.
it is nil, not nill. I'm not sure where you're going with that check.
Other issues / things to improve:
numberValue / numberValue == 1 does not make any sense. A number dividided by itself always results in 1. So checking that is pointless.
Also instead of
if something == 1 then
return true
else
return false
end
Can simply be replaced by return something == 1. There is no need for a conditional statement here.
To your question:
To check wether a value is a string use type(value) == "string".
To check wether a value can be convertet do a number use tonumber(value). It will either return a number or nil.
So according to your error the conversion to a number failed.
If you don't know for sure that your value can be converted to a number, you should ensure that tonumber succeded befor you do any operations on its return value.
local numberValue = tonumber(value)
if not numberValue then
print("converting value to a number failed)
return
end
-- at this point you know numberValue is a number
So if you wanted to write a function that ensures a string represents a number you could do something like this:
function IsNumber(value)
return tonumber(value) and true or false
end
I have created a function that (pseudo)randomly creates a table containing numbers. I then loop this function until at least correct result is found. As soon as I've confirmed that at least one such result exists, I stop the function and return the table.
When I create tables containing small values, there are no issues. However, once the random numbers grow to the range of hundreds, the function begins to return nil, even though the table is true the line before I return it.
local sort = table.sort
local random = math.random
local aMin, aMax = 8, 12
local bMin, bMax = 200, 2000
local function compare( a, b )
return a < b
end
local function getNumbers()
local valid = false
local numbers = {}
-- Generate a random length table, containing random number values.
for i = 1, random( aMin, aMax ) do
numbers[i] = random( bMin, bMax )
end
sort( numbers, compare )
-- See if a specific sequence of numbers exist in the table.
for i = 2, #numbers do
if numbers[i-1]+1 == numbers[i] or numbers[i-1] == numbers[i] then
-- Sequence found, so stop.
valid = true
break
end
end
for i = 1, #numbers-1 do
for j = i+1, #numbers do
if numbers[j] % numbers[i] == 0 and numbers[i] ~= 1 then
valid = true
break
end
end
end
if valid then
print( "Within function:", numbers )
return numbers
else
getNumbers()
end
end
local numbers = getNumbers()
print( "Outside function:", numbers )
This function, to my understanding, is supposed to loop infinitely until I find a valid sequence. The only way that the function can even end, according to my code, is if valid is true.
Sometimes, more often than not, with large numbers the function simply outputs a nil value to the outside of the function. What is going on here?
You're just doing getNumbers() to recurse instead of return getNumbers(). This means that if the recursion gets entered, the final returned value will be nil no matter what else happens.
In the else case of the if valid then, you are not returning anything. You only return anything in the valid case. In the else case, a recursive call may return something, but then you ignore that returned value. The print you see is corresponding to the return from the recursive call; it isn't making it out the original call.
You mean to return getNumbers().
I'd like to format a number to look like 1,234 or 1,234,432 or 123,456,789, you get the idea. I tried doing this as follows:
function reformatint(i)
local length = string.len(i)
for v = 1, math.floor(length/3) do
for k = 1, 3 do
newint = string.sub(mystring, -k*v)
end
newint = ','..newint
end
return newint
end
As you can see, a failed attempt, my problem is that I can't figure out what the error is because the program I am running this in refuses to report an error back to me.
Here's a function that takes negative numbers, and fractional parts into account:
function format_int(number)
local i, j, minus, int, fraction = tostring(number):find('([-]?)(%d+)([.]?%d*)')
-- reverse the int-string and append a comma to all blocks of 3 digits
int = int:reverse():gsub("(%d%d%d)", "%1,")
-- reverse the int-string back remove an optional comma and put the
-- optional minus and fractional part back
return minus .. int:reverse():gsub("^,", "") .. fraction
end
assert(format_int(1234) == '1,234')
assert(format_int(1234567) == '1,234,567')
assert(format_int(123456789) == '123,456,789')
assert(format_int(123456789.1234) == '123,456,789.1234')
assert(format_int(-123456789.) == '-123,456,789')
assert(format_int(-123456789.1234) == '-123,456,789.1234')
assert(format_int('-123456789.1234') == '-123,456,789.1234')
print('All tests passed!')
Well, let's take this from the top down. First of all, it's failing because you've got a reference error:
...
for k = 1, 3 do
newint = string.sub(mystring, -k*v) -- What is 'mystring'?
end
...
Most likely you want i to be there, not mystring.
Second, while replacing mystring with i will fix the errors, it still won't work correctly.
> =reformatint(100)
,100
> =reformatint(1)
,000
That's obviously not right. It seems like what you're trying to do is go through the string, and build up the new string with the commas added. But there are a couple of problems...
function reformatint(i)
local length = string.len(i)
for v = 1, math.floor(length/3) do
for k = 1, 3 do -- What is this inner loop for?
newint = string.sub(mystring, -k*v) -- This chops off the end of
-- your string only
end
newint = ','..newint -- This will make your result have a ',' at
-- the beginning, no matter what
end
return newint
end
With some rework, you can get a function that work.
function reformatint(integer)
for i = 1, math.floor((string.len(integer)-1) / 3) do
integer = string.sub(integer, 1, -3*i-i) ..
',' ..
string.sub(integer, -3*i-i+1)
end
return integer
end
The function above seems to work correctly. However, it's fairly convoluted... Might want to make it more readable.
As a side note, a quick google search finds a function that has already been made for this:
function comma_value(amount)
local formatted = amount
while true do
formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2')
if (k==0) then
break
end
end
return formatted
end
You can do without loops:
function numWithCommas(n)
return tostring(math.floor(n)):reverse():gsub("(%d%d%d)","%1,")
:gsub(",(%-?)$","%1"):reverse()
end
assert(numWithCommas(100000) == "100,000")
assert(numWithCommas(100) == "100")
assert(numWithCommas(-100000) == "-100,000")
assert(numWithCommas(10000000) == "10,000,000")
assert(numWithCommas(10000000.00) == "10,000,000")
The second gsub is needed to avoid -,100 being generated.
I remember discussing about this in the LÖVE forums ... let me look for it...
Found it!
This will work with positive integers:
function reformatInt(i)
return tostring(i):reverse():gsub("%d%d%d", "%1,"):reverse():gsub("^,", "")
end
On the link above you may read details about implementation.
Using Lua how do I split a given IP address to get the minimum and maximum range for example:
94.19.21.119
I have a csv like this:
18087936,18153471,"AU"
18153472,18219007,"JP"
18219008,18350079,"IN"
18350080,18874367,"CN"
thats read to 3 tables and the csv is min,max,country code:
IPfrom = {}
IPto = {}
IPCountry = {}
they get populated like this:
IPfrom[18087936] = L
IPto[L] = 18153471
IPCountry[L] = "AU"
with L being the line number of the io.read, what Im then trying to do is get the minimum range so I can without looping check if it exists then if it does that key holds the index of the maximum range and if the ip is within the min/max I get the country code. Probably a different way of doing things but the tables are over 100000 entries so looping is taking some time.
Perhaps something like the following will work for you:
--
-- Converts an IPv4 address into its integer value
--
function iptoint(ip)
local ipint = 0
local iter = string.gmatch(ip, "%d+")
for i = 3, 0, -1 do
local piece = tonumber(iter())
if piece == nil or piece < 0 or piece > 255 then
return nil
end
ipint = bit32.bor(ipint, bit32.lshift(piece, 8 * i))
end
return ipint
end
--
-- Looks up an IPv4 address in a multidimensional table, with the entries:
-- {start_address, end_address, country}
-- and returns the matching country
--
function iptocountry(ip, tbl)
local ipint = iptoint(ip)
if ipint == nil then
return nil
end
for _,v in pairs(tbl) do
if ipint >= v[1] and ipint <= v[2] then
return v[3]
end
end
return nil
end
Example usage:
local countries = {
{16777216, 17367039, "US"},
{1578300000, 1678300000, "CAN"}
-- ... rest of entries loaded from CSV file
}
local ip = "94.19.21.119"
print (iptocountry(ip, countries)) -- prints CAN
A hash table (the basic type in Lua) will give you O(N). An array (a table with no holes with indices from someMinAddr to someMaxAddr) will give you O(1), but use a significant amount of memory. A binary search through a properly sorted structured table could give you O(log N), which for 100000 addresses is probably worth the effort. I imagine you could have a structure like this:
IPfrom = {
{line=L1, addFrom=from1, addrTo=to1, c=country1},
{line=L2, addFrom=from2, addrTo=to2, c=country2},
{line=L3, addFrom=from3, addrTo=to3, c=country3},
{line=L4, addFrom=from4, addrTo=to4, c=country4},
...
}
because I don't see the point of separating the to and country fields from the other info, just means more table lookup. Anyways if you really do want to separate them the following is not affected:
-- init:
create table from CSV file
sort IPFrom on addFrom field
-- as many times as required:
function findIP(addr)
is addr smaller than IPfrom[middle].addrTo3?
if yes, is addr smaller than IPfrom[middle of middle]?
etc
end
This is recursive so if you structure it properly you can use tail calls and not worry about stack overflow (;), something like
function findIPRecurs(addr, ipTbl, indxMin, indxMax)
local middle = (indxMin + indxMax )/2
local midAddr = ipTbl[middle].addrFrom
if addr < midAddr then
return findIPRecurs(addr, ipTbl, indxMin, middle)
else if addr > midAddr then
return findIPRecurs(addr, ipTbl, middle, indxMax)
else -- have entry:
return middle
end
end
function findIP(addr)
return findIPRecurs(addr, ipTbl, 1, #ipTbl)
end
I have not tested this so there might be some fixing up to do but you get the idea. This will use the same memory as O(N) method but for large arrays will be considerably faster; much less memory than O(1) method, and probably acceptably slower.
Is there a way to convert human readable time "09:41:43" to some comparable format?
What I want is function timeGreater(time1, time2), satisfied the below assertion
assert(true == timeGreater("09:41:43", "09:00:42"))
assert(false == timeGreater("12:55:43", "19:00:43")))
It seems like a simple string comparison may be sufficient (assuming time is valid):
function timeGreater(a, b) return a > b end
assert(true == timeGreater("09:41:43", "09:00:42"))
assert(false == timeGreater("12:55:43", "19:00:43"))
Converting your time to seconds should work. The code below might work, LUA isn't my strong suit!
function stime(s)
local pattern = "(%d+):(%d+):(%d+)"
local hours, minutes, seconds = string.match(s, pattern)
return (hours*3600)+(minutes*60)+seconds
end
function timeGreater(a, b)
return stime(a) > stime(b)
end