복붙노트

[PYTHON] python 숫자 식을 LaTeX로 변환하기

PYTHON

python 숫자 식을 LaTeX로 변환하기

다음과 같이 유효한 파이썬 구문을 사용하여 문자열을 변환해야합니다.

'1+2**(x+y)'

동등한 LaTeX를 얻으십시오 :

$1+2^{x+y}$

나는 sympy의 latex 함수를 시도했지만 문자열 형식이 아닌 실제 표현을 처리한다.

>>> latex(1+2**(x+y))
'$1 + 2^{x + y}$'
>>> latex('1+2**(x+y)')
'$1+2**(x+y)$'

그러나 이것을하기 위해서 x와 y를 타입 "심볼"로 선언해야합니다.

컴파일러 모듈에서 파서를 사용하여 좀 더 직선적 인, 바람직하게 할 수있는 무언가를 원한다.

>>> compiler.parse('1+2**(x+y)')
Module(None, Stmt([Discard(Add((Const(1), Power((Const(2), Add((Name('x'), Name('y'))))))))]))

마지막으로, 왜 그런가 : 나는 라텍스 스 니펫을 생성하여 mathjax를 사용하여 웹 페이지에 표시 할 수 있어야합니다.

해결법

  1. ==============================

    1.sympy.latex를 eval과 함께 사용할 수 있습니다.

    sympy.latex를 eval과 함께 사용할 수 있습니다.

    s = "1+2**(x+y)"
    sympy.latex(eval(s))   # prints '$1 + {2}^{x + y}$'
    

    변수를 심볼로 선언해야하지만, 실제로 문제가 발생하면 모든 것을 파싱하고 처음부터 라텍스를 생성하는 것보다 파서를 작성하는 것이 훨씬 쉽습니다.

  2. ==============================

    2.sympy를 포함하지 않는 다소 길지만 여전히 불완전한 방법이 있습니다. \ frac {-b - \ sqrt {b ^ {2} -}로 변환 된 (-b-sqrt (b ** 2-4 * a * c)) / 4 \; \; c}} {2 \; a}로 렌더링하고 다음과 같이 렌더링합니다.

    sympy를 포함하지 않는 다소 길지만 여전히 불완전한 방법이 있습니다. \ frac {-b - \ sqrt {b ^ {2} -}로 변환 된 (-b-sqrt (b ** 2-4 * a * c)) / 4 \; \; c}} {2 \; a}로 렌더링하고 다음과 같이 렌더링합니다.

    기본적으로 AST를 생성하고 AST 노드에 해당하는 라텍스 연산을 생성합니다. 부족한 곳에서 그것을 확장하는 방법에 대한 충분한 아이디어가 있어야합니다.

    
    import ast
    
    class LatexVisitor(ast.NodeVisitor):
    
        def prec(self, n):
            return getattr(self, 'prec_'+n.__class__.__name__, getattr(self, 'generic_prec'))(n)
    
        def visit_Call(self, n):
            func = self.visit(n.func)
            args = ', '.join(map(self.visit, n.args))
            if func == 'sqrt':
                return '\sqrt{%s}' % args
            else:
                return r'\operatorname{%s}\left(%s\right)' % (func, args)
    
        def prec_Call(self, n):
            return 1000
    
        def visit_Name(self, n):
            return n.id
    
        def prec_Name(self, n):
            return 1000
    
        def visit_UnaryOp(self, n):
            if self.prec(n.op) > self.prec(n.operand):
                return r'%s \left(%s\right)' % (self.visit(n.op), self.visit(n.operand))
            else:
                return r'%s %s' % (self.visit(n.op), self.visit(n.operand))
    
        def prec_UnaryOp(self, n):
            return self.prec(n.op)
    
        def visit_BinOp(self, n):
            if self.prec(n.op) > self.prec(n.left):
                left = r'\left(%s\right)' % self.visit(n.left)
            else:
                left = self.visit(n.left)
            if self.prec(n.op) > self.prec(n.right):
                right = r'\left(%s\right)' % self.visit(n.right)
            else:
                right = self.visit(n.right)
            if isinstance(n.op, ast.Div):
                return r'\frac{%s}{%s}' % (self.visit(n.left), self.visit(n.right))
            elif isinstance(n.op, ast.FloorDiv):
                return r'\left\lfloor\frac{%s}{%s}\right\rfloor' % (self.visit(n.left), self.visit(n.right))
            elif isinstance(n.op, ast.Pow):
                return r'%s^{%s}' % (left, self.visit(n.right))
            else:
                return r'%s %s %s' % (left, self.visit(n.op), right)
    
        def prec_BinOp(self, n):
            return self.prec(n.op)
    
        def visit_Sub(self, n):
            return '-'
    
        def prec_Sub(self, n):
            return 300
    
        def visit_Add(self, n):
            return '+'
    
        def prec_Add(self, n):
            return 300
    
        def visit_Mult(self, n):
            return '\\;'
    
        def prec_Mult(self, n):
            return 400
    
        def visit_Mod(self, n):
            return '\\bmod'
    
        def prec_Mod(self, n):
            return 500
    
        def prec_Pow(self, n):
            return 700
    
        def prec_Div(self, n):
            return 400
    
        def prec_FloorDiv(self, n):
            return 400
    
        def visit_LShift(self, n):
            return '\\operatorname{shiftLeft}'
    
        def visit_RShift(self, n):
            return '\\operatorname{shiftRight}'
    
        def visit_BitOr(self, n):
            return '\\operatorname{or}'
    
        def visit_BitXor(self, n):
            return '\\operatorname{xor}'
    
        def visit_BitAnd(self, n):
            return '\\operatorname{and}'
    
        def visit_Invert(self, n):
            return '\\operatorname{invert}'
    
        def prec_Invert(self, n):
            return 800
    
        def visit_Not(self, n):
            return '\\neg'
    
        def prec_Not(self, n):
            return 800
    
        def visit_UAdd(self, n):
            return '+'
    
        def prec_UAdd(self, n):
            return 800
    
        def visit_USub(self, n):
            return '-'
    
        def prec_USub(self, n):
            return 800
        def visit_Num(self, n):
            return str(n.n)
    
        def prec_Num(self, n):
            return 1000
    
        def generic_visit(self, n):
            if isinstance(n, ast.AST):
                return r'' % (n.__class__.__name__, ', '.join(map(self.visit, [getattr(n, f) for f in n._fields])))
            else:
                return str(n)
    
        def generic_prec(self, n):
            return 0
    
    def py2tex(expr):
        pt = ast.parse(expr)
        return LatexVisitor().visit(pt.body[0].value)
    
    
  3. ==============================

    3.SymPy를 사용할 수 있습니다. 문자열을 sympify () 함수에 먼저 전달하면 유효한 SymPy 표현식으로 변환됩니다 (즉, 기호 생성 등). 그래서 너는 할 수있어.

    SymPy를 사용할 수 있습니다. 문자열을 sympify () 함수에 먼저 전달하면 유효한 SymPy 표현식으로 변환됩니다 (즉, 기호 생성 등). 그래서 너는 할 수있어.

    >>> latex(sympify('1+2**(x+y)'))
    1 + 2^{x + y}
    

    S ()는 또한 sympify ()의 지름길이기도합니다. 즉, latex (S ( '1 + 2 ** (x + y)'))도 작동합니다.

  4. ==============================

    4.Geoff Reedy 우수 답변에 대한 약간의 수정 :

    Geoff Reedy 우수 답변에 대한 약간의 수정 :

    class GenerateSymbols(defaultdict):
        def __missing__(self, key):
            self[key] = sympy.Symbol(key)
            return self[key]
    

    전에는 새 항목을 사전에 추가하지 않았습니다. 이제 이것을 식과 함께 사용할 수 있습니다.

    d= GenerateSymbols()    
    eq = '(-b-sqrt(b**2-4*a*c))/(2*a)'
    

    LaTeX로 변환하기 전에 더 단순화 할 수 있습니다.

    sympy.latex(sympy.simplify(eval(eq,d)))
    

    당신은 이것을 얻습니다 :

    '$- \\frac{b + \\operatorname{sqrt}\\left(- 4 a c + b^{2}\\right)}{2 a}$'
    
  5. ==============================

    5.Tom10의 답을 바탕으로 기호를 생성하고 eval을 호출 할 때 사용할 사전을 정의 할 수 있습니다.

    Tom10의 답을 바탕으로 기호를 생성하고 eval을 호출 할 때 사용할 사전을 정의 할 수 있습니다.

    from collections import defaultdict
    class GenerateSymbols(defaultdict):
      def __missing__(self, key):
        return sympy.Symbol(key)
    

    그럼 당신이 사용한다면

    sympy.latex(eval('1+2**(x+y)',GenerateSymbols()))
    

    변수에 대한 기호를 미리 작성하는 것에 대해 걱정할 필요가 없습니다.

  6. from https://stackoverflow.com/questions/3867028/converting-a-python-numeric-expression-to-latex by cc-by-sa and MIT license