"translating" One character to another in lua - 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

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.

Lua: Type of a character

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

Lua table.concat

Is there a way to use the arg 2 value of table.concat to represent the current table index?
eg:
t = {}
t[1] = "a"
t[2] = "b"
t[3] = "c"
X = table.concat(t,"\n")
desired output of table concat (X):
"1 a\n2 b\n3 c\n"
Simple answer : no.
table.concat is something really basic, and really fast.
So you should do it in a loop anyhow.
If you want to avoid excessive string concatenation you can do:
function concatIndexed(tab,template)
template = template or '%d %s\n'
local tt = {}
for k,v in ipairs(tab) do
tt[#tt+1]=template:format(k,v)
end
return table.concat(tt)
end
X = concatIndexed(t) -- and optionally specify a certain per item format
Y = concatIndexed(t,'custom format %3d %s\n')
I don't think so: how would you tell it that the separator between keys and values is supposed to be a space, for example?
You can write a general mapping function to do what you'd like:
function map2(t, func)
local out = {}
for k, v in pairs(t) do
out[k] = func(k, v)
end
return out
end
function joinbyspace(k, v)
return k .. ' ' .. v
end
X = table.concat(map2(t, joinbyspace), "\n")
No. But there is a work around:
local n = 0
local function next_line_no()
n = n + 1
return n..' '
end
X = table.concat(t,'\0'):gsub('%f[%Z]',next_line_no):gsub('%z','\n')
function Util_Concat(tab, seperator)
if seperator == nil then return table.concat(tab) end
local buffer = {}
for i, v in ipairs(tab) do
buffer[#buffer + 1] = v
if i < #tab then
buffer[#buffer + 1] = seperator
end
end
return table.concat(buffer)
end
usage tab is where the table input is and seperator be both nil or string (if it nil it act like ordinary table.concat)
print(Util_Concat({"Hello", "World"}, "_"))
--Prints
--Hello_world

Case-insensitive Lua pattern-matching

I'm writing a grep utility in Lua for our mobile devices running Windows CE 6/7, but I've run into some issues implementing case-insensitive match patterns. The obvious solution of converting everything to uppercase (or lower) does not work so simply due to the character classes.
The only other thing I can think of is converting the literals in the pattern itself to uppercase.
Here's what I have so far:
function toUpperPattern(instr)
-- Check first character
if string.find(instr, "^%l") then
instr = string.upper(string.sub(instr, 1, 1)) .. string.sub(instr, 2)
end
-- Check the rest of the pattern
while 1 do
local a, b, str = string.find(instr, "[^%%](%l+)")
if not a then break end
if str then
instr = string.sub(instr, 1, a) .. string.upper(string.sub(instr, a+1, b)) .. string.sub(instr, b + 1)
end
end
return instr
end
I hate to admit how long it took to get even that far, and I can still see right away there are going to be problems with things like escaped percent signs '%%'
I figured this must be a fairly common issue, but I can't seem to find much on the topic.
Are there any easier (or at least complete) ways to do this? I'm starting to go crazy here...
Hoping you Lua gurus out there can enlighten me!
Try something like this:
function case_insensitive_pattern(pattern)
-- find an optional '%' (group 1) followed by any character (group 2)
local p = pattern:gsub("(%%?)(.)", function(percent, letter)
if percent ~= "" or not letter:match("%a") then
-- if the '%' matched, or `letter` is not a letter, return "as is"
return percent .. letter
else
-- else, return a case-insensitive character class of the matched letter
return string.format("[%s%s]", letter:lower(), letter:upper())
end
end)
return p
end
print(case_insensitive_pattern("xyz = %d+ or %% end"))
which prints:
[xX][yY][zZ] = %d+ [oO][rR] %% [eE][nN][dD]
Lua 5.1, LPeg v0.12
do
local p = re.compile([[
pattern <- ( {b} / {escaped} / brackets / other)+
b <- "%b" . .
escaped <- "%" .
brackets <- { "[" ([^]%]+ / escaped)* "]" }
other <- [^[%]+ -> cases
]], {
cases = function(str) return (str:gsub('%a',function(a) return '['..a:lower()..a:upper()..']' end)) end
})
local pb = re.compile([[
pattern <- ( {b} / {escaped} / brackets / other)+
b <- "%b" . .
escaped <- "%" .
brackets <- {: {"["} ({escaped} / bcases)* {"]"} :}
bcases <- [^]%]+ -> bcases
other <- [^[%]+ -> cases
]], {
cases = function(str) return (str:gsub('%a',function(a) return '['..a:lower()..a:upper()..']' end)) end
, bcases = function(str) return (str:gsub('%a',function(a) return a:lower()..a:upper() end)) end
})
function iPattern(pattern,brackets)
('sanity check'):find(pattern)
return table.concat({re.match(pattern, brackets and pb or p)})
end
end
local test = '[ab%c%]d%%]+ o%%r %bnm'
print(iPattern(test)) -- [ab%c%]d%%]+ [oO]%%[rR] %bnm
print(iPattern(test,true)) -- [aAbB%c%]dD%%]+ [oO]%%[rR] %bnm
print(('qwe [%D]% O%r n---m asd'):match(iPattern(test, true))) -- %D]% O%r n---m
Pure Lua version:
It is necessary to analyze all the characters in the string to convert it into a correct pattern because Lua patterns do not have alternations like in regexps (abc|something).
function iPattern(pattern, brackets)
('sanity check'):find(pattern)
local tmp = {}
local i=1
while i <= #pattern do -- 'for' don't let change counter
local char = pattern:sub(i,i) -- current char
if char == '%' then
tmp[#tmp+1] = char -- add to tmp table
i=i+1 -- next char position
char = pattern:sub(i,i)
tmp[#tmp+1] = char
if char == 'b' then -- '%bxy' - add next 2 chars
tmp[#tmp+1] = pattern:sub(i+1,i+2)
i=i+2
end
elseif char=='[' then -- brackets
tmp[#tmp+1] = char
i = i+1
while i <= #pattern do
char = pattern:sub(i,i)
if char == '%' then -- no '%bxy' inside brackets
tmp[#tmp+1] = char
tmp[#tmp+1] = pattern:sub(i+1,i+1)
i = i+1
elseif char:match("%a") then -- letter
tmp[#tmp+1] = not brackets and char or char:lower()..char:upper()
else -- something else
tmp[#tmp+1] = char
end
if char==']' then break end -- close bracket
i = i+1
end
elseif char:match("%a") then -- letter
tmp[#tmp+1] = '['..char:lower()..char:upper()..']'
else
tmp[#tmp+1] = char -- something else
end
i=i+1
end
return table.concat(tmp)
end
local test = '[ab%c%]d%%]+ o%%r %bnm'
print(iPattern(test)) -- [ab%c%]d%%]+ [oO]%%[rR] %bnm
print(iPattern(test,true)) -- [aAbB%c%]dD%%]+ [oO]%%[rR] %bnm
print(('qwe [%D]% O%r n---m asd'):match(iPattern(test, true))) -- %D]% O%r n---m

Resources