How would I undo the actions of string.gmatch for a certain section of string in lua - string

So I am using lua and splitting a string by spaces to write a sort of sub-language. And I am trying to have it not split anything inside parenthesis, I am already at the stage where I can detect whether there is parenthesis. But I want to reverse the gmatching of the string inside the parenthesis as I want to preserve the string contained within.
local function split(strng)
local __s={}
local all_included={}
local flag_table={}
local uncompiled={}
local flagged=false
local flagnum=0
local c=0
for i in string.gmatch(strng,'%S+') do
c=c+1
table.insert(all_included,i)
if(flagged==false)then
if(string.find(i,'%('or'%['or'%{'))then
flagged=true
flag_table[tostring(c)]=1
table.insert(uncompiled,i)
print'flagged'
else
table.insert(__s,i)
end
elseif(flagged==true)then
table.insert(uncompiled,i)
if(string.find(i,'%)' or '%]' or '%}'))then
flagged=false
local __=''
for i=1,#uncompiled do
__=__ .. uncompiled[i]
end
table.insert(__s,__)
print'unflagged'
end
end
end
return __s;
end
This is my splitting code

I would just not use gmatch for this at all.
local input = " this is a string (containg some (well, many) annoying) parentheses and should be split. The string contains double spaces. What should be done? And what about trailing spaces? "
local pos = 1
local words = {}
local last_start = pos
while pos <= #input do
local char = string.byte(input, pos)
if char == string.byte(" ") then
table.insert(words, string.sub(input, last_start, pos - 1))
last_start = pos + 1
elseif char == string.byte("(") then
local depth = 1
while depth ~= 0 and pos + 1 < #input do
local char = string.byte(input, pos + 1)
if char == string.byte(")") then
depth = depth - 1
elseif char == string.byte("(") then
depth = depth + 1
end
pos = pos + 1
end
end
pos = pos + 1
end
table.insert(words, string.sub(input, last_start))
for k, v in pairs(words) do
print(k, "'" .. v .. "'")
end
Output:
1 ''
2 'this'
3 'is'
4 'a'
5 'string'
6 '(containg some (well, many) annoying)'
7 'parentheses'
8 'and'
9 'should'
10 'be'
11 'split.'
12 'The'
13 'string'
14 'contains'
15 ''
16 'double'
17 ''
18 ''
19 'spaces.'
20 'What'
21 'should'
22 'be'
23 'done?'
24 'And'
25 'what'
26 'about'
27 'trailing'
28 'spaces?'
29 ''
Thinking about trailing spaces and other such problems is left as an exercise for the reader. I tried to highlight some of the possible problems with the example that I used. Also, I only looked at one kind of parenthesis since I do not want to think how this (string} should be ]parsed.
Oh and if nested parenthesis are not a concerned: Most of the code above can be replaced with a call to string.find(input, ")", pos, true) to find the closing parenthesis.
Please note that you cannot or or and patterns as attempted in your code.
"%(" or "%[" equals "%("
Lua will interpret that expression left to right. "%( is a true value Lua will reduce the expression to "%(", which logically is the same as the full expression.
So string.find(i,'%('or'%['or'%{') will only find ('s in i.

As a similar but slightly different approach to Uli's answer, I would first split by parentheses. Then you can split the the odd-numbered fields on whitespace:
split = require("split") -- https://luarocks.org/modules/telemachus/split
split__by_parentheses = function(input)
local fields = {}
local level = 0
local field = ""
for i = 1, #input do
local char = input:sub(i, i)
if char == "(" then
if level == 0 then
-- add non-parenthesized field to list
fields[#fields+1] = field
field = ""
end
level = level + 1
end
field = field .. char
if char == ")" then
level = level - 1
assert(level >= 0, 'Mismatched parentheses')
if level == 0 then
-- add parenthesized field to list
fields[#fields+1] = field
field = ""
end
end
end
assert(level == 0, 'Mismatched parentheses')
fields[#fields+1] = field
return fields
end
input = " this is a string (containg some (well, many) annoying) parentheses and should be split. The string contains double spaces. What should be done? And what about trailing spaces? "
fields = split__by_parentheses(input)
for i, field in ipairs(fields) do
print(("%d\t'%s'"):format(i, field))
if i % 2 == 1 then
for j, word in ipairs(split.split(field)) do
print(("\t%d\t%s"):format(j, word))
end
end
end
outputs
1 ' this is a string '
1
2 this
3 is
4 a
5 string
6
2 '(containg some (well, many) annoying)'
3 ' parentheses and should be split. The string contains double spaces. What should be done? And what about trailing spaces? '
1
2 parentheses
3 and
4 should
5 be
6 split.
7 The
8 string
9 contains
10 double
11 spaces.
12 What
13 should
14 be
15 done?
16 And
17 what
18 about
19 trailing
20 spaces?
21

Related

Python Logical Operators find the right way if(and and or or)

Can not find the mistake in logical operators, may be someone can give me a hint how to put AND OR OR.
Problem is with if data and data and data and (or or or)
in () > I need to accept code:
contains capital letters, then the number of capitals must be odd
have at least 4 letters (independent of case)
so it means: UPPER + LOWER >= 4 or UPPER >= 4 or LOWER >= 4
output should be:
checker_code("Dfgh#88$")
True
def checker_code(security_code):
data = {'upper':0, 'lower':0, 'spec':0, 'digit':0, 'sum':0}
spec_charact = ['!','#','#','$','%','^','&','*','(',')','?',',','.']
if len(security_code) < 8 or len(security_code) > 30:
return False
for i in security_code:
if any(i.isupper() for i in security_code):
data['upper'] = data['upper'] + 1
if i.islower():
data['lower'] = data['lower'] + 1
if i in spec_charact:
data['spec'] = data['spec'] + 1
if i.isdigit():
data['digit'] = data['digit'] + 1
if i.isdigit():
data['sum'] = data['sum'] + int(i)
if(data['upper'] % 2 !=0 and data['spec'] >= 2 and data['digit'] >= 2 and data['sum'] % 2 == 0 and (data['upper'] + data['lower'] >= 4 or data['upper'] >= 4 or case['lower'] >= 4)):
return True
else:
return False
Change your line
if any(i.isupper() for i in security_code):
to this:
if i.isupper():
Since you are already iterating for i in security_code in your outer for loop, it is redundant to do it again in your first if-statement. I think your code is applying whether the 1st character is upper across all letters, so it thinks your string of 8 characters has 8 upper-case characters since "D" is uppercase
Your test if any(i.isupper() for i in security_code): is adding to data["upper"] everytime through the loop because you are checking all of security_code at every iteration and since it does have a uppercase letter, it adds to the count.
Instead, just do if i.issuper(): to only check the current element of the security code.

Iterate through a string using split

I essentially have two list containing strings:
com = ['746365', '6365']
dec = ['6d955s2359d757bb40d0cf36bd7a35662d8b3']
I take the length of the first element in list a '746365' and cut list b into the same length as the first element, (len('746365') = 6) and the result of b is '6d955s'. I now wish to move along the element in b by one place until i reach the end ('62d8b3').
I currently have:
count = 0
for a in com:
for b in dec:
print(com.index(a), a)
length_of = len(a)
print(b[0 + count:length_of + count])
count = count + 1
This doesn't work. However if I remove the count parts and leave whats displayed beneath it works but I can't get it to move along by one
for a in com:
for b in dec:
print(com.index(a), a)
length_of = len(a)
print(b[0:length_of])
how can I adjust this code so that I print then move along by one and print the next?
The initial result should be:
6d955s d955s2 955s23 etc etc..
once the end of dec has been reached, it'll move onto the next value in com.
Thanks.
Try this:
for a in com:
for b in dec:
for i in range(0,len(b)-len(a)+1):
clipped_str = b[i:i+len(a)]
print(clipped_str)
Try this code:
start = 0
for c_element in com:
current_length = len(c_element)
end = start + current_length
for d_element in dec:
for _ in range(len(d_element) - current_length + 1):
print(d_element[start:end])
start += 1
end += 1
else:
start = 0

To convert upper case to lower case of same word in qbasic

Hi there i want to get idea or code for converting uppercase into lowercase and lowercase into uppercase of same word for eg: convert StAcKOVERfloW to sTaCkoverFLOw please can any one give me idea or the code for qbasic programming language
The way to solve this task is to process the characters in the string one after the other. A basic FOR NEXT loop accomplishes this:
FOR cpos% = 1 TO LEN(text$)
char$ = MID$(text$, cpos%, 1) ' Extracts 1 character at the current position
...
NEXT
QBasic has the UCASE and LCASE functions that will convert their string argument into uppercase and lowercase respectively. If the string we deal with consists of a single word with nothing but uppercase and lowercase characters, next code snippet will produce the desired result:
text$ = "StAcKOVERfloW"
PRINT text$;
FOR cpos% = 1 TO LEN(text$)
char$ = MID$(text$, cpos%, 1)
IF char$ >= "A" AND char$ <= "Z" THEN
MID$(text$, cpos%) = LCASE$(char$)
ELSE
MID$(text$, cpos%) = UCASE$(char$)
END IF
NEXT
PRINT " --> "; text$
We can write the above code without using UCASE or LCASE. Then we will be dealing with the ASCII codes of the characters. The uppercase characters "A" to "Z" have ASCII codes 65 to 90, and the lowercase characters "a" to "z" have ASCII codes 97 to 122. These ranges are 32 apart and that's an important number for the conversion from one in the other.
Next version works this way:
text$ = "StAcKOVERfloW"
PRINT text$;
FOR cpos% = 1 TO LEN(text$)
char$ = MID$(text$, cpos%, 1)
IF char$ >= "A" AND char$ <= "Z" THEN
MID$(text$, cpos%) = CHR$(ASC(char$) + 32) ' Upper to Lower means + 32
ELSE
MID$(text$, cpos%) = CHR$(ASC(char$) - 32) ' Lower to Upper means - 32
END IF
NEXT
PRINT " --> "; text$
This move to using the ASCII code will allow us to write the conversion in a single line. It's the XOR operator that does the heavy lifting here. We no longer need to decide about adding 32 or subtracting 32. The exclusive OR does the toggle for us:
text$ = "StAcKOVERfloW"
PRINT text$;
FOR cpos% = 1 TO LEN(text$)
MID$(text$, cpos%) = CHR$(ASC(MID$(text$, cpos%, 1)) XOR 32)
NEXT
PRINT " --> "; text$
For a general solution to the problem of toggling the case of characters, we have to take into consideration that the user at the keyboard could be inputting an empty text, and that the text could turn out to contain characters that are not uppercase or lowercase letters.
To guard against an empty text, we can replace FOR NEXT by WHILE WEND where the condition is such that the loop is skipped if the current position cpos% does not exist in the string text$.
Because all modification to the string happens conditionally, there's no danger of modifying anything else than letters.
INPUT ; "Text : ", text$
cpos% = 1
WHILE cpos% <= LEN(text$)
ascii% = ASC(MID$(text$, cpos%, 1))
ucase% = ascii% AND &HDF
IF ucase% >= 65 AND ucase% <= 90 THEN
MID$(text$, cpos%) = CHR$(ascii% XOR 32)
END IF
cpos% = cpos% + 1
WEND
PRINT " --> "; text$
The code is 'optimized' in the way that it favors using numerical operations over using string operations. In general it is true that string assignments take a relatively long time.
The code first converts the ASCII code to uppercase so as to simplify the IF from
IF (ascii% >= 65 AND ascii% <= 90) or (ascii% >=97 and ascii% <=122) THEN
to
ucase% = ascii% AND &HDF
IF ucase% >= 65 AND ucase% <= 90 THEN

Evaluate equation but ignore order of mathematical operations and parentheses

I'm trying to write a function that ignores the order of mathematical operations and parentheses. The function just evaluates operators from left to right. (for +-*/^)
Example 1: 5 - 3 * 8^2 returns 256.
Example 2: 4 / 2 - 1^2 + (5*3) returns 18.
Here's what I did:
function out = calc(num)
[curNum, num] = strtok(num, '+-*/^');
out = str2num(curNum);
while ~isempty(num)
sign = num(1);
[curNum, num] = strtok(num, '+-*/^');
switch sign
case '+'
out = out + str2num(curNum);
case'-'
out = out - str2num(curNum);
case '*'
out = out.*str2num(curNum);
case '/'
out = out./str2num(curNum);
case '^'
out = out.^str2num(curNum);
end
end
end
My function doesn't ignore the left to right rule. How do I correct for this?
Your first example fails because you are splitting the string with the +-*/ delimiters, and you omitted the ^. You should change this to +-*/^ in lines 2 and 6.
Your second example fails because you aren't telling your program how to ignore the ( and ) characters. You should strip them before you enter the switch statement.
curNum = strrep(curNum,'(','')
curNum = strrep(curNum,')','')
switch sign
...
This is a way without any switch statements.
str = '4 / 2 - 1^2 + (5*3)'
%// get rid of spaces and brackets
str(regexp(str,'[ ()]')) = []
%// get numbers
[numbers, operators] = regexp(str, '\d+', 'match','split')
%// get number of numbers
n = numel(numbers);
%// reorder string with numbers closing brackets and operators
newStr = [numbers; repmat({')'},1,n); operators(2:end)];
%// add opening brackets at the beginning
newStr = [repmat('(',1,n) newStr{:}]
%// evaluate
result = eval(newStr)
str =
4/2-1^2+5*3
newStr =
((((((4)/2)-1)^2)+5)*3)
result =
18

Reconstructing string after parsing and modifying numbers from it in Lua

I have strings like the following (quotation marks are only showing that there may be leading and trailing whitespaces), and I need to extract the numbers from the string, which may be integer or float, negative or non-negative.
" M0 0.5 l 20 0 0 20.34 -20 0q10 0 10 10 t 10 10 54.333 10 h -50 z"
After extracting the numbers I have to multiply them with random numbers, which the following function produces.
-- returns a random float number between the specified boundaries (floats)
function random_in_interval(lower_boundary, upper_boundary)
return ((math.random() * (upper_boundary - lower_boundary)) + lower_boundary)
end
At the end reconstruct the string with the characters and multiplied numbers in the correct order. Also all this has to happen in Lua, and I can't use any external libraries, since this will be used in a LuaTeX compiled document.
The case of the characters must not be changed, characters may or may not have spaces before and after them, but in the output it would be nice if there were. I have already written a helper function to add whitespace before and after characters, however when a character has a whitespace before or after it this will introduce multiple whitespaces, which I cannot solve at the moment.
-- adds whitespace before and after characters
function pad_characters(str)
local padded_str = ""
if #str ~= 0 then
for i = 1, #str, 1 do
local char = string.sub(str, i, i)
if string.match(char, '%a') ~= nil then
padded_str = padded_str .. " " .. char .. " "
else
padded_str = padded_str .. char
end
end
end
-- remove leading and trailing whitespaces
if #padded_str ~= 0 then
padded_str = string.match(padded_str, "^%s*(.-)%s*$")
end
return padded_str
end
I have no idea how I could parse, modify the numeric parts of the string, and reconstruct it in the correct order, and doing this in pure Lua without using any external libraries.
Try this. Adapt as needed.
s=" M0 0.5 l 20 0 0 20.34 -20 0q10 0 10 10 t 10 10 54.333 10 h -50 z"
print(s:gsub("%S+",function (x)
local y=tonumber(x)
if y then
return y*math.random()
else
return x
end
end))
I couldn't come up with anything better than processing each character, and decide if it is a number (digit, decimal point, negative sign) or anything else and act according to it.
-- returns a random float number between the specified boundaries (floats)
function random_in_interval(lower_boundary, upper_boundary)
return ((math.random() * (upper_boundary - lower_boundary)) + lower_boundary)
end
-- note: scaling is applied before randomization
function randomize_and_scale(str, scale_factor, lower_boundary, upper_boundary)
local previous_was_number = false
local processed_str = ""
local number = ""
for i = 1, #str, 1 do
local char = string.sub(str, i, i)
if previous_was_number then
if string.match(char, '%d') ~= nil or
char == "." then
number = number .. char
else -- scale and randomize
number = number * scale_factor
number = number * random_in_interval(lower_boundary, upper_boundary)
processed_str = processed_str .. number .. char
number = ""
previous_was_number = false
end
else
if string.match(char, '%d') ~= nil or
char == "-" then
number = number .. char
previous_was_number = true
else
processed_str = processed_str .. char
-- apply stuff
previous_was_number = false
end
end
end
return processed_str
end

Resources