Is there any way to implement algorithm using ONLY regular expressions? - python

I have string with only + and -, plus increases some variable, minus respectively decreases it. I should check if variable will be less than 0 or greater than N during processing any symbol of input string.
For example I have input:
N = 10
string = "+++++++++---+-+-+"
Output:
True
Input:
N = 3
string = "+-+-+-++-+++--"
Output:
False
Python solution is:
def check(string, N):
accumulator = 0
for ch in string:
if ch == '+':
accumulator += 1
elif ch == '-':
accumulator -= 1
if accumulator < 0 or accumulator > N:
return False
return True
But I need to implement this using ONLY regular expressions, like this:
def check(string, N):
regex = r'^$' # <-- regex is here
return bool(re.match(regex, string))
Any ideas?

Related

Removing substring from string in Python

I want to write a function that takes 2 inputs: a string and a substring, then the function will remove that part of the substring from the string.
def remove_substring(s, substr):
"""(str, str) -> NoneType
Returns string without string substr
remove_substring_from_string("Im in cs", "cs")
Im in
"""
other_s = ''
for substr in s:
if substr in s:
continue
How do I continue on from here? Assuming my logic is sound.
Avoiding the use of Python functions.
Method 1
def remove_substring_from_string(s, substr):
'''
find start index in s of substring
remove it by skipping over it
'''
i = 0
while i < len(s) - len(substr) + 1:
# Check if substring starts at i
if s[i:i+len(substr)] == substr:
break
i += 1
else:
# break not hit, so substr not found
return s
# break hit
return s[:i] + s[i+len(substr):]
Method 2
If the range function can be used, the above can be written more compactly as follows.
def remove_substring_from_string(s, substr):
'''
find start index in s of substring
remove it by skipping over it
'''
for i in range(len(s) - len(substr) + 1):
if s[i:i+len(substr)] == substr:
break
else:
# break not hit, so substr not found
return s
return s[:i] + s[i+len(substr):]
Test
print(remove_substring_from_string("I have nothing to declare except my genuis", " except my genuis"))
# Output: I have nothing to declare'
This approach is based on the KMP algorithm:
def KMP(s):
n = len(s)
pi = [0 for _ in range(n)]
for i in range(1, n):
j = pi[i - 1]
while j > 0 and s[i] != s[j]:
j = pi[j - 1]
if s[i] == s[j]:
j += 1
pi[i] = j
return pi
# Removes all occurences of t in s
def remove_substring_from_string(s, t):
n = len(s)
m = len(t)
# Calculate the prefix function using KMP
pi = KMP(t + '\x00' + s)[m + 1:]
r = ""
i = 0
while i + m - 1 < n: # Before the remaining string is smaller than the substring
if pi[i + m - 1] == m: # If the substring is here, skip it
i += m
else: # Otherwise, add the current character and move to the next
r += s[i]
i += 1
# Add the remaining string
r += s[i:]
return r
It runs in O(|s| + |t|), but it has a few downsides:
The code is long and unintuitive.
It requires that there is no null (\x00) in the input strings.
Its constant factors are pretty bad for short s and t.
It doesn't handle overlapping strings how you might want it: remove_substring_from_string("aaa", "aa") will return "a". The only guarantee made is that t in remove_substring_from_string(s, t) is False for any two strings s and t.
A C++ example and further explanation for the KMP algorithm can be found here. The remove_substring_from_string function then only checks if the entire substring is matched at each position and if so, skips over the substring.
I would do this using re.
import re
def remove_substring(s, substr):
# type: (str, str) -> str
return re.subn(substr, '', s)[0]
remove_substring('I am in cs', 'cs')
# 'I am in '
remove_substring('This also removes multiple substr that are found. Even if that substr is repeated like substrsubstrsubstr', 'substr')
# 'This also removes multiple that are found. Even if that is repeated like '
def remove_substring(s, substr):
while s != "":
if substr in s:
s = s.replace(substr, "")
else:
return s
if s == "":
return "Empty String"
The idea here is that we replace all occurrences of substr within s, by replacing the first instance of substr and then looping until we are done.

How can i remove the break from find_frequent(s) code since our teacher told us we can't use it on the test and I'm trying to practice not using it?

I wrote this code, and I'm struggling to replace using break since it says in the homework that we are not allowed to use continue/break statements in our loops.
The code's goal is:
finds the character that appears most frequently in the input parameter string and returns it. For Example, if the string is "Canada day" the function returns the string "a"
If there are two characters or more with the same frequency, the function should return the first of many values with the same frequency.
def find_frequent(s):
"""
-------------------------------------------------------
description
Use:
-------------------------------------------------------
Parameters:
name - description (type)
Returns:
name - description (type)
------------------------------------------------------
"""
L = []
count = 0
char = 0
i = 0
words = True
while i < 1 and words:
x = s[i]
for j in range(len(L)):
if x == L[j]:
words = False
L[j + 1] = L[j + 1] + 1
else:
L.append(x)
L.append(1)
for i in range(1, len(L), 2):
if L[i] > count:
count = L[i]
char = L[i - 1]
return char
the output should look like this
`Enter a string: Hello Hi`
output should be
`Most frequent characters: H`
I'm getting this output
Enter a string: canada
Most frequent character: c
You can replace the break statement in a for loop with a while loop.
print("using for loop + break")
for i in range(0, 5):
print(i)
if i == 3:
break
print("using while")
i = 0
keep_searching = True
while i < 5 and keep_searching:
print(i)
if i == 3:
keep_searching = False
i += 1
The output is:
using for loop + break
0
1
2
3
using while
0
1
2
3
I think you can figure it out from here, but if you need help with finding the most frequent character (a different issue from the break), take a look here and here.
No need for a break if you don't use a loop in the first place :-)
def find_frequent(s):
return max(s, key=s.count)
(I'm actually serious... forbidding break sounds to me like your teacher didn't want you to write it with such nested loops.)
Or if you want to teach your teacher a lesson (the lesson being that they shouldn't forbid stuff), you could fake the break:
for i in range(0, len(s), 1):
x = s[i]
it = iter(range(len(L))) # make it an iterator
for j in it:
if x == L[j]:
L[j + 1] = L[j + 1] + 1
*it, # exhaust the iterator
it = None # make it false
if it: # instead of `else`
L.append(x)
L.append(1)

Addition and Subtraction

I need help with returning the value of expression(expression being the parameter of the function).
This is what i have tried so far. It's just an example with a random equation, my plan would be to understand how to solve it correctly so i could later on tranform it into a function
sum = 0
eq = '2+4-5'
string = ""
for x in eq:
if x in ('+', '-'):
if x == '+':
sum += int(string)
elif x == "-":
sum -= int(string)
string = ""
else:
string += x
sum += int(string)
print(sum)
"1+2" => 3 # input = "1+2" and the output of the function would be 3
"-1+21" => 20
"+1-1" => 0
Look up the eval() function:
>> eq = "2+4-5"
>> eval(eq)
1
As said in the comments eval() evaluate the string passed as Python code which is potentially dangerous.
Try This one:
import re
eq = '+1-1'
ls = [int(i) for i in re.findall('[-+]?[0-9]+', eq)]
res = sum(ls)
print(res)

How many operations to transform RPN string into valid RPN string?

I failed an interview earlier this morning on this question, and haven't been able to figure out why. Can anyone help me out?
An expression consisting of operands and binary operators can be written in Reverse Polish Notation (RPN) by writing both the operands followed by the operator. For example, 3 + (4 * 5) can be written as "3 4 5 * +".
You are given a string consisting of x's and *'s. x represents an operand and * represents a binary operator. It is easy to see that not all such strings represent valid RPN expressions. For example, the "x*x" is not a valid RPN expression, while "xx*" and "xxx**" are valid expressions. What is the minimum number of insert, delete and replace operations needed to convert the given string into a valid RPN expression?
5
x
xx*
xxx**
*xx
xx*xx**
OUTPUT
0
0
0
2
0
Code so far:
import fileinput
def solution (rpn):
xs = 0
numReplaces = 0
numDeletes = 0
numInserts = 0
for i in xrange(len(rpn)):
if rpn[i] == 'x':
xs += 1
elif rpn[i] == '*':
if xs > 1:
xs -= 1
elif xs == 1:
if numDeletes > 0:
numReplaces += 1
numDeletes -= 1
else:
if i == len(rpn)-1:
numInserts += 1
else:
numDeletes += 1
else:
if numDeletes > 1:
numDeletes -= 2
numReplaces += 2
else:
numDeletes += 1
while xs > 1:
if xs > 2:
numReplaces += 1
xs -= 2
if xs == 2:
numInserts += 1
xs -= 1
return numReplaces + numDeletes + numInserts
first = True
for line in fileinput.input():
if first:
numCases = int(line)
first = False
else:
print solution(line)
I think the way to start is that RPM evaluation can be performed easily by maintaining a stack of operands. For a valid input string, when you hit an operator, you pop the last two values off the stack, apply the operator and push the result back on to the stack.
Therefore, we need to find the value added by each of the "fixes":
Insert
Operand: you hit an operator, and there is only one item on the stack
Operator: You finish the string and there are multiple items left on the stack
Delete
Operand: you are at the end of the string. Adding operators will have the same result
Operator: there is only one item on the stack, adding an operand will have the same result. If the stack is empty, delete the operator
Replace
Operator -> operand: There is only one operand on the stack
Operand -> operator: Here be dragons. I believe that this will be useful only when you're out of operators, meaning the stack size is > 1; unfortunately, we don't know if these are direct operands or the result of operations, so we'll just add n-1 operators to condense the stack into a result.
I'm not 100% sure on these, but it sounds like any error condition can be handled by any of these, at equal cost, so:
def count_errors(input_):
def tokenize(input_):
''' for our purposes, each character is a token '''
for char in input_:
yield char
def is_operator(val):
return val == '*'
def is_operand(val):
return val == 'x'
stack = []
error = 0
for token in tokenize(input_):
if is_operand(token):
stack.append(token)
elif is_operator(token):
if len(stack) >= 2:
stack.pop()
stack.pop()
stack.append('x')
elif len(stack) == 1:
stack.pop()
stack.append('x')
errors += 1
else:
errors += 1
if len(stack):
return errors + len(stack) - 1
else:
return errors + 1

Calculator Subtraction leads to infinite loop

I'm working on a calculator which will accept input from the user.
It has to solve expressions such as:
1+38*(!2)-5%37
I have been working on the addition and the subtraction but I got into a problem.
I have a loop that is looking for "+" or "-" symbols.
For the "+" it works, but for the "-", whenever I'm solving an expression like
1-38
It gets me into an infinite loop since the result of that expression is
-37
and the loop keeps recognizing the "-" symbol as a subtraction, but as negative 37.
How do I solve this issue?
def symbols_exist(exp, symbols_list):
""" Gets an expression string and a symbols list and returns true if any symbol
exists in the expression, else returns false. """
for s in symbols_list:
if s in exp:
return True
return False
def BinaryOperation(exp, idx):
""" Gets an expression and an index of an operator and returns a tuple with (first_value, operator, second_value). """
first_value = 0
second_value = 0
#Get first value
idx2 = idx -1
while (idx2 > 0) and (exp[idx2] in string.digits):
idx2 -=1
first_value = exp[idx2:idx]
#Get second value
idx2 = idx +1
while (idx2 < len(exp)) and (exp[idx2] in string.digits):
idx2 += 1
second_value = exp[idx+1:idx2]
return (first_value, exp[idx], second_value)
def solve(exp):
if not symbols_exist(exp, all_symbols):
return exp
idx = 0
while idx < len(exp):
if exp[idx] in string.digits:
#Digit
idx +=1
elif exp[idx] in ("+", "-"):
#Addition and Subtraction
sub_exp = BinaryOperation(exp, idx)
if sub_exp[1] == "+":
value = int(sub_exp[0]) + int(sub_exp[2])
else:
value = int(sub_exp[0]) - int(sub_exp[2])
value = str(value)
exp = exp.replace(''.join(sub_exp), value)
print exp
return solve(exp)
A possible solution that combines the three functions in the original example. (EDIT: just realised the original answer I posted could be simplified quite a bit)
all_symbols = '+-'
def solve(expres):
lhs, symbol, rhs = expres[0], None, ''
for ch in expres[1:]:
if symbol:
rhs += ch
elif ch in all_symbols:
symbol = ch
else:
lhs += ch
if symbol is '+':
return int(lhs) + solve(rhs)
if symbol is '-':
return int(lhs) - solve(rhs)
return int(expres)
print solve('1+5')
And another type of solution that may be useful to consider
operations = [
('+', lambda a, b: a + b),
('-', lambda a, b: a - b)
]
def solve(exp):
for symbol, operation in operations:
p = exp.rfind(symbol)
if p > 0:
return operation(solve(exp[:p]), solve(exp[p + 1:]))
return int(exp)

Categories

Resources