Find bracket which are not closed without using regex in python - python

I am trying to find out if any bracket is not closed without using regex, this is what I am trying but it is failed when the string are like "re(d))()(()"
def bracket(str):
return [0,1][str.count(')') == str.count('(')]
s = "re(d))()(()"
print bracket(s)
Is there any better way to do it.

Something like this?
def check_brackets(s):
counter = 0
for chr in s:
if chr == "(":
counter += 1
elif chr == ")":
counter -= 1
if counter < 0:
return False
return counter == 0
EDIT: Here's how you can do that with many different bracket types:
BRACKETS = ("()", "[]", "{}")
def check_brackets(s):
counter = []
for chr in s:
for br in BRACKETS:
open = br[0]
close = br[1]
if chr == open:
counter.append(open)
break
elif chr == close:
try:
last_br = counter.pop()
except IndexError:
return False
if last_br != open: # ensures that the end matches the beginnig
return False
return not bool(counter)
Note that it will mark ([)] as invalid (which is as it should be).

Using the approach from Shunting-yard algorithm:
from collections import deque
def solve(s):
queue = deque()
for c in s:
if c == ')':
if queue:
queue.pop()
continue
return False
elif c == '(':
queue.append(c)
return not bool(queue)
Demo:
>>> solve("re(d))()(()")
False
>>> solve("(re(d)()())")
True
>>> solve("(re(d)()((())))")
True
>>> solve(")))(((")
False

In [44]: from collections import deque
...: def solve(s):
...: queue = deque()
...: for c in s:
...: if c == ')':
...: if queue:
...: queue.pop()
...: else:
...: return False
...: elif c == '(':
...: queue.append(c)
...: return not bool(queue)
...:
In [45]: print solve('()'), solve('())'), solve('re(d))()(()')
True False False
it's important to check if the deque being empty when a ')' comes

Related

Using Python, how to print output string as -> aaa3bb2c1ddddd5 when Input string is aaabbcddddd

Using Python, how to print output string as -> aaa3bb2c1ddddd5 when Input string is aaabbcddddd
I want to concatenate actual character value and number of times a character is repeated in a string
def mycode(myString):
lenstr = len(myString)
print('length of string is '+str(lenstr));
for ele in myString:
count=0
for character in myString:
if character == ele:
count = count+1
totalstr = ele+str(count)
return totalstr
If the string is always sorted and grouped together like that, then you can use a collections.Counter to do it.
from collections import Counter
inp = "aaabbcddddd"
counter = Counter(inp)
out = "".join(k * v + str(v) for k,v in counter.items())
Or in one line:
print(''.join(k * v + str(v) for k,v in Counter(inp).items()))
Output:
aaa3bb2c1ddddd5
Or you can do it manually:
inp = "aaabbcddddd"
last = inp[0]
out = inp[0]
count = 1
for i in inp[1:]:
if i == last:
count += 1
else:
out += str(count)
count = 1
last = i
out += i
out += str(count)
print(out)
Here is a one line solution using a regex replacement with callback:
inp = "aaabbcddddd"
output = re.sub(r'((\w)\2*)', lambda m: m.group(1) + str(len(m.group(1))), inp)
print(output) # aaa3bb2c1ddddd5
Another one-liner:
import itertools
test = 'aaabbcddddd'
out = ''.join(f"{(g := ''.join(ig))}{len(g)}" for _, ig in itertools.groupby(test))
assert out == 'aaa3bb2c1ddddd5'
def char_counter_string(string):
prev_char = None
char_counter = 0
output = ''
for char_index in range(len(string)+1):
if char_index == len(string):
output += str(char_counter)
break
if string[char_index] != prev_char and prev_char is not None:
output += str(char_counter)
char_counter = 0
output += string[char_index]
char_counter += 1
prev_char = string[char_index]
return output
if __name__ == '__main__':
print(char_counter_string('aaabbcddddd'))
you can do like..
Code:
Time Complexity: O(n)
input_string="aaabbcddddd"
res=""
count=1
for i in range(1, len(input_string)):
if input_string[i] == input_string[i-1]:
count += 1
else:
res+=input_string[i-1]*count + str(count)
count = 1
res+=input_string[-1]*count + str(count)
print(res) #aaa3bb2c1ddddd5
Here's another way, ...
Full disclosure: ... as long as the run of characters is 10 or less, it will work. I.e., if there are 11 of anything in row, this won't work (the count will be wrong).
It's just a function wrapping a reduce.
from functools import reduce
def char_rep_count(in_string):
return reduce(
lambda acc, inp:
(acc[:-1]+inp+str(int(acc[-1])+1))
if (inp==acc[-2])
else (acc+inp+"1"),
in_string[1:],
in_string[0]+"1"
)
And here's some sample output:
print(char_rep_count("aaabbcdddd"))
aaa3bb2c1dddd4
I think this fulfils the brief and is also very fast:
s = 'aaabbcddddd'
def mycode(myString):
if myString:
count = 1
rs = [prev := myString[0]]
for c in myString[1:]:
if c != prev:
rs.append(f'{count}')
count = 1
else:
count += 1
rs.append(prev := c)
rs.append(f'{count}')
return ''.join(rs)
return myString

Python for loop iterating an already iterated item

So I was trying to solve this leetcode problem:
Input: command = "G()(al)"
Output: "Goal"
Explanation: The Goal Parser interprets the command as follows:
G -> G
() -> o
(al) -> al
The final concatenated result is "Goal".
This is my code:
def interpret(command: str) -> str:
res = ''
for i in command:
if i == 'G':
res += i
if i == '(':
ind = command.index(i)
if command[ind + 1] == ')':
res += 'o'
if command[ind + 1] == 'a':
res += 'al'
return res
The problem is, instead of returning 'Goal', the function returns 'Goo'. So I changed the function to the following to see what's going on:
for i in command:
if i == '(':
print(command.index(i))
And the above code prints out this
1
1
which means the loop is iterating an element twice?
What did I do wrong and how can I fix the function to return the correct output?
command.index() gives you the first occurrence of '('.
Rewrite your function as follows:
def interpret(command: str) -> str:
res = ""
for c, i in enumerate(command):
if i == "G":
res += i
if i == "(":
ind = c
if command[ind + 1] == ")":
res += "o"
if command[ind + 1] == "a":
res += "al"
return res

Recursive Hexadecimal Conversion Python 3

I've made a hexadecimal converter to practice recursion/recursive thinking. I, however, The recurssion doesn't appear to be happening as the functions seems to just output the result of 9 as of current.The code is as follows:
import math
curr=0
def convert(x):
L=len(x)
L-=1
sol=0
if L == 0:
return 0
else:
if x[curr]==["A","a"]:
v=10
elif x[curr]==["B","b"]:
v=11
elif x[curr]==["C","c"]:
v=12
elif x[curr]==["D","d"]:
v=13
elif x[curr]==["E","e"]:
v=14
elif x[curr]==["F","f"]:
v=15
else:
v=int(x[curr])
sol+=((v)*(16**(L-1)))
return sol + convert(x[curr+1])
def main():
print(convert('98A'))
main()
You were setting L = len(x) everytime you call the function. Here is one solution:
import math
def convert(x, L):
c = len(x) - 1
sol=0
if L > c:
return 0
else:
if (x[L]=="A" or x[L]=="a"):
v=10
elif (x[L]=="B" or x[L]=="b"):
v=11
elif (x[L]=="C" or x[L]=="c"):
v=12
elif (x[L]=="D" or x[L]=="d"):
v=13
elif (x[L]=="E" or x[L]=="e"):
v=14
elif (x[L]=="F" or x[L]=="f"):
v=15
else:
v=int(x[L])
sol+=((v)*(16**(c - L)))
print(sol)
return sol + convert(x, L + 1)
def main():
print(convert('98A', 0))
main()
You can use something like this:
class HexMap:
# mapping char to int
d = { hex(n)[2:]:n for n in range(16)}
def convert(x):
s = 0
# use reverse string and sum up - no need for recursion
for i,c in enumerate(x.lower()[::-1]):
s += HexMap.d[c]*16**i
return s
def main():
print(convert('98A'))
main()
Output:
2442
Recursive version:
# class HexMap: see above
def convert(x):
def convert(x,fak):
if not x:
return 0
else:
return HexMap.d[x[-1]]*16**fak + convert(x[:-1],fak+1)
return convert(x.lower(),0)
def main():
print(convert('98A'))
main()
Same output.

returning 1 instead of true in python

I am trying to return one instead of true in python.
The code i am working on is:
delimiters = ( '()', '[]', '{}', "''", '""' )
esc = '\\'
def is_balanced(s, delimiters=delimiters, esc=esc):
stack = []
opening = tuple(str[0] for str in delimiters)
closing = tuple(str[1] for str in delimiters)
for i, c in enumerate(s):
if len(stack) and stack[-1] == -1:
stack.pop()
elif c in esc:
stack.append(-1)
elif c in opening and (not len(stack) or opening[stack[-1]] != closing[stack[-1]]):
stack.append(opening.index(c))
elif c in closing:
if len(stack) == 0 or closing.index(c) != stack[-1]:
return False
stack.pop()
return len(stack) == 0
num_cases = raw_input()
num_cases = int(num_cases)
for num in range(num_cases):
s = raw_input()
print is_balanced(s)
It basically checks whether the string typed is balanced or not. If balanced, should return 1 and if not 0.
I tried this:
1
Test string
True
It returns true. I would like it to return 1. How do i do it?
Alternatively you could cast your boolean to an int:
>>>myBoolean = True
>>>int(myBoolean)
1
>>>myBoolean = False
>>>int(myBoolean)
0
Huh? You change the code:
Instead of
return False
write
return 0
and instead of
return len(stack) == 0
write
if len(stack) == 0:
return 1
return 0
The latter 3-liner can be rewritten on a single line, but I chose the above for clarity.
return 1 if len(stack) == 0 else 0
This concisely changes the return value of is_balanced, and is equivalent to:
if len(stack) == 0:
return 1
else:
return 0
Of course you could keep is_balanced unchanged and print (in similar notation):
1 if is_balanced(s) else 0
Just use
print +is_balanced(s)
instead.

Splitting C string in Python

I would like to split a string similar to
'abc "defg hijk \\"l; mn\\" opqrs"; tuv'
into
(['abc', '"defg hijk \\"l; mn\\" opqrs"'], 33)
i.e. I don't want to break on semicolon inside (nested) quotes. What's the easiest way, tokenize? It doesn't hurt if it's fast, but short is better.
Edit: I forgot one more detail that makes it even more tricky. I need the position of the semicolon that is cutting off the string, or -1 if there is none. (I'm doing changes to legacy code that used to be recursive, but stackoverflowed when the string became very long.)
It's unlikely there is an easy way to solve this without a proper parser. You could probably get away with a hand built parser that doesn't require tokenizing though.
Something like the following should be a good guide:
def parse(s):
cur_s = []
strings = []
def flush_string():
strings.push(''.join(cur_s))
cur_s = []
def handle_special_cases():
# TODO: Fill this in
for c in s:
if c == ';':
break
elif c in ['\\' '"']:
handle_special_cases()
elif c == ' ':
flush_string()
else:
cur_s.push(c)
flush_string()
return strings
It's a stateful search, so simple stateless operations are not available. Here's a simple char-by-char stateful evaluator that might meet your "short" without resorting to full tokenization/parsing:
#!/usr/bin/env python
inp="""abc "defg hijk \\"l; mn\\" opqrs"; tuv'`"""
def words_to_semi(inpstr):
ret = ['']
st8 = 1 # state: 1=reg, 2=in quotes, 3=escaped quote, 4=escaped reg, 0=end
ops = { 1 : {' ': lambda c: (None,1),
'"': lambda c: (c,2),
';': lambda c: ('',0),
'\\': lambda c: (c,4),
},
2 : {'\\': lambda c: (c,3),
'"': lambda c: (c,1),
},
3 : {None: lambda c: (c,2)},
4 : {None: lambda c: (c,1)},
}
pos = 0
for C in inpstr:
oc,st8 = ops[st8].get(C, ops[st8].get(None, lambda c:(c,st8)))(C)
if not st8: break
if oc is None:
ret.append('')
else:
ret[-1] += oc
pos = pos + 1
return ret, pos
print str(words_to_semi(inp))
Just modify the ops dict (and add new states) to handle other cases; everything else is generic code.
Here's the brute-force method I went with. Brrr...
def f(s):
instr = False
inescape = False
a = ''
rs = []
cut_index = -1
for idx,ch in enumerate(s):
if instr:
a += ch
if inescape:
inescape = False
elif ch == '\\':
inescape = True
elif ch == '"':
if a:
rs += [a]
a = ''
instr = False
elif ch == '"':
if a:
rs += [a]
a = ch
instr = True
elif ch == ';':
if a:
rs += [a]
cut_index = idx
break
elif ch == ' ' or ch == '\t' or ch == '\n':
if a:
rs += [a]
a = ''
else:
a += ch
return rs, cut_index
f('abc "defg hijk \\"l; mn\\" opqrs"; tuv')

Categories