deleting characters using backspace - python-3.x

I'm creating a text box class with a method that updates its text. It has the user's keyboard input as parameter, keys. The text box class also has an attribute, text, which is pretty self explanatory, it's its text. So I need to add the users input to the text box's text. Except if the user types a backspace key (which is '\x08') I'll need to delete all the letters before it. But of course if there's 2 backspaces followed up consecutively, it's not like a backspace would delete a backspace, I'll need to delete twice instead. So now that you understand the situation, here's my approach to the problem:
def update(self, keys):
if len(keys) > 0:
# I have a shift variable because when you modify a variable at the same time as
# iterating through it, the index will off shift, so I need to reverse that
shift = 0
for i in range(len(keys)):
i -= shift
# If there's a backspace
if keys[i] == '\x08':
# If it's the first character
if i == 0:
# Remove the last character from the text box's text
self.text = self.text[:-1]
# Get rid of the backspace from the user input
keys = keys[1:]
# reverse the off shift, or else the for loop will skip the second element
shift += 1
else:
j = i
# Counts how many backspaces follow up consecutively
del_count = 1
while keys[j] != '\x08':
j -= 1
del_count += 1
# Adjusts the user's input
keys = keys[:j - del_count] + keys[i+1:]
shift += del_count
self.text += keys
print(self.text)
It almost works perfectly, except when the user's input is a character followed up by multiple backspaces, I get an index error. For example, if the user input (keys) was "a\x08\x08", I'd get an index error at if keys[i] == '\x08':. What is the cause for this? And can someone give me a solution? Thanks in advance.

You should not modify the iterable inside its loop.
I was approached this problem within 3 steps:
Merged text and keys first
Count and collect index of backspace chars and effected normal chars
Deleted both of them in the merged object in reversed order
Try this out:
def update(text, keys):
if keys:
# Step 1: Merge both `key` and `texts`
print(repr(text))
text += keys
print(repr(text))
# Step 2: Count and collect `backspace` posision and `effected chars` position in reversed order
backspace_posision = []
char_deleted_position = []
for i, char in enumerate(text[::-1]):
_r_i = - i - 1
if char == "\x08":
backspace_posision.append(_r_i)
print("backspace_posision:", backspace_posision)
elif len(char_deleted_position) < len(backspace_posision):
char_deleted_position.append(_r_i)
print(char)
print("char_deleted_position:", char_deleted_position)
# Step 3: Remove them in reversed order
texts = list(text)
text_leng = len(texts)
print(repr(texts))
for _r_i in sorted(backspace_posision + char_deleted_position, reverse=True):
i = text_leng + _r_i
print(i)
texts.pop(i)
print(repr(texts))
text = "".join(texts)
print(repr(text))
Example output will look like this
update("ABC", "D\x08\x08EFG\x08H\x08\x08")
# Original text
>>>'ABC'
# Merged
>>>'ABCD\x08\x08EFG\x08H\x08\x08'
# Collecting backspace and effected chars in reversed order
# Collecting backspace
>>>backspace_posision: [-1]
>>>backspace_posision: [-1, -2]
# Collecting effected chars
>>>H
>>>char_deleted_position: [-3]
# Collecting backspace
>>>backspace_posision: [-1, -2, -4]
# Collecting effected chars
>>>G
>>>char_deleted_position: [-3, -5]
>>>F
>>>char_deleted_position: [-3, -5, -6]
# Collecting backspace
>>>backspace_posision: [-1, -2, -4, -8]
>>>backspace_posision: [-1, -2, -4, -8, -9]
# Collecting effected chars
>>>D
>>>char_deleted_position: [-3, -5, -6, -10]
>>>C
>>>char_deleted_position: [-3, -5, -6, -10, -11]
# Iterate the merged text in reversed order and remove them
>>>['A', 'B', 'C', 'D', '\x08', '\x08', 'E', 'F', 'G', '\x08', 'H', '\x08', '\x08']
>>>12
>>>['A', 'B', 'C', 'D', '\x08', '\x08', 'E', 'F', 'G', '\x08', 'H', '\x08']
>>>11
>>>['A', 'B', 'C', 'D', '\x08', '\x08', 'E', 'F', 'G', '\x08', 'H']
>>>10
>>>['A', 'B', 'C', 'D', '\x08', '\x08', 'E', 'F', 'G', '\x08']
>>>9
>>>['A', 'B', 'C', 'D', '\x08', '\x08', 'E', 'F', 'G']
>>>8
>>>['A', 'B', 'C', 'D', '\x08', '\x08', 'E', 'F']
>>>7
>>>['A', 'B', 'C', 'D', '\x08', '\x08', 'E']
>>>5
>>>['A', 'B', 'C', 'D', '\x08', 'E']
>>>4
>>>['A', 'B', 'C', 'D', 'E']
>>>3
>>>['A', 'B', 'C', 'E']
>>>2
>>>['A', 'B', 'E']
>>>'ABE'

Related

How do I get FOR to work on a list but leaping through it according to another list and how to get it back to the start to keep counting like a loop?

So this is the chromatic_scale = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
I want to form major, minor and other scales based on this.
To form a major scale, for example, I need to leap through the chromatic scale like this: major = [2, 2, 1, 2, 2, 2, 1] (in music, we say "tone, tone, semitone, tone, tone, tone, semitone" where tone means leaping 2 list items and semitone means leaping 1, thus the list)
A practical example: Starting from 'C', I should get ['C', 'D', 'E', 'F', 'G', 'A', 'B', 'C'] (yes, it should loop back to 'C' at the end).
1 - I thought of doing it with FOR but how do I get FOR to work on a list (chromatic) but leaping through it according to another list (major)?
2 - And if I start from 'A', for instance, how to get it back to the beginning to keep counting?
At the end, I managed to do it but I used WHILE instead of FOR.
chromatic = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B',
'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
def major(tom):
major_scale = [2, 2, 1, 2, 2, 2, 1]
step = 0
t = chromatic.index(tom)
m = []
while len(m) < 8:
m.append(chromatic[t])
if len(m) == 8:
break
t += major_scale[step]
step += 1
return m
x = major('D')
print(x)
Thank you everyone!

Convert number to letters using dictionary in Python

I have input that provides a number and a sequence of distinct letters (upper/lowercase).
The program generates a dictionary for provided sequence of letters and the number should be converted using into letters using values from dictionary.
For example, I have following input:
Convert 49036 using fFeEdDcCbBaA.
The dictionary created for this sequence of letters is:
numberkey = {500000: 'f', 100000: 'F', 50000: 'e', 10000: 'E', 5000: 'd', 1000: 'D', 500: 'c', 100: 'C', 50: 'b', 10: 'B', 5: 'a', 1: 'A'}
The output of the conversion should be this:
EeDEBBBaA
Roman number conversion rules applies.
The output I'm getting so far is not correct:
EEEEdDDDDBBBaA
Would appreciate any help. Thanks.
Here's a simple and generalised approach, based on the Roman Numeral concept.
n = 49036
numberkey = {500000: 'f', 100000: 'F', 50000: 'e', 10000: 'E', 5000: 'd', 1000: 'D', 500: 'c', 100: 'C', 50: 'b', 10: 'B', 5: 'a', 1: 'A'}
x = list(numberkey.items())
x.sort()
new_base = [] #to get special symbols for 4's and 9's
for i in range(len(x)-1):
if x[i][0] < (x[i+1][0]/2):
new_base.append((x[i+1][0]-x[i][0], x[i][1]+x[i+1][1]))
if (str(x[i][0]).find("10")==0) and numberkey.get(x[i][0]//10, None):
num = numberkey[x[i][0]//10]
new_base.append((x[i][0]-(x[i][0]//10), num+x[i][1]))
x += new_base
x.sort()
ans = ""
i = len(x)-1
while n and i>=0:
count = n//x[i][0]
if count:
ans += count*x[i][1]
n -= count*x[i][0]
i -= 1
print(and) #EeDEBBBaA

How to custom sort a list with exceptions for first elements then default afterwards

I have an arbitrary length list of strings I want to sort in alphabetical order unless it is a specific string, then I want those to have "priority" over others and come first.
Example input:
['a', 'b', 'c', 'd', 'e', 'f', 'g']
I want to sort the list such that the values ['c', 'g', 'e'] come first in that order then the rest of the list is sorted alphabetically.
Result:
['c', 'g', 'e', 'a', 'b', 'd', 'f']
I'm trying to figure out how to create a key function I can pass to sorted.
This should work:
def key_func(elem):
if elem == "c":
return chr(0)
if elem == "g":
return chr(1)
if elem == "e":
return chr(2)
return elem
lst = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
lst.sort(key=key_func)
print(lst)
Output:
['c', 'g', 'e', 'a', 'b', 'd', 'f']
Just ensure your list doesn't contain chr(0), chr(1) or chr(2)
If you want different "priority" strings, change key_func to this:
priority = ['c', 'g', 'e']
def key_func(elem):
if elem not in priority:
return elem
return chr(priority.index(elem))

Count the elements in a list of a list(python)

[['s', 'a', 'b', 't'], ['s', 'c', 'd', 't'], ['s', 'c', 'e', 't','g']]
I want to count how many elements are in each list of the list.
so,[4,4,5].How can i do that in python?
Just use len for each element on the given list:
l = [['s', 'a', 'b', 't'], ['s', 'c', 'd', 't'], ['s', 'c', 'e', 't','g']]
[len(x) for x in l] # [4, 4, 5]
you can utilize the len() function. It takes a list as a parameter and returns the elements count.
python len function

How to use the difference between two lists to transform the first into the second? Python

I have a large number of identical lists 'old' which I want to transform in the same way into a list 'new'. The way I want to do it, is to make an example of the desired list 'new'. Then I turn the difference between the two lists 'old' and 'new' into a rule, and then use that rule to turn my other lists 'old_2' into 'new_2'.
I cannot figure out how to do the first step and the second step does not give me the expected result. Is there an elegant way to do this?
import numpy
# 0 1 2 3 4 5
old_1 = ['A', 'B', 'C', 'D', 'E', 'F']
new = ['B', 'C', 'D', 'E', 'A']
# 01 Get the difference new - /- old_1 based on index positions of
# the list elements, to get something like this:
order = [1,2,3,4,0]
# 02 Then use this order to transform a second identical list, old_2.
# For this I wanted to use the following:
old_2 = ['A', 'B', 'C', 'D', 'E', 'F']
old_2 = numpy.array(old_2)
order = numpy.array(order)
inds = order.argsort()
print('inds =', inds) # As a check, this gives the wrong order: [4 1 0 2 3]
new_2 = old_2[inds]
# I expected this to result in what I want, which is:
print(new_2)
['C', 'B', 'D', 'E', 'A']
# But what I get in reality is this:
inds = [4 1 0 2 3]
['E' 'B' 'A' 'C' 'D']
Any suggestions to get the desired result?
new_2 = ['B', 'C', 'D', 'E', 'A']
From what I understand, I tried to edit your code. Hopefully it helps.
import numpy as np
def get_order(new, old):
order = []
for element in new:
order.append(old.index(element))
return order
def main():
old_1 = ['A', 'B', 'C', 'D', 'E', 'F']
new = ['B', 'C', 'D', 'E', 'A']
order = get_order(new, old_1)
print(order)
old_2 = ['A', 'B', 'C', 'D', 'E', 'F']
old_2 = np.array(old_2)
order = np.array(order)
#inds = order.argsort()
#print('inds =', inds) # As a check, this gives the wrong order: [4 1 0 2 3]
new_2 = old_2[order]
print(new_2)
if __name__ == '__main__':
main()
Output
[1, 2, 3, 4, 0]
['B' 'C' 'D' 'E' 'A']

Resources