def parse_expr(s, local_dict=None, transformations=standard_transformations): """ Converts the string ``s`` to a SymPy expression, in ``local_dict`` Examples ======== >>> from sympy.parsing.sympy_parser import parse_expr >>> parse_expr("1/2") 1/2 >>> type(_) <class 'sympy.core.numbers.Half'> """ if local_dict is None: local_dict = {} global_dict = {} exec 'from sympy import *' in global_dict # keep autosimplification from joining Integer or # minus sign into a Mul; this modification doesn't # prevent the 2-arg Mul from becoming an Add, however. hit = False if '(' in s: kern = '_kern' while kern in s: kern += "_" s = re.sub(r'(\d *\*|-) *\(', r'\1%s*(' % kern, s) hit = kern in s tokens = [] input_code = StringIO(s.strip()) for toknum, tokval, _, _, _ in generate_tokens(input_code.readline): tokens.append((toknum, tokval)) for transform in transformations: tokens = transform(tokens, local_dict, global_dict) code = untokenize(tokens) expr = eval( code, global_dict, local_dict) # take local objects in preference if not hit: return expr rep = {C.Symbol(kern): 1} def _clear(expr): if hasattr(expr, 'xreplace'): return expr.xreplace(rep) elif isinstance(expr, (list, tuple, set)): return type(expr)([_clear(e) for e in expr]) if hasattr(expr, 'subs'): return expr.subs(rep) return expr return _clear(expr)
def stringify_expr(s, local_dict, global_dict, transformations): """ Converts the string ``s`` to Python code, in ``local_dict`` Generally, ``parse_expr`` should be used. """ tokens = [] input_code = StringIO(s.strip()) for toknum, tokval, _, _, _ in generate_tokens(input_code.readline): tokens.append((toknum, tokval)) for transform in transformations: tokens = transform(tokens, local_dict, global_dict) return untokenize(tokens)
def _transform(s, local_dict, global_dict, rationalize, convert_xor): g = generate_tokens(StringIO(s).readline) result = [] for toknum, tokval, _, _, _ in g: if toknum == NUMBER: number = tokval postfix = [] if number.endswith('j') or number.endswith('J'): number = number[:-1] postfix = [(OP, '*'), (NAME, 'I')] if '.' in number or ( ('e' in number or 'E' in number) and not (number.startswith('0x') or number.startswith('0X'))): match = _re_repeated.match(number) if match is not None: # Clear repeating decimals, e.g. 3.4[31] -> (3 + 4/10 + 31/990) pre, post, repetend = match.groups() zeros = '0' * len(post) repetends = repetend.lstrip('0') a = pre or '0' b, c = post or '0', '1' + zeros d, e = repetends, ('9' * len(repetend)) + zeros seq = [ (OP, '('), (NAME, 'Integer'), (OP, '('), (NUMBER, a), (OP, ')'), (OP, '+'), (NAME, 'Rational'), (OP, '('), (NUMBER, b), (OP, ','), (NUMBER, c), (OP, ')'), (OP, '+'), (NAME, 'Rational'), (OP, '('), (NUMBER, d), (OP, ','), (NUMBER, e), (OP, ')'), (OP, ')'), ] elif rationalize: seq = [(NAME, 'Rational'), (OP, '('), (STRING, repr(str(number))), (OP, ')')] else: seq = [(NAME, 'Float'), (OP, '('), (NUMBER, repr(str(number))), (OP, ')')] else: seq = [(NAME, 'Integer'), (OP, '('), (NUMBER, number), (OP, ')')] result.extend(seq + postfix) elif toknum == NAME: name = tokval if name in ['True', 'False', 'None' ] or iskeyword(name) or name in local_dict: result.append((NAME, name)) continue elif name in global_dict: obj = global_dict[name] if isinstance(obj, (Basic, type)) or callable(obj): result.append((NAME, name)) continue result.extend([ (NAME, 'Symbol'), (OP, '('), (NAME, repr(str(name))), (OP, ')'), ]) elif toknum == OP: op = tokval if op == '^' and convert_xor: result.append((OP, '**')) else: result.append((OP, op)) else: result.append((toknum, tokval)) return untokenize(result)
def _transform(s, local_dict, global_dict, rationalize, convert_xor): g = generate_tokens(StringIO(s).readline) result = [] prevtoken = '' for toknum, tokval, _, _, _ in g: if toknum == NUMBER: number = tokval postfix = [] if number.endswith('j') or number.endswith('J'): number = number[:-1] postfix = [(OP, '*'), (NAME, 'I')] if '.' in number or (('e' in number or 'E' in number) and not (number.startswith('0x') or number.startswith('0X'))): match = _re_repeated.match(number) if match is not None: # Clear repeating decimals, e.g. 3.4[31] -> (3 + 4/10 + 31/990) pre, post, repetend = match.groups() zeros = '0'*len(post) post, repetends = [w.lstrip('0') for w in [post, repetend]] # or else interpreted as octal a = pre or '0' b, c = post or '0', '1' + zeros d, e = repetends, ('9'*len(repetend)) + zeros seq = [ (OP, '('), (NAME, 'Integer'), (OP, '('), (NUMBER, a), (OP, ')'), (OP, '+'), (NAME, 'Rational'), (OP, '('), ( NUMBER, b), (OP, ','), (NUMBER, c), (OP, ')'), (OP, '+'), (NAME, 'Rational'), (OP, '('), ( NUMBER, d), (OP, ','), (NUMBER, e), (OP, ')'), (OP, ')'), ] elif rationalize: seq = [(NAME, 'Rational'), (OP, '('), (STRING, repr(str(number))), (OP, ')')] else: seq = [(NAME, 'Float'), (OP, '('), (NUMBER, repr(str(number))), (OP, ')')] else: seq = [(NAME, 'Integer'), (OP, '('), ( NUMBER, number), (OP, ')')] result.extend(seq + postfix) elif toknum == NAME: name = tokval if name in ['True', 'False', 'None'] or iskeyword(name) or name in local_dict: result.append((NAME, name)) continue elif name in global_dict: obj = global_dict[name] if isinstance(obj, (Basic, type)) or callable(obj): result.append((NAME, name)) continue result.extend([ (NAME, 'Symbol'), (OP, '('), (NAME, repr(str(name))), (OP, ')'), ]) elif toknum == OP: op = tokval if op == '^' and convert_xor: result.append((OP, '**')) elif op == '!!': if prevtoken == '!' or prevtoken == '!!': raise TokenError result = _add_factorial_tokens('factorial2', result) elif op == '!': if prevtoken == '!' or prevtoken == '!!': raise TokenError result = _add_factorial_tokens('factorial', result) else: result.append((OP, op)) else: result.append((toknum, tokval)) prevtoken = tokval return untokenize(result)