Lua: Type of a character - lua

I need a function
function getCharType(c)
local i = string.byte(c) -- works only for 1 byte chars
if (i > 48) and (i < 57) then return 1 end
if (i > 97) and (i < 122) then return 2 end
return 0
end
which should return
2 - if c is a letter
1 - if c is a digit
0 - if c is a symbol (anything else)
c itself will already be a lower case character: charType = getCharType(string.lower(Character)). If Unicode characters are possible, that would be fine.
With the above getCharType("ö") is 0.

To find out whether a non-ASCII character is an uppercase or lowercase letter or a number, you need Unicode data. Module:Unicode data on Wikipedia has a function like this that uses Module:Unicode data/category (data for the General Category of Unicode characters).
Here's an adaptation of the lookup_category function from Module:Unicode data. I haven't included the Unicode data (Module:Unicode data/category); you will have to copy it from the link above.
local category_data -- set this variable to the table in Module:Unicode data/category above
local floor = math.floor
local function binary_range_search(code_point, ranges)
local low, mid, high
low, high = 1, #ranges
while low <= high do
mid = floor((low + high) / 2)
local range = ranges[mid]
if code_point < range[1] then
high = mid - 1
elseif code_point <= range[2] then
return range
else
low = mid + 1
end
end
return nil
end
function get_category(code_point)
if category_data.singles[code_point] then
return category_data.singles[code_point]
else
local range = binary_range_search(code_point, category_data.ranges)
return range and range[3] or "Cn"
end
end
The function get_category takes a code point (a number) and returns the name of the General Category. I guess the categories you are interested in are Nd (number, decimal digit) and the categories that begin with L (letter).
You will need a function that converts a character to a codepoint. If the file is encoded in UTF-8 and you are using Lua 5.3, you can use the utf8.codepoint function: get_category(utf8.codepoint('ö')) will result in 'Ll'. You can convert category codes to the number value that your function above uses: function category_to_number(category) if category == "Nd" then return 1 elseif category:sub(1, 1) == "L" then return 2 else return 0 end end.

Works only with ASCII characters (not Unicode)
function getCharType(c)
return #c:rep(3):match(".%w?%a?")-1
end

Related

Reliable way of getting the exact decimals from any number

I'm having problem returning spesific amount of decimal numbers from this function, i would like it to get that info from "dec" argument, but i'm stuck with this right now.
Edit: Made it work with the edited version bellow but isn't there a better way?
local function remove_decimal(t, dec)
if type(dec) == "number" then
for key, num in pairs(type(t) == "table" and t or {}) do
if type(num) == "number" then
local num_to_string = tostring(num)
local mod, d = math.modf(num)
-- find only decimal numbers
local num_dec = num_to_string:sub(#tostring(mod) + (mod == 0 and num < 0 and 3 or 2))
if dec <= #num_dec then
-- return amount of deciamls in the num by dec
local r = d < 0 and "-0." or "0."
local r2 = r .. num_dec:sub(1, dec)
t[key] = mod + tonumber(r2)
end
end
end
end
return t
end
By passing the function bellow i want a result like this:
result[1] > 0.12
result[2] > -0.12
result[3] > 123.45
result[4] > -1.23
local result = remove_decimal({0.123, -0.123, 123.456, -1.234}, 2)
print(result[1])
print(result[2])
print(result[3])
print(result[4])
I tried this but it seems to only work with one integer numbers and if number is 12.34 instead of 1.34 e.g, the decimal place will be removed and become 12.3. Using other methods
local d = dec + (num < 0 and 2 or 1)
local r = tonumber(num_to_string:sub(1, -#num_to_string - d)) or 0
A good approach is to find the position of the decimal point (the dot, .) and then extract a substring starting from the first character to the dot's position plus how many digits you want:
local function truncate(number, dec)
local strnum = tostring(number)
local i, j = string.find(strnum, '%.')
if not i then
return number
end
local strtrn = string.sub(strnum, 1, i+dec)
return tonumber(strtrn)
end
Call it like this:
print(truncate(123.456, 2))
print(truncate(1234567, 2))
123.45
1234567
To bulk-truncate a set of numbers:
local function truncate_all(t, dec)
for key, value in pairs(t) do
t[key] = truncate(t[key], dec)
end
return t
end
Usage:
local result = truncate_all({0.123, -0.123, 123.456, -1.234}, 2)
for key, value in pairs(result) do
print(key, value)
end
1 0.12
2 -0.12
3 123.45
4 -1.23
One could use the function string.format which is similar to the printf functions from C language. If one use the format "%.2f" the resulting string will contain 2 decimals, if one use "%.3f" the resulting string will be contain 3 decimals, etc. The idea is to dynamically create the format "%.XXXf" corresponding to the number of decimal needed by the function. Then call the function string.format with the newly created format string to generate the string "123.XXX". The last step would be to convert back the string to a number with the function tonumber.
Note that if one want the special character % to be preserved when string.format is called, you need to write %%.
function KeepDecimals (Number, DecimalCount)
local FloatFormat = string.format("%%.%df", DecimalCount)
local String = string.format(FloatFormat, Number)
return tonumber(String)
end
The behavior seems close to what the OP is looking for:
for Count = 1, 5 do
print(KeepDecimals(1.123456789, Count))
end
This code should print the following:
1.1
1.12
1.123
1.1235
1.12346
Regarding the initial code, it's quite straight-forward to integrate the provided solution. Note that I renamed the function to keep_decimal because in my understanding, the function will keep the requested number of decimals, and discard the rest.
function keep_decimal (Table, Count)
local NewTable = {}
local NewIndex = 1
for Index = 1, #Table do
NewTable[NewIndex] = KeepDecimal(Table[Index], Count)
NewIndex = NewIndex + 1
end
return NewTable
end
Obviously, the code could be tested easily, simply by copy and pasting into a Lua interpreter.
Result = keep_decimal({0.123, -0.123, 123.456, -1.234}, 2)
for Index = 1, #Result do
print(Result[Index])
end
This should print the following:
0.12
-0.12
123.46
-1.23
Edit due to the clarification of the need of truncate:
function Truncate (Number, Digits)
local Divider = Digits * 10
local TruncatedValue = math.floor(Number * Divider) / Divider
return TruncatedValue
end
On my computer, the code is working as expected:
> Truncate(123.456, 2)
123.45

Generating star pattern in LUA

I am new to programming in LUA. And I am not able to solve this question below.
Given a number N, generate a star pattern such that on the first line there are N stars and on the subsequent lines the number of stars decreases by 1.
The pattern generated should have N rows. In every row, every fifth star (*) is replaced with a hash (#). Every row should have the required number of stars (*) and hash (#) symbols.
Sample input and output, where the first line is the number of test cases
This is what I tried.. And I am not able to move further
function generatePattern()
n = tonumber(io.read())
i = n
while(i >= 1)
do
j = 1
while(j<=i)
do
if(j<=i)
then
if(j%5 == 0)
then
print("#");
else
print("*");
end
print(" ");
end
j = j+1;
end
print("\n");
i = i-1;
end
end
tc = tonumber(io.read())
for i=1,tc
do
generatePattern()
end
First, just the stars without hashes. This part is easy:
local function pattern(n)
for i=n,1,-1 do
print(string.rep("*", i))
end
end
To replace each 5th asterisk with a hash, you can extend the expression with the following substitution:
local function pattern(n)
for i=n,1,-1 do
print((string.rep("*", i):gsub("(%*%*%*%*)%*", "%1#")))
end
end
The asterisks in the pattern need to be escaped with a %, since * holds special meaning within Lua patterns.
Note that string.gsub returns 2 values, but they can be truncated to one value by adding an extra set of parentheses, leading to the somewhat awkward-looking form print((..)).
Depending on Lua version the metamethod __index holding rep for repeats...
--- Lua 5.3
n=10
asterisk='*'
print(asterisk:rep(n))
-- puts out: **********
#! /usr/bin/env lua
for n = arg[1], 1, -1 do
local char = ''
while #char < n do
if #char %5 == 4 then char = char ..'#'
else char = char ..'*'
end -- mod 5
end -- #char
print( char )
end -- arg[1]
chmod +x asterisk.lua
./asterisk.lua 15
Please do not follow this answer since it is bad coding style! I would delete it but SO won't let me. See comment and other answers for better solutions.
My Lua print adds newlines to each printout, therefore I concatenate each character in a string and print the concatenated string out afterwards.
function generatePattern()
n = tonumber(io.read())
i = n
while(i >= 1)
do
ouput = ""
j = 1
while(j<=i)
do
if(j%5 == 0)
then
ouput=ouput .. "#";
else
ouput=ouput .. "*";
end
j = j+1;
end
print(ouput);
i = i-1;
end
end
Also this code is just yours minimal transformed to give the correct output. There are plenty of different ways to solve the task, some are faster or more intuitive than others.

"translating" One character to another in lua

I want to make a lua script that takes the input of a table, then outputs the strings in that table in their full width counterparts, eg
input = {"Hello", " ", "World"}
print(full(table.concat(input)))
and it will print "Hello World"
I tried it using this:
local encoding = [[ 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!゛#$%&()*+、ー。/:;〈=〉?@[\\]^_‘{|}~]]
function char(i)
return encoding:sub(i:len(),i:len())
end
function decode(t)
for i=1,#t do t[i]=char(t[i]) end
return table.concat(t)
end
function returns(word, word_eol)
print(char(word_eol[2]))
end
but that did not work
note: it is a plugin for hexchat that's why I have it as print(char(word_eol[2])))
Because when you hook a command in hexchat it spits out a table that is the command name, then what was entered after
If (string) = [[ 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!゛#$%&()*+、ー。/:;〈=〉?@[\]^_‘{|}~]], you're finding the n th character of (string), with n being the length of the character, which will always be one. If I understand correctly, this will do the job, by having a separate alphabet and matching the characters.
local encoding = [[ 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!゛#$%&()*+、ー。/:;〈=〉?@[]^_‘{|}~]]
local decoding = [[ 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&()*+,-./:;{=}?#[]^_'{|}~]]
function char(i)
local l = decoding:find(i,1,true)
return encoding:sub(l,l)
end
function decode(t)
for i=1,#t do t[i]=char(t[i]) end
return table.concat(t)
end
function returns(word, word_eol)
print(char(word_eol[2]))
end
function full(s)
return (s:gsub('.', function(c)
c = c:byte()
if c == 0x20 then
return string.char(0xE3, 0x80, 0x80)
elseif c >= 0x21 and c <= 0x5F then
return string.char(0xEF, 0xBC, c+0x60)
elseif c >= 0x60 and c <= 0x7E then
return string.char(0xEF, 0xBD, c+0x20)
end
end))
end

Sum of primes in a number - Lua

I'm trying to calculate the sum of the prime numbers in a given number. For instance, for the number 123456, the result will be 10 because 2+3+5 = 10.
I tried to write a code that does that in Lua but I had some issues.
First, here is the code:
function isPrime(num)
if(num == 1 or (num ~= 2 and num%2 == 0)) then
return false
end
for i=3, math.sqrt(num), 2 do
if(num%i == 0) then
return false
end
end
return true
end
function sumOfPrimes(num)
local sum = 0
for digit in string.gmatch(num,"%d") do
local prime = isPrime(digit)
if(isPrime(digit)) then
sum = sum + digit
end
print(digit)
end
return sum
end
function main()
print(sumOfPrimes(123456))
end
main()
It returnes 9 instead of 10. Another thing I've noticed is it adds 1 also to sum, but 1 isn't a prime. What's the problem here?
string.gmatch returns a string, you need to convert it to number before doing calculations
Btw, you are doing the prime validation twice on your loop.
This is a fixed version (returns 10 as expected):
...
function sumOfPrimes(num)
local sum = 0
for digit in string.gmatch(num, "%d") do
digit = tonumber(digit) --needed conversion
local prime_digit = isPrime(digit)
if prime_digit then
sum = sum + digit
end
end
return sum
end

Format string to number with minimum length in lua

For example I need number with minimum 3 digit
"512" --> 512
"24" --> 24.0
"5" --> 5.00
One option is write small function. Using answers here for my case it will be something like this
function f(value, w)
local p = math.ceil(math.log10(value))
local prec = value <= 1 and w - 1 or p > w and 0 or w - p
return string.format('%.' .. prec .. 'f', value)
end
print(f(12, 3))
But may be it is possible just using string.format() or any other simple way?
Ok, it seems this case beyond the string.format power. Thanks to #Schollii, this is my current variant
function f(value, w)
local p = math.ceil(math.log10(value))
local prec = value <= 1 and w - 1 or p > w and 0 or w - p
return string.format('%.' .. prec .. 'f', value)
end
print(f(12, 3))
There is no format code specifically for this since string.format uses printf minus a few codes (like * which would hace simplified the solution I give below). So you have to implement yourself, for example:
function f(num, w)
-- get number of digits before decimal
local intWidth = math.ceil(math.log10(num))
-- if intWidth > w then ... end -- may need this
local fmt='%'..w..'.' .. (w-intWidth) .. 'f'
return string.format(fmt, num)
end
print(f(12, 4))
print(f(12, 3))
print(f(12, 2))
print(f(512, 3))
print(f(24, 3))
print(f(5, 3))
You should probably handle case where integer part doesn't fit in field width given (return ceil or floor?).
You can't. Maximum you can reach - specify floating point precision or digit number, but you can't force output to be like your example. Lua uses C like printf with few limitations reference. Look here for full specifiers list link. Remember unsupported ones.
Writing a function would be the best and only solution, especially as your task looks strange, as it doesn't count decimal dot.

Resources