AsciiMath Parser

   

Asciimath 是什么?

一种 JavaScript 实现的简易的数学公式标记语言,相比 LaTeX\LaTeX 更加易学易用。

如何使用

API

你可以使用 asciimath-parser 或者 asciimath-parser-nearley,如果想要使用前者,阅读本文档即可,而如果是后者,可能存在一些区别,请参照其 README.

基本使用

使用 npm/yarn/pnpm 包管理工具安装。

pnpm i -D asciimath-parser

引入 AsciiMath,创建实例,使用 toTex 方法来生成 LaTeX 代码。

import { AsciiMath } from 'asciimath-parser'
const am = new AsciiMath()
console.log(am.toTex('sum_(n=1)^(+oo)1/n^2=pi^2/6'))
// \displaystyle{ \sum _{ n = 1 } ^{ + \infty } \frac{ 1 }{ n ^{ 2 } } = \frac{ \pi ^{ 2 } }{ 6 } }

配置参数与扩展语法

以下为 AsciiMath 在构造时接受的参数类型

type ReplaceLaw = [RegExp | string, string | ((substring: string, ...args: any[]) => string)]

interface AsciiMathConfig {
  display?: boolean
  replaceBeforeTokenizing?: ReplaceLaw[]
  symbols?: Array<[string, SymbolValueType]> | Record<string, SymbolValueType>
}
display

指定生成的公式是否被包含在 \displaystyle 环境下,默认值为 true

replaceBeforeTokenizing

在公式被处理之前,将匹配到的字符串替换为目标串,然后再传入 AsciiMath 处理

点击查看详情

例如这样指定它

const cfg: AsciiMathConfig = {
  replaceBeforeTokenizing: [
    [/d0/g, '{:"d"theta:}'],
    [/x(\d+)/g, (_, $1) => `x^(${$1})`],
  ]
}
const am = new AsciiMath(cfg) // 实例化
console.log(am.toTex('...'))

那么,在公式被解析之前,会先进行如下操作

  • 将字符串 d0 转换为 {:"d"theta:},然后 AsciiMath 将 {:"d"theta:} 处理为 { \text{d} \theta }
  • 将类似 x2, x10 转换为 x^(2) 以及 x^(10),然后 AsciiMath 再将其分别转换为 x^{ 2 }x^{ 10 }
symbols

指定扩展的 TokenType,所有的 Token 类型可参考 symbols.ts,但是不建议随意扩展 Token。下面列出建议扩展的类型:

enum TokenTypes {
  Const, // 将匹配到的字符串翻译为目标 tex 代码
  OperatorOA, // 带有一个参数的操作符,例如绝对值 `abs(a)`
  OperatorOAB, // 带有两个参数的操作符,例如分数 `frac(a)(b)`
  OperatorAOB, // 中缀操作符,例如除法 `a / b`
  OperatorAO, // 后缀操作符,例如阶乘 `!`
}
点击查看详情

例如,指定 symbols 的值为

const cfg: AsciiMathConfig = {
  symbols: {
    dx: { type: TokenTypes.Const, tex: '{\\mathrm{d}x}' },
    rm: { type: TokenTypes.OperatorOA, tex: '\\mathrm{$1}', eatNext: true },
    frac: { type: TokenTypes.OperatorOAB, tex: '\\frac{ $1 }{ $2 }' },
    over: { type: TokenTypes.OperatorAOB, tex: '{ $1 \\over $2 }' },
  }
}
const am = new AsciiMath(cfg) // 实例化
console.log(am.toTex('...'))

那么 dx, rm, frac, over 将会成为对应的 Token 被识别,最终会达到下面的效果

  • dx 生成的代码就是 {\mathrm{d}x}

  • rm(absc) 生成的代码为 \mathrm{absc},其中 absc 即为 rm 这个操作符的参数,$1 将会被 absc 替换

    其中 eatNext 的作用是,直接将下一个单词读取为字符串,而不识别其中的任何 token. 上面的例子中,absc 包含的关键字 abs,但是程序并不会将它读取为 absc,而将它直接处理为 absc 字符串,并用它替换掉模板中的 $1.

    如果不设置 eatNexttrue,那么得到的结果就是 \mathrm{ \left|c\right| }.

    如果你想要读取更长的字符串,可以用双引号或者圆括号来包裹这个串,例如 rm "here is a mathrm block".

    eatNext 参数只建议与 OperatorOAOperatorOAB 两种类型一起使用.

  • frac(m)(n) 生成的代码为 \frac{ m }{ n }$1$2 会分别被 mn 替换

  • a over b 生成的代码为 { a \over b }$1$2 会分别被 ab 替换

Cli

使用包管理工具安装,可以使用全局安装或本工作环境安装。

pnpm add -g asciimath-parser-cli

输入一个文件,将所有被 反引号 ` 包裹的公式都转换为被 美元符 $ 包裹的 LaTeX 公式。

am-parse input.txt
# 将会生成 input_parsed_xxx.tex

使用场景

注意

  • 这个库是由我个人重构的,一些语法可能与 asciimath.org 原版不同,尤其是矩阵,使用时请格外注意。
  • Asciimath parser 只是简单的将输入的公式转换为 LaTeX 代码,并不依赖于 DOM 和 mathml,如果你需要可视化呈现这些公式,请与 KaTeX 或 mathjax 等这些工具一起使用。

特别感谢

zmx0142857 的笔记以及他的帮助。

遇到问题

请至 GitHub issue 提供能够稳定复现的情况并给出适当的报错信息。

样例

主题输出源码
上下标a12+b12=c12\displaystyle{ a _{ 1 } ^{ 2 } + b _{ 1 } ^{ 2 } = c _{ 1 } ^{ 2 } }a_1^2 + b_1^2 = c_1^2
文本hello world\displaystyle{ \text{hello world} }"hello world"
分式ab,a/b\displaystyle{ \frac{ a }{ b } , a {/} b }a/b, a//b
根式n,xn,a2b\displaystyle{ \sqrt{ n } , \sqrt[ n ]{ x } , \frac{ a ^{ 2 } }{ \sqrt{ b } } }sqrt n, root n x, a^2/sqrt b
极限limn(1+1n)n\displaystyle{ \lim _{ n \to \infty } \left( 1 + \frac{ 1 }{ n } \right) ^{ n } }lim_(n->oo) (1+1/n)^n
积分abf(x)dx\displaystyle{ \int _{ a } ^{ b } f \left( x \right) {\text{d}x} }int_a^b f(x) dx
隐形括号sinx2\displaystyle{ \sin { \frac{ x }{ 2 } } }sin {: x/2 :}
微分dydx,drdθ,f(x)\displaystyle{ \frac{ {\text{d}y} }{ {\text{d}x} } , \frac{ \text{d} r }{ \text{d} \theta } , f ^{\prime\prime} \left( x \right) }dy/dx, ("d"r)/("d"theta), f''(x)
微分(实验性)dfdx,d2fdx2,x¨\displaystyle{ \frac{ \mathrm{d} f }{ \mathrm{d} x } , \frac{ \mathrm{d} ^{ 2 } f }{ \mathrm{d} x ^{ 2 } } , \ddot{ x } }ddfx , dd^2 f x , ddot x
偏微分fx,3fxy2\displaystyle{ \frac{ \partial f }{ \partial x } , \frac{ \partial ^{ 3 } f }{ \partial x \partial y ^{ 2 } } }(del f)/(del x), (del^3 f)/(del x del y^2)
偏微分(实验性)fx,3fxy2,x\displaystyle{ \frac{ \partial f }{ \partial x } , \frac{ \partial ^{ 3 } f }{ \partial x \partial y ^{ 2 } } , \frac{ \partial { } }{ \partial x } }ppfx, pp^3 f (x y^2), pp {::} x
矩阵[abcd],[abcdef]\displaystyle{ \left[ \begin{array}{cc} a & b \\ c & d \end{array} \right] , \left[ \begin{array}{cc|c} a & b & c \\ d & e & f \end{array} \right] }[a, b; c, d], [a, b | c; d, e | f]
分段函数x={xifx>0xotherwise\displaystyle{ \left| x \right| = \left\lbrace \begin{array}{ll} x & \text{if}\quad x > 0 \\ - x & \text{otherwise}\quad \end{array} \right. }|x| = { x, if x > 0; -x, otherwise :}

符号对照手册

希腊字母

输出源码输出源码输出源码输出源码
α\displaystyle{ \alpha }alphaβ\displaystyle{ \beta }betaχ\displaystyle{ \chi }chiδ\displaystyle{ \delta }delta
Δ\displaystyle{ \Delta }Deltaε\displaystyle{ \varepsilon }epsiϵ\displaystyle{ \epsilon }epsilonη\displaystyle{ \eta }eta
γ\displaystyle{ \gamma }gammaΓ\displaystyle{ \Gamma }Gammaι\displaystyle{ \iota }iotaκ\displaystyle{ \kappa }kappa
λ\displaystyle{ \lambda }lambdaΛ\displaystyle{ \Lambda }Lambdaμ\displaystyle{ \mu }muν\displaystyle{ \nu }nu
ω\displaystyle{ \omega }omegaΩ\displaystyle{ \Omega }Omegaϕ\displaystyle{ \phi }phiφ\displaystyle{ \varphi }varphi
Φ\displaystyle{ \Phi }PhiΦ\displaystyle{ \varPhi }varPhiπ\displaystyle{ \pi }piΠ\displaystyle{ \Pi }Pi
ψ\displaystyle{ \psi }psiΨ\displaystyle{ \Psi }Psiρ\displaystyle{ \rho }rhoσ\displaystyle{ \sigma }sigma
Σ\displaystyle{ \Sigma }Sigmaτ\displaystyle{ \tau }tauθ\displaystyle{ \theta }thetaϑ\displaystyle{ \vartheta }vartheta
Θ\displaystyle{ \Theta }Thetaυ\displaystyle{ \upsilon }upsilonξ\displaystyle{ \xi }xiΞ\displaystyle{ \Xi }Xi
ζ\displaystyle{ \zeta }zeta

括号

输出源码输出源码输出源码输出源码
(\displaystyle{ \left( \right. }()\displaystyle{ ) })\displaystyle{ \left. \right. }{:.\displaystyle{ . }:}
[\displaystyle{ \left[ \right. }[]\displaystyle{ ] }]{\displaystyle{ \left\lbrace \right. }{}\displaystyle{ \rbrace }}
\displaystyle{ \left\langle \right. }(:\displaystyle{ \rangle }:)\displaystyle{ \left\lfloor \right. }|__\displaystyle{ \rfloor }__|
\displaystyle{ \left\lceil \right. }|~\displaystyle{ \rceil }~|\displaystyle{ \mid }|x\displaystyle{ \left| x \right| }abs(x)
v\displaystyle{ \left\| \mathbf{ v } \right\| }norm(bb(v))x2\displaystyle{ \left\lfloor \frac{ x }{ 2 } \right\rfloor }floor(x/2)x3\displaystyle{ \left\lceil \frac{ x }{ 3 } \right\rceil }ceil(x/3)

算数运算符

输出源码输出源码输出源码输出源码
+\displaystyle{ + }+\displaystyle{ - }-\displaystyle{ \cdot }*\displaystyle{ \ast }**
/\displaystyle{ {/} }//\\displaystyle{ \backslash }\\×\displaystyle{ \times }xx÷\displaystyle{ \div }-:
\displaystyle{ \circ }@\displaystyle{ \oplus }o+\displaystyle{ \otimes }ox\displaystyle{ \odot }o.
\displaystyle{ \sum }sum\displaystyle{ \prod }prod\displaystyle{ \wedge }^^\displaystyle{ \bigwedge }^^^
\displaystyle{ \vee }vv\displaystyle{ \bigvee }vvv\displaystyle{ \cap }nn\displaystyle{ \bigcap }nnn
\displaystyle{ \cup }uu\displaystyle{ \bigcup }uuu%\displaystyle{ \% }%

关系运算符

输出源码输出源码输出源码输出源码
=\displaystyle{ = }=\displaystyle{ \ne }!=\displaystyle{ \equiv }-=≢\displaystyle{ \not\equiv }!-=
\displaystyle{ \cong }~=\displaystyle{ \approx }~~<\displaystyle{ < }lt>\displaystyle{ > }gt
\displaystyle{ \ge }ge\displaystyle{ \le }le\displaystyle{ \leqslant }<=\displaystyle{ \geqslant }>=
\displaystyle{ \prec }-<\displaystyle{ \succ }>-\displaystyle{ \in }in\displaystyle{ \notin }!in
\displaystyle{ \subset }sub\displaystyle{ \supset }sup\displaystyle{ \subseteq }sube\displaystyle{ \supseteq }supe
⊈\displaystyle{ \not\subseteq }!sube\displaystyle{ \subsetneqq }subne\displaystyle{ \unlhd }normal\displaystyle{ \unrhd }rnormal
\displaystyle{ \lhd }lhd\displaystyle{ \rhd }rhd\displaystyle{ ∽ }S~\displaystyle{ \propto }prop
\displaystyle{ \complement }complement

逻辑运算符

输出源码输出源码输出源码输出源码
 and \displaystyle{ \text{ and } }and or \displaystyle{ \text{ or } }or¬\displaystyle{ \neg }not\displaystyle{ \Rightarrow }rArr
if\displaystyle{ \text{if}\quad }if    \displaystyle{ \iff }iff\displaystyle{ \forall }AA\displaystyle{ \exists }EE
\displaystyle{ \bot }_|_\displaystyle{ \top }TT\displaystyle{ \vdash }|--\displaystyle{ \models }|==

杂项

输出源码输出源码输出源码输出源码
\displaystyle{ \int }int\displaystyle{ \iint }iint\displaystyle{ \iiint }iiint\displaystyle{ \oint }oint
\displaystyle{ \partial }del\displaystyle{ \nabla }grad±\displaystyle{ \pm }+-\displaystyle{ \varnothing }O/
\displaystyle{ \infty }oo\displaystyle{ \aleph }aleph\displaystyle{ \angle }/_\displaystyle{ \therefore }:.
\displaystyle{ \because }:'\displaystyle{ \ldots }...\displaystyle{ \cdots }cdots\displaystyle{ \vdots }vdots
\displaystyle{ \ddots }ddots\displaystyle{ \square }squareN\displaystyle{ \mathbb{N} }NNQ\displaystyle{ \mathbb{Q} }QQ
R\displaystyle{ \mathbb{R} }RRC\displaystyle{ \mathbb{C} }CCZ\displaystyle{ \mathbb{Z} }ZZ(Nk)\displaystyle{ { N \choose k } }N choose k

数学函数

输出源码输出源码输出源码输出源码
sin\displaystyle{ \sin }sincos\displaystyle{ \cos }costan\displaystyle{ \tan }tancot\displaystyle{ \cot }cot
sec\displaystyle{ \sec }seccsc\displaystyle{ \csc }cscsinh\displaystyle{ \sinh }sinhcosh\displaystyle{ \cosh }cosh
tanh\displaystyle{ \tanh }tanhcoth\displaystyle{ \coth }cothcsch\displaystyle{ \operatorname{csch} }cschsech\displaystyle{ \operatorname{sech} }sech
arcsin\displaystyle{ \arcsin }arcsinarccos\displaystyle{ \arccos }arccosarctan\displaystyle{ \arctan }arctanlog\displaystyle{ \log }log
ln\displaystyle{ \ln }lndet\displaystyle{ \det }detdim\displaystyle{ \dim }dimlim\displaystyle{ \lim }lim
mod\displaystyle{ \operatorname{mod} }modgcd\displaystyle{ \gcd }gcdlcm\displaystyle{ \operatorname{lcm} }lcmmin\displaystyle{ \min }min
max\displaystyle{ \max }maxsgn\displaystyle{ \operatorname{sgn} }sgnsup\displaystyle{ \sup }Supinf\displaystyle{ \inf }inf
exp\displaystyle{ \exp }exp

箭头

输出源码输出源码输出源码输出源码
\displaystyle{ \uparrow }uarr\displaystyle{ \downarrow }darr\displaystyle{ \rightarrow }rarr\displaystyle{ \leftarrow }larr
\displaystyle{ \to }->\displaystyle{ \mapsto }|->\displaystyle{ \leftrightarrow }harr\displaystyle{ \Rightarrow }rArr
\displaystyle{ \Leftarrow }lArr\displaystyle{ \Leftrightarrow }hArr\displaystyle{ \twoheadrightarrow }->>\displaystyle{ \rightarrowtail }>->
\displaystyle{ \curvearrowleft }curvArrLt\displaystyle{ \curvearrowright }curvArrRt\displaystyle{ \circlearrowleft }circArrLt\displaystyle{ \circlearrowright }circArrRt
\displaystyle{ \rightsquigarrow }~>\displaystyle{ \nrightarrow }-/->\displaystyle{ \nleftarrow }<-/-\displaystyle{ \nleftrightarrow }<-/->

字体

输出源码输出源码输出源码输出源码
A\displaystyle{ \mathbf{ A } }bb AA\displaystyle{ \boldsymbol{ A } }bm AA\displaystyle{ \mathbb{ A } }bbb AA\displaystyle{ \mathcal{ A } }cc A
A\displaystyle{ \mathtt{ A } }tt AA\displaystyle{ \mathfrak{ A } }fr AA\displaystyle{ \mathsf{ A } }sf AA\displaystyle{ \mathscr{ A } }scr A

注音符号

输出源码输出源码输出源码输出源码
x^\displaystyle{ \hat{ x } }hat xxˉ\displaystyle{ \bar{ x } }bar xx\displaystyle{ \underline{ x } }ul xx\displaystyle{ \vec{ x } }vec x
x˙\displaystyle{ \dot{ x } }dot xx¨\displaystyle{ \ddot{ x } }ddot xx\displaystyle{ \stackrel{\frown}{ x } }arc xx~\displaystyle{ \tilde{ x } }tilde x
AB\displaystyle{ \overrightarrow{ A B } }Vec(AB)AB^\displaystyle{ \widehat{ A B } }Hat(AB)AB~\displaystyle{ \widetilde{ A B } }Tilde(AB)

上下叠合

输出源码输出源码
xbala\displaystyle{ \overset{ \text{bala} }{ x } }overset("bala")(x)12345n\displaystyle{ \overbrace{ 12345 } ^{ n } }overbrace(12345)^n
12345n\displaystyle{ \underbrace{ 12345 } _{ n } }underbrace(12345)_n=123456\displaystyle{ \xlongequal[ 123 ]{ 456 } }==_(123)^(456)
ab\displaystyle{ \xrightarrow[ a ]{ b } }-->_(a)^(b)ab\displaystyle{ { a \atop b } }a atop b

特殊

输出源码输出源码
I’m here\displaystyle{ \text{I'm here} }text(I'm here)\displaystyle{ \hbar }tex"\hbar"
abc\displaystyle{ { \color{red} ab c } }color(red)(abc)hello world\displaystyle{ \text{hello world} }"hello world"

转义符号

输出源码输出源码输出源码输出源码
#\displaystyle{ \# }\#$\displaystyle{ \$ }\$@\displaystyle{ @ }\@_\displaystyle{ \_ }\_

字体大小

输出源码输出源码
text\displaystyle{ {\tiny \text{text} } }tiny "text"text\displaystyle{ {\small \text{text} } }small "text"
text\displaystyle{ {\large \text{text} } }large "text"text\displaystyle{ {\huge \text{text} } }huge "text"

语法糖

输出源码输出源码输出源码输出源码
dx\displaystyle{ {\text{d}x} }dxdy\displaystyle{ {\text{d}y} }dydz\displaystyle{ {\text{d}z} }dzdt\displaystyle{ {\text{d}t} }dt

使用 # 来插入 displaystyle

输出源码
[2fx22fxy2fyx2fy2]\displaystyle{ \left[ \begin{array}{cc} \displaystyle \frac{ \partial ^{ 2 } f }{ \partial x ^{ 2 } } & \frac{ \partial ^{ 2 } f }{ \partial x \partial y } \\ \frac{ \partial ^{ 2 } f }{ \partial y \partial x } & \displaystyle \frac{ \partial ^{ 2 } f }{ \partial y ^{ 2 } } \end{array} \right] }[#part^2 f x, part^2 f (x y); part^2 f (y x), #part^2 f y]

使用 aligned 环境

f(x) & = x "e"^x
                            <-- 一个空行
f'(x) & = (x + 1) "e"^x
                            <-- 一个空行
f''(x) & = (x + 2) "e"^x
f(x)=xexf(x)=(x+1)exf(x)=(x+2)ex\displaystyle{ \begin{aligned}f \left( x \right) & = x \text{e} ^{ x } \\ f ^{\prime} \left( x \right) & = \left( x + 1 \right) \text{e} ^{ x } \\ f ^{\prime\prime} \left( x \right) & = \left( x + 2 \right) \text{e} ^{ x }\end{aligned} }

注意 & 相当于 LaTeX 中的 &,而上述的空行相当于 LaTeX 中的 \\ 换行

空白

输出源码宽度
ab\displaystyle{ a \quad b }a quad b1 em
ab\displaystyle{ a \qquad b }a qquad b2 em
ab\displaystyle{ a \enspace b }a enspace b0.5 em
a  b\displaystyle{ a \; b }a \; b5/18 em
ab\displaystyle{ a \: b }a \: b4/18 em
ab\displaystyle{ a \, b }a \, b3/18 em
a ⁣b\displaystyle{ a \! b }a \! b-3/18 em
ab\displaystyle{ a \hspace{12pt} b }a hspace(12pt) b12 pt
Playground built with Astro     Deploys on Netlify