简体   繁体   English

Math Latex 宏在 reStructuredText 和 Sphinx 中进行替换

[英]Math Latex macros to make substitutions in reStructuredText and Sphinx

Using Sphinx and reStructuredText , would it be possible to define math macros to make substitutions in a math Latex formula?使用SphinxreStructuredText ,是否可以定义数学宏以在数学 Latex 公式中进行替换?

Basically, I would like to have something like基本上,我想要类似的东西

.. |bnabla| replace:: :math:`\boldsymbol{\nabla}`
.. |vv| replace:: :math:`\textbf{v}`

.. math:: \rho \mbox{D}_t |vv| = - |bnabla| p + \rho \textbf{g} + \eta |bnabla|^2 |vv|,

where |vv| is the velocity and |bnabla| is the nabla operator.

Then follow many other equations with |vv| and |bnabla|...

but it does not work at all.但它根本不起作用。 First the flags are not substituted in math mode and second, even if they were substituted, a :math: statement does not work in a .. math:: block.首先,在数学模式下不会替换标志,其次,即使它们被替换, :math:语句在.. math::块中也不起作用。 Would it be a good idea and not to complicate to change these two behaviours in Sphinx?在 Sphinx 中改变这两种行为是否是一个好主意而不是复杂化?

Another solution would be to use latex macros as in this question Creating LaTeX math macros within Sphinx but I think the final code would be simpler to read with local rst substitutions as in my example.另一种解决方案是使用乳胶宏,如在这个问题中创建 LaTeX 数学宏在 Sphinx 中,但我认为最终的代码会更容易阅读与我的例子中的本地 rst 替换。 I would like to have clear formulas that can also be read in text mode.我想要清晰的公式,也可以在文本模式下阅读。

Moreover, I am using the MathJax extension so I cannot use the variable pngmath_latex_preamble.此外,我使用的是 MathJax 扩展,所以我不能使用变量 pngmath_latex_preamble。 I could use this solution for MathJax https://stackoverflow.com/a/19268549/1779806 but it seems quite complicate and once again the code would be clearer with "local" rst substitutions.我可以将此解决方案用于 MathJax https://stackoverflow.com/a/19268549/1779806,但它似乎非常复杂,并且再次使用“本地”第一个替换代码会更清晰。

Edit:编辑:

I realized that it would be very convenient and useful for many people to implement a mathmacro substitution directive directly in reStructuredText (ie in the Python package docutils).我意识到对许多人来说,直接在 reStructuredText 中(即在 Python 包 docutils 中)实现mathmacro替换指令会非常方便和有用。 The new directive should work like this:新指令应该像这样工作:

Definition:定义:

.. |bnabla| mathmacro:: \boldsymbol{\nabla}
.. |vv| mathmacro:: \textbf{v}

These math macros could be included directly in text as in这些数学宏可以直接包含在文本中,如

|bnabla| is the nabla operator,

which should produce an inline equation like this这应该产生一个像这样的内联方程

:math:`\boldsymbol{\nabla}` is the nabla operator.

These macros could also be included in inline equations:这些宏也可以包含在内联方程中:

This is an inline equation :math:`\vv = \bnabla f`, 

which should be equivalent of这应该相当于

:math:`\textbf{v} = \boldsymbol{\nabla}f`

They could also be included in block equation它们也可以包含在块方程中

.. math:: \vv = \bnabla f

which should be equivalent of这应该相当于

.. math:: \textbf{v} = \boldsymbol{\nabla}f.

However, I am really not familiar with how docutils works internally.但是,我真的不熟悉 docutils 内部是如何工作的。 I notice in particular that the MathBlock directive (defined in docutils/parsers/rst/directives/body.py) does not call any parsing of its input so there is no substitution in math mode.我特别注意到 MathBlock 指令(在 docutils/parsers/rst/directives/body.py 中定义)不会对其输入进行任何解析,因此在数学模式下没有替换。

I do not know if it is possible to change the behaviour of a substitution directive such that the substitution is cleaver and adapt to the context from where it is call, in text, in inline math or in block math.我不知道是否有可能改变替换指令的行为,使得替换更加切割并适应它被调用的上下文、文本、内联数学或块数学。

Does someone can give me some clues on how to implement this useful new feature?有人可以给我一些关于如何实现这个有用的新功能的线索吗?

Since I really needed a good solution for this need, I worked it out myself... It tool me awhile and the solution is maybe not perfect, but at least it works well.因为我真的需要一个很好的解决方案来满足这个需求,所以我自己解决了......它为我提供了一段时间,解决方案可能并不完美,但至少它运作良好。 I present the result since it can be useful for other people.我展示了结果,因为它对其他人有用。

I also adapted the solution as a Sphinx extension, which can be found here .我还将该解决方案改编为 Sphinx 扩展,可在此处找到。

I had to define a new substitution directive and to redefined the math directive and role.我必须定义一个新的替换指令并重新定义数学指令和角色。 All this is done in a file mathmacro.py:所有这些都在一个文件 mathmacro.py 中完成:

"""
'Proof of concept' for a new reStructuredText directive *mathmacro*.

Use for example with::

  python mathmacro.py example.rst example.html

"""

import re

from docutils.parsers.rst.directives.misc import Replace

from docutils.parsers.rst.directives.body import MathBlock
from docutils.parsers.rst.roles import math_role

def multiple_replacer(replace_dict):
    """Return a function replacing doing multiple replacements.

    The produced function replace `replace_dict.keys()` by
    `replace_dict.values`, respectively.

    """
    def replacement_function(match):
        s = match.group(0)
        end = s[-1]
        if re.match(r'[\W_]', end):
            return replace_dict[s[:-1]]+end
        else:
            return replace_dict[s]

    pattern = re.compile("|".join([re.escape(k)+r'[\W_\Z]|'+re.escape(k)+r'\Z'
                                   for k in replace_dict.keys()]), 
                         re.M)
    return lambda string: pattern.sub(replacement_function, string)


class MathMacro(Replace):
    """Directive defining a math macro."""
    def run(self):
        if not hasattr(self.state.document, 'math_macros'):
            self.state.document.math_macros = {}

        latex_key = '\\'+self.state.parent.rawsource.split('|')[1]
        self.state.document.math_macros[latex_key] = ''.join(self.content)

        self.state.document.math_macros_replace = \
            multiple_replacer(self.state.document.math_macros)

        self.content[0] = ':math:`'+self.content[0]
        self.content[-1] = self.content[-1]+'`'

        return super(MathMacro, self).run()


class NewMathBlock(MathBlock):
    """New math block directive parsing the latex code."""
    def run(self):
        try:
            multiple_replace = self.state.document.math_macros_replace
        except AttributeError:
            pass
        else:
            if self.state.document.math_macros:
                for i, c in enumerate(self.content):
                    self.content[i] = multiple_replace(c)
        return super(NewMathBlock, self).run()


def new_math_role(role, rawtext, text, lineno, inliner, 
                  options={}, content=[]):
    """New math role parsing the latex code."""
    try:
        multiple_replace = inliner.document.math_macros_replace
    except AttributeError:
        pass
    else:
        if inliner.document.math_macros:
            rawtext = multiple_replace(rawtext)

    return math_role(role, rawtext, text, lineno, inliner,
                     options=options, content=content)


if __name__ == '__main__':

    from docutils.parsers.rst.directives import register_directive
    from docutils.parsers.rst.roles import register_canonical_role

    register_directive('mathmacro', MathMacro)
    register_directive('math', NewMathBlock)
    register_canonical_role('math', new_math_role)



    from docutils.core import publish_cmdline, default_description
    description = ('Generates (X)HTML documents '
                   'from standalone reStructuredText sources. '
                   +default_description)
    publish_cmdline(writer_name='html', description=description)

The content of the file example.rst:文件example.rst的内容:

Here, I show how to use a new mathmacro substitution directive in
reStructuredText. I think even this small example demonstrates that it
is useful.


First some math without math macros.  Let's take the example of the
incompressible Navier-Stokes equation:

.. math:: \mbox{D}_t \textbf{v} = 
   -\boldsymbol{\nabla} p + \nu \boldsymbol{\nabla} ^2 \textbf{v}.

where :math:`\mbox{D}_t` is the convective derivative,
:math:`\textbf{v}` the velocity, :math:`\boldsymbol{\nabla}` the
nabla operator, :math:`\nu` the viscosity and
:math:`\boldsymbol{\nabla}^2` the Laplacian operator.


.. |Dt| mathmacro:: \mbox{D}_t
.. |bnabla| mathmacro:: \boldsymbol{\nabla}
.. |vv| mathmacro:: \textbf{v}

Now, let's use some math macros and try to get the same result...  The
Navier-Stokes equation can now be written like this:

.. math:: \Dt \vv = - \bnabla p + \nu \bnabla^2 \vv

where |Dt| is the convective derivative, |vv| the velocity, |bnabla|
the nabla operator, :math:`\nu` the viscosity and :math:`\bnabla^2`
the Laplacian operator.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM