def remove_distances(code, r_codes=[], r_indices=[]): symbols = [] par_stack = [] new_code = '' # For each character in the code... for i, c in enumerate(code): # ... add the character to the new code. new_code += c in_element = -1 if is_symbol(code, i): # Check if symbol c is part of one of the r_codes for j in range(len(r_codes)): if r_indices[j] <= i < r_indices[j] + len(r_codes[j]): in_element = j if r_codes[j] not in symbols: symbols.append(r_codes[j]) if in_element < 0 and c not in symbols: symbols.append(c) if c == '(': par_stack.append(i) # If we find a part of the code enclosed in parentheses ... elif c == ')': start = par_stack.pop(-1) part = code[start:i + 1].strip('()') # ... check whether this part contains a +/- operator. if ('+' in part or '-' in part) and '(' not in code[start + 1:i]: # If yes, remove the operation from the code ... new_code = new_code[:-(i - start + 1)] symb, op, dist = part[0], part[1], int(''.join(part[2:])) # ... find the code to calculate from ... if symb == '$': symb = symbols[-1] # ... and get the correct distance. if op == '-': dist *= -1 # If it concerns a single symbol, calculate the distance from it if symb.isalnum() and len(symb) == 1: new_symb = alphabet[alphabet.index(symb) + dist] # If it concerns a code ... else: new_symb = '' # ... add the distance to each symbol in the code. for i, s in enumerate(symb): if is_symbol(symb, i): new_symb += alphabet[alphabet.index(s) + dist] else: new_symb += s # Add the result to the new code. new_code += new_symb #if new_symb not in symbols: symbols.append(new_symb) #print('>', code) #print('>>', new_code) return new_code
def split_code(code): stack = [] alternations = [] elements = [] # For each character in the code: for i in range(len(code)): # If it is a symbol not in an operator, add it to the elements. if is_symbol(code, i) and len(stack) == 0: elements.append(code[i]) # If it is an opening bracket, add it to the stack elif code[i] in '<([': stack.append(i) # If it is a closing bracket ... elif code[i] in '>])': start = stack.pop(-1) # ... and the stack is not empty, it is a lower level operator. if len(stack) != 0: continue # Iteration, Symmetry and Alternation have different cases. if start > 1 and code[start-1] == '*': elements.append(code[start-2:i+1]) if code[i] == ']' and start > 0 and code[start-1] == 'S': elements.append(code[start-1:i+1]) elif code[i] == '>': if start > 0 and code[start-1] == '/': lhs = alternations.pop(-1) elements.append(lhs + code[start-1:i+1]) else: alternations.append(code[start:i+1]) return elements
def replace_chunks(string, chunk, r1): elems, _ = chunk elems2 = copy(elems) # For each element: for i, elem in enumerate(elems): # Remove all outer parentheses, .... elem_stripped = elem.strip('()') dist = '' # ... find the part of the string before any + or - ... if '+' in elem_stripped: dist_ind = elem_stripped.index('+') dist += elem_stripped[dist_ind:] if '-' in elem_stripped: dist_ind = elem_stripped.index('-') dist += elem_stripped[dist_ind:] # ... and replace that part with a new part, given in r1 ... new_r = '' for j, c in enumerate(r1[i]): # ... while carrying over any distance operator. if is_symbol(r1[i], j) and dist != '': new_r += '(' + c + dist + ')' else: new_r += c elems2[i] = elems2[i].replace(elem_stripped, new_r) # Now reconstruct the string and return it. return reconstruct_string(string, chunk, elems2)
def get_chunks(string, l1): par_stack = [] elements = [] elem_indices = [] # For each character in the string: for i, c in enumerate(string): # If it is an opening parenthesis, add it to the stack. if c == '(': par_stack.append(i) # If it is a closing parenthesis ... if c == ')': # ... get the corresponding parenthesis from the stack ... start = par_stack.pop(-1) # ... and find the substring the parentheses enclose (elem). elem = string[start:i+1] elem_len = len(elem.strip('()')) # if elem is already in the elements list ... if elements != [] and '('+''.join(elements[-elem_len:])+')' == elem: # ... remove those elements from the elements list. elements = elements[:-elem_len] elem_indices = elem_indices[:-elem_len] # if elem contains only symbols ... if elem.strip('()').isalnum(): # ... add it to the elements list. elements.append(elem) elem_indices.append(start) # If it is a symbol, add it to the elements list. if is_symbol(string, i): elements.append(c) elem_indices.append(i) chunks = [] symb_string = '' # For each sequential combination of elements ... for i in range(len(elements)): for j in range(i, len(elements)): # ... create a string of all symbols in those elements. symb_string = '' for e in elements[i:j+1]: symb = e.strip('()') for s in symb: if s not in '+-': symb_string += s else: break # If this string corresponds to l1 ... if symb_string == l1: # ... we have found a chunk. chunks.append((elements[i:j+1], elem_indices[i:j+1])) return chunks
def add_distances_chunk(code, chunk): elems, indices = chunk new_string = '' symbols = [] # For each character in the string: for i, c in enumerate(code): # If it is not a symbol, skip it. if not is_symbol(code, i): new_string += c continue # If it is one of the elements in the chunk ... in_element = False for j in range(len(elems)): if indices[j] <= i < indices[j] + len(elems[j]): new_string += c in_element = True # ... add it to the symbols, if it is not in already. if c not in symbols: symbols.append(c) # If it was added, we don't need to do anything with it anymore. if in_element: continue # At this point, we have encountered a symbol not in the given elements. # If there are no previous symbols, we cannot find a distance. if symbols == []: return False # Calculate the distance from the last new symbol ... dist = alphabet.index(c) - alphabet.index(symbols[-1]) new_symb = alphabet[alphabet.index(symbols[-1]) + dist] # ... and write the symbol as a distance from this symbol. if dist >= 0: new_string += '($+' + str(dist) + ')' else: new_string += '($-' + str(abs(dist)) + ')' if new_symb not in symbols: symbols.append(new_symb) return new_string
def paste(self): paste = pyperclip.paste() self.update_expression() if paste and not self.exp.is_error(): self.history.out() paste = paste.replace('sin⁻¹', 'asin').replace('cos⁻¹', 'acos').replace( 'tan⁻¹', 'atan').replace('rootx(', 'Ŷ').replace(' ', '') for k, v in ADVANCED_KEYS.items(): if k not in ['^', 'π', '√', '∛', 'Ŷ']: paste = paste.replace(v, k) for i in paste: if not is_symbol(i): self.last_invalid_exp = self.exp.exp self.exp.set_exp(ERRORS[5]) self.update_monitor() return self.exp.put_data_on_exp(paste) self.update_monitor()
def add_distances_symbols(code, lhs, add_from_last=True): if isinstance(code, str): new_code = '' else: new_code = [] if isinstance(lhs, list): symbols = lhs else: symbols = [] # For each character in the string ... for i, c in enumerate(code): add_code = '' is_symb = is_symbol(code, i) # If c is a symbol and not already in the lefthandside ... if is_symb and c not in lhs: # ... calculate the distance from the last symbol dist = alphabet.index(c) - alphabet.index(symbols[-1]) # ... and add c to the code as that distance if add_from_last: start = '($' else: start = '(' + str(symbols[-1]) if dist >= 0: add_code += start + '+' + str(dist) + ')' else: add_code += start + '-' + str(abs(dist)) + ')' # Otherwise, just add c to the new code else: add_code += c if isinstance(code, str): new_code += add_code else: new_code.append(add_code) if is_symb and c not in symbols: if c in lhs or add_from_last: symbols.append(c) return new_code
def replace_symbols(string, l1, r1): new_string = '' symbols = [] r_indices = [] r_elems = [] # For each element in the string: for i, c in enumerate(string): # If it is a symbol and occurs in l1 ... if is_symbol(string, i) and c in l1: n = symbols.count(c)%l1.count(c) # ... find the corresponding symbol in r1 ... new_symbol = r1[l1.index(c, n)%len(r1)] r_indices.append(len(new_string)) r_elems.append(new_symbol) # ... and add it to the new string. new_string += new_symbol symbols.append(c) # Otherwise, just add it to the string. else: new_string += c return new_string, r_elems, r_indices
def add_distances_positional(code, lhs, rhs): new_code = '' counts = {c: 0 for c in rhs} # For each character in the string ... for i, c in enumerate(code): is_symb = is_symbol(code, i) # If c is a symbol and not already in the lefthandside ... if is_symb and c not in lhs: # ... find the symbol in lhs at the same position as c in rhs ... pos_symbol = lhs[rhs.index(c, counts[c])] counts[c] += 1 # ... calculate the distance from the last symbol dist = alphabet.index(c) - alphabet.index(pos_symbol) # ... and add c to the code as that distance if dist >= 0: new_code += '(' + pos_symbol + '+' + str(dist) + ')' else: new_code += '(' + pos_symbol + '-' + str(abs(dist)) + ')' # Otherwise, just add c to the new code else: new_code += c return new_code