我有一个可以实现方程式的软件,并且可以在线写入它们,例如:
==================
x = a_avg + ((x-1)/b_trans)^(-y^(-x))
y = ....
z = .... (something that have a similar form)
... etc, etc
=================
所以基本上,我有*.doc
这些方程式,我想把它们转换成 Latex,这样它们看起来就像这样:
$x = a_{avg} + \frac{x-1}{b_{trans}}^{-y^{-x}}$
挑战在于将索引(例如 )转换avg
为trans
下{}
标或上标。也可以转换()/()
为\frac{}{}
。有人知道有这样一个包可以将整个文档转换为方程列表吗?或者有人知道如何做到这一点吗?
我将非常感激您的建议!
保罗
答案1
如果 eq.txt 包含类似以下行
x = a_avg + ((x-1)/b_trans)^(-y^(-x))
然后是一个简单的编辑行,例如
sed -e 's/(/{(/g' -e 's/)/)}/g' -e 's/\//\\over /g' -e 's/_\([a-z]*\)/_{\\mathrm{\1}}/g' -e 's/.*/$\0$/' eq.txt
将输出
$x = a_{\mathrm{avg}} + {({(x-1)}\over b_{\mathrm{trans}})}^{(-y^{(-x)})}$
每行
当排版为
\documentclass{article}
\begin{document}
$x = a_{\mathrm{avg}} + {({(x-1)}\over b_{\mathrm{trans}})}^{(-y^{(-x)})}$
\end{document}
生产
我在这里使用了 sed,但您可以使用 perl 或 lua 或您的编辑器搜索/替换。
实际上,您需要在括号中使用正则表达式多下点功夫(注意有一个)
滑落了……),但我希望这足以展示基本思想。
答案2
这是一个不寻常的答案,因为虽然它确实将 OP 的代码转换为 LaTeX 代码,但该代码的存储方式是计算机可以读取的,而不是人眼可以读取的。因此,描述这个答案更合适的方法是它提供了一个用 LaTeX 编写的解释器,用于转换和呈现以非 LaTeX 格式提供的方程式。然而,最新的更新现在可以将内部代码转换为去标记化的翻译相关的 LaTeX 代码。
这个答案已经更新了很多:
已编辑,以便可以解析选定的数学运算符和希腊字母而无需转义(例如,cos x = beta
正确解析)。可以添加更多内容。
已编辑,因此方括号[...]
可以用作不可见的分组字符。
重新编辑以自动转换/
为\frac
样式(感谢 David 的\over
描述使用 \over 与 \frac 的实际后果如何?)。
已编辑以提供自动化。
经过编辑,提供翻译以及解释性呈现。
解释方程式
此答案自动执行使用 LaTeX 宏解释以非 LaTeX 用户语法表达的方程式的过程。我提供了 LaTeX 宏,\interpreteq{}
其中传递了非乳胶方程式,在 7 个阶段进行解析,重构并呈现为 LaTeX 方程式。
这种方法的真正巧妙之处在于,用户输入的非 LaTeX 格式的方程式会被解析为数学“基因”,这些基因会按照运算顺序组成方程式。然后,每个基因会被转换成 LaTeX 格式,生成的基因会自动重组为可执行 LaTeX 代码的 DNA 链。
但是,可执行代码的 DNA 链间接地表达在listofitems
包的内部表示中,该包用于以数学方式分割原始的非 LaTeX 方程。方程的这个内部表示(看起来很奇怪)可以在\detokenize\expandafter{\Z}
的结尾处显示,作为该方法的证明\interpreteq
。这将提供实际执行的标记,以呈现方程的 LaTeX 形式。
举例来说,采用用户格式化(非 LaTeX)的方程式:
x = a_avg + ([x-1] /b_trans)^(-y^[-x])
该包使用以下解析层次结构将此标记字符串解析到列表listofitems
中:\Q
\setsepchar[@]{=@(||)||[||]@^@/||*@+||-@_@alpha||beta||pi||cos||sin||tan}
解析的第一层是查找 的实例=
。 左侧的所有代码=
都存储在 中\Q[1]
,而 [第一个] 右侧=
(以及第二个 左侧=
)的所有代码都存储在 中\Q[2]
。 此级别的分隔符(即=
)存储在 中\Qsep[1]
。
对于每个部分\Q[1]
和\Q[2]
,都会发生第二级解析,即查找(
、)
、[
和的所有实例]
。因此,例如\Q[2,3]
表示 [非 LaTeX] DNA 链位于 右侧=
且位于括号或方括号分隔符的第 3 个实例之前。
根据 PEMDAS 操作顺序,此过程继续进行 7 级以上的解析:
=
(
,)
,[
, 和]
^
/
和*
+
和-
_
alpha
、、、、、以及其他所需功能beta
pi
cos
sin
tan
任何不是可解析分隔符的内容最终都会出现在某个低级\Q[.,.,...]
基因条目中。但是,所有可解析分隔符最终都会出现在\Qsep[.,.,...]
分隔符基因条目中。这些\Qsep
条目需要转换转换为 LaTeX 格式,这个过程由宏执行\QS
:
\def\QS[#1]{%
\if+\Qsep[#1]+\else%
\if-\Qsep[#1]-\else%
\if/\Qsep[#1]\over\else%
\if=\Qsep[#1]=\else%
\if^\Qsep[#1]^\else%
\if(\Qsep[#1]\bgroup\left(\else%
\if)\Qsep[#1]\right)\egroup\else%
\if[\Qsep[#1]\bgroup\else%
\if]\Qsep[#1]\egroup\else%
\if*\Qsep[#1]\cdot\else%
\if_\Qsep[#1]\expandafter\theund\else%
\csname \Qsep[#1]\endcsname\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi%
}
\Q[]
然后,DNA 被重构为对索引序列和\QS[]
(转换的)基因的调用字符串\Qsep[]
。它们都以原始顺序出现在切片中。因此,例如,用户格式方程(x = a_avg + ([x-1] /b_trans)^(-y^[-x])
)一旦被切片并被转换\interpreteq
,就会通过以下表达式重构为 DNA 链:
\Q [1,1,1,1,1,1,1]\QS [1]\Q [2,1,1,1,1,1,1]\QS [2,1,1,1,1,1]\Q [2,1,1,1,1,2,1]\QS
[2,1,1,1,1]\Q [2,1,1,1,2,1,1]\QS [2,1]\Q [2,2,1,1,1,1,1]\QS [2,2]\Q [2,3,1,1,1,1,1]\QS
[2,3,1,1,1]\Q [2,3,1,1,2,1,1]\QS [2,3]\Q [2,4,1,1,1,1,1]\QS [2,4,1,1]\Q [2,4,1,2,1,1,1]\QS
[2,4,1,2,1,1]\Q [2,4,1,2,1,2,1]\QS [2,4]\Q [2,5,1,1,1,1,1]\QS [2,5,1]\Q [2,5,2,1,1,1,1]\QS
[2,5]\Q [2,6,1,1,1,1,1]\QS [2,6,1,1,1]\Q [2,6,1,1,2,1,1]\QS [2,6,1]\Q [2,6,2,1,1,1,1]\QS
[2,6]\Q [2,7,1,1,1,1,1]\QS [2,7,1,1,1]\Q [2,7,1,1,2,1,1]\QS [2,7]\Q [2,8,1,1,1,1,1]\QS
[2,8]\Q [2,9,1,1,1,1,1]
并且,基于\Q
和中的基因\QS
,结果看起来像是期望的,即
翻译方程式
翻译可以通过宏形式实现,\translateeq{}
也可以通过空间分离方程的翻译环境实现
\begin{translateeqs}% NO BLANK LINE IS PERMITTED HERE
EQ1
EQ2
...
EQn
\end{translateeqs}% NO BLANK LINE IS PERMITTED BEFORE HERE
这仅通过临时重新定义过程中的几个关键宏并使用将和基因\protected@edef
扩展为它们相关的 LaTeX 代码来实现。然后,生成的方程式不会像以前一样呈现,而是以去标记化的 LaTeX 代码呈现。 \Q
\QS
实际上,翻译可以在单独的文档中完成,并将结果从生成的 PDF 复制并粘贴到目标源文档中。
数学家
您将在以下 MWE 中看到的 5 个方程式(解释和翻译)均以非 LaTeX 形式输入。转换过程的显著亮点包括处理多字符下标而不进行分组、识别大量文本(非宏)数学函数和希腊字母名称(可以添加更多)、自动转换/
为分数、自动调整括号大小、转换*
为\cdot
等。以下是 5 个方程式:
cos(1/s) = f*g
f(x) = y^(2*x) =beta
f(x) = pi * y^[((2/x)^3 + [B/x_i])^n] =(z/B)^(2/x_i)
f(x) = pi * y^[((2/x)^3 + B/x_i )^n] =(z/B)^(2/x_i)
x = a_avg + ([x-1] /b_trans)^(-y^[-x])
以下是 MWE:
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage{listofitems,ifthen}
\def\QS[#1]{%
\if+\Qsep[#1]+\else%
\if-\Qsep[#1]-\else%
\if/\Qsep[#1]\over\else%
\if=\Qsep[#1]=\else%
\if^\Qsep[#1]^\else%
\if(\Qsep[#1]\bgroup\left(\else%
\if)\Qsep[#1]\right)\egroup\else%
\if[\Qsep[#1]\bgroup\else%
\if]\Qsep[#1]\egroup\else%
\if*\Qsep[#1]\cdot\else%
\if_\Qsep[#1]\expandafter\theund\else%
\csname \Qsep[#1]\endcsname\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi%
}%
\def\theund#1[#2]{_{\mathrm{#1[#2]}}}%
\setsepchar[@]{=@(||)||[||]@^@/||*@+||-@_@alpha||beta||pi||cos||sin||tan}
\makeatletter
\def\gQ[#1]{\edef\tmp{#1}\expandafter\g@addto@macro\expandafter\Z%
\expandafter{\expandafter\Q\expandafter[\tmp]}}
\def\gQS[#1]{\edef\tmp{#1}\expandafter\g@addto@macro\expandafter\Z%
\expandafter{\expandafter\QS\expandafter[\tmp]}}
\makeatother
\newcommand\interpreteq[1]{%
\def\Z{}%
\greadlist*\Q{#1}%
\presentQ%
\Z%
}
\newcounter{lindex}
\def\presentQ{% =
\setcounter{lindex}{0}%
\whiledo{\value{lindex}<\listlen\Q[]}{%
\stepcounter{lindex}%
\presentQA[\thelindex]%
\ifnum\value{lindex}<\listlen\Q[]\relax%
\gQS[\thelindex]%
\fi%
}%
}
\newcounter{lindexA}
\def\presentQA[#1]{% ()
\setcounter{lindexA}{0}%
\whiledo{\value{lindexA}<\listlen\Q[#1]}{%
\stepcounter{lindexA}%
\presentQB[#1,\thelindexA]%
\ifnum\value{lindexA}<\listlen\Q[#1]\relax%
\gQS[#1,\thelindexA]%
\fi%
}
}
\newcounter{lindexB}
\def\presentQB[#1]{% ^
\setcounter{lindexB}{0}%
\whiledo{\value{lindexB}<\listlen\Q[#1]}{%
\stepcounter{lindexB}%
\presentQC[#1,\thelindexB]%
\ifnum\value{lindexB}<\listlen\Q[#1]\relax%
\gQS[#1,\thelindexB]%
\fi%
}
}
\newcounter{lindexC}
\def\presentQC[#1]{% /*
\setcounter{lindexC}{0}%
\whiledo{\value{lindexC}<\listlen\Q[#1]}{%
\stepcounter{lindexC}%
\presentQD[#1,\thelindexC]%
\ifnum\value{lindexC}<\listlen\Q[#1]\relax%
\gQS[#1,\thelindexC]%
\fi%
}
}
\newcounter{lindexD}
\def\presentQD[#1]{% +-
\setcounter{lindexD}{0}%
\whiledo{\value{lindexD}<\listlen\Q[#1]}{%
\stepcounter{lindexD}%
\presentQE[#1,\thelindexD]%
\ifnum\value{lindexD}<\listlen\Q[#1]\relax%
\gQS[#1,\thelindexD]%
\fi%
}
}
\newcounter{lindexE}
\def\presentQE[#1]{% _
\setcounter{lindexE}{0}%
\whiledo{\value{lindexE}<\listlen\Q[#1]}{%
\stepcounter{lindexE}%
\presentQF[#1,\thelindexE]%
\ifnum\value{lindexE}<\listlen\Q[#1]\relax%
\gQS[#1,\thelindexE]%
\fi%
}
}
\newcounter{lindexF}
\def\presentQF[#1]{% alpha beta pi cos sin tan
\setcounter{lindexF}{0}%
\whiledo{\value{lindexF}<\listlen\Q[#1]}{%
\stepcounter{lindexF}%
\gQ[#1,\thelindexF]%
\ifnum\value{lindexF}<\listlen\Q[#1]\relax%
\gQS[#1,\thelindexF]%
\fi%
}
}
% THESE ARE THE REDEFITIIONS FOR TRANSLATION
\usepackage{environ}
\def\QSALT[#1]{%
\if+\Qsep[#1]+\else%
\if-\Qsep[#1]-\else%
\if/\Qsep[#1]\over\else%
\if=\Qsep[#1]=\else%
\if^\Qsep[#1]^\else%
\if(\Qsep[#1]{\left(\else%
\if)\Qsep[#1]\right)}\else%
\if[\Qsep[#1]{\else%
\if]\Qsep[#1]}\else%
\if*\Qsep[#1]\cdot\else%
\if_\Qsep[#1]\expandafter\theundALT\else%
\expandafter\noexpand\csname \Qsep[#1]\endcsname\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi%
}%
\def\theundALT#1[#2]{_{\noexpand\mathrm{#1[#2]}}}%
\makeatletter
\newcommand\translateeq[1]{%
\bgroup%
\let\QS\QSALT%
\def\Z{}%
\greadlist*\Q{#1}%
\presentQ%
\protected@edef\ZZ{\Z}
\par\medskip\noindent%
\parbox{\linewidth}{\detokenize\expandafter{\ZZ}}%
\par\medskip%
\egroup%
}
\makeatother
\NewEnviron{translateeqs}{\expandafter\nexteqn\BODY\par\relax}
\long\def\nexteqn#1\par#2\relax{%
\translateeq{#1}\ifx\relax#2\else\nexteqn#2\relax\fi%
}
\begin{document}
\textbf{INTERPRETATING EQUATIONS}
\[
\interpreteq{cos(1/s) = f*g}
\]
\[
\interpreteq{f(x) = y^(2*x) =beta}
\]
\[
\interpreteq{f(x) = pi * y^[((2/x)^3 + [B/x_i])^n] =(z/B)^(2/x_i)}
\]
\[
\interpreteq{f(x) = pi * y^[((2/x)^3 + B/x_i )^n] =(z/B)^(2/x_i)}
\]
\[
\interpreteq{x = a_avg + ([x-1] /b_trans)^(-y^[-x])}
\]
This is the code ``DNA'' that expresses the above equation:
\detokenize\expandafter{\Z}% COPY/PASTE RESULT OF THIS FROM PDF TO BELOW
See? I copied/pasted it into equation mode and get the same result.
\[
\Q [1,1,1,1,1,1,1]\QS [1]\Q [2,1,1,1,1,1,1]\QS [2,1,1,1,1,1]\Q [2,1,1,1,1,2,1]\QS
[2,1,1,1,1]\Q [2,1,1,1,2,1,1]\QS [2,1]\Q [2,2,1,1,1,1,1]\QS [2,2]\Q [2,3,1,1,1,1,1]\QS
[2,3,1,1,1]\Q [2,3,1,1,2,1,1]\QS [2,3]\Q [2,4,1,1,1,1,1]\QS [2,4,1,1]\Q [2,4,1,2,1,1,1]\QS
[2,4,1,2,1,1]\Q [2,4,1,2,1,2,1]\QS [2,4]\Q [2,5,1,1,1,1,1]\QS [2,5,1]\Q [2,5,2,1,1,1,1]\QS
[2,5]\Q [2,6,1,1,1,1,1]\QS [2,6,1,1,1]\Q [2,6,1,1,2,1,1]\QS [2,6,1]\Q [2,6,2,1,1,1,1]\QS
[2,6]\Q [2,7,1,1,1,1,1]\QS [2,7,1,1,1]\Q [2,7,1,1,2,1,1]\QS [2,7]\Q [2,8,1,1,1,1,1]\QS
[2,8]\Q [2,9,1,1,1,1,1]
\]
\textbf{TRANSLATING EQUATIONS}
\begin{translateeqs}% NO BLANK LINE IS PERMITTED HERE
cos(1/s) = f*g
f(x) = y^(2*x) =beta
f(x) = pi * y^[((2/x)^3 + [B/x_i])^n] =(z/B)^(2/x_i)
f(x) = pi * y^[((2/x)^3 + B/x_i )^n] =(z/B)^(2/x_i)
x = a_avg + ([x-1] /b_trans)^(-y^[-x])
\end{translateeqs}% NO BLANK LINE IS PERMITTED BEFORE HERE
\translateeq{x = a_avg + ([x-1] /b_trans)^(-y^[-x])}
\end{document}