有没有什么简单的方法可以适应soulutf8
LaTeX 数学模式分隔符?
截至目前,编译
\documentclass{article}
\usepackage{xcolor,soulutf8}
\begin{document}
Well, \hl{\(e^{i\pi}=-1\)}.
\end{document}
结果pdflatex
是
! Extra }, or forgotten $.
\SOUL@doword ...hskip \z@ \relax \the \SOUL@word }
\let \SOUL@errmsg \SOUL@er...
l.4 Well, \hl{\(e^{i\pi}=-1\)}
.
? X
让我们不要进入讨论哪一个更好:$...$
或者\(...\)
;理所当然地认为排字员有他/她的理由选择第二对分隔符。
PS 正如 Heiko 指出的那样,同样的问题也存在于 soul 中(不幸的是,目前它似乎缺少一个活跃的维护者),其文档特别提到了这个限制。
答案1
可以解析 的参数,\hl
用 替换该参数中的所有\(...\)
内容$...$
,然后使用 的原始定义\hl
。我不完全确定以下内容是否完全稳定,尽管到目前为止它对我遇到的所有问题都有效。
编辑:通过删除从不匹配的情况(##3
是点并且##2
不是)来最小化代码,并且不在\(.\)
替换的每次递归中包含标记,而只包含一次(这足够了,因为##3
在递归的情况下它们存在)。
请注意,存在有效但奇怪的语法的情况(如果在 的参数之外使用\hl
)会在这里失败:如果将和或$
之一混合作为分隔符,则提供的代码会失败;尽管或是有效语法,但会失败,因为它们与 的所需参数模式不匹配。\(
\)
$a^b\)
\(a^b$
\hl{$a^b\)}
\hl{\(a^b$}
\hl@grab
\documentclass{article}
\usepackage{xcolor,soulutf8}
\usepackage[]{amsmath}
\usepackage{letltxmacro}
\LetLtxMacro\hlBAK\hl
\begingroup
\makeatletter
\catcode`.=4% changing catcode so the dot is never matched by ordinary text
\def\zz%
{\endgroup
\renewcommand\hl[1]
{%
\hl@grab##1\(.\)\endhl@grab
}%
\long\def\hl@grab##1\(##2\)##3\endhl@grab%
{%
\hl@grab@ifdot{##2}
{\hlBAK{##1}}
{\hl@grab##1$##2$##3\endhl@grab}%
}%
\long\def\hl@grab@ifdot##1%
{%
\ifx.##1%
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}%
}%
\zz
\begin{document}
Well, \hl{\(.e^{i\pi}=-1\) text \(2=2\).}
\end{document}
编辑:下面使用两个宏来提供替换,一个宏用于替换\(
,另一个宏用于替换\)
。 因此, 和 的奇怪(但技术上正确)语法\(a^b$
也$a^b\)
应该作为 的参数\hl
(尽管这种方式\hl{\(a^b\( text $a^b$}
也可以工作,但显然不是正确的语法)。
\documentclass{article}
\usepackage{xcolor,soulutf8}
\usepackage[]{amsmath}
\usepackage{letltxmacro}
\LetLtxMacro\hlBAK\hl
\begingroup
\makeatletter
\catcode`.=4% changing catcode so the dot is never matched by ordinary text
\def\zz%
{\endgroup
\renewcommand\hl[1]
{%
\hl@grab@A##1\(.\endhl@grab
}%
\long\def\hl@grab##1\(##2\)##3\endhl@grab%
{%
\hl@grab@ifdot{##2}
{\hlBAK{##1}}
{\hl@grab##1$##2$##3\endhl@grab}%
}%
\long\def\hl@grab@A##1\(##2\endhl@grab%\)
{%
\hl@grab@ifdot{##2}
{\hl@grab@B##1\).\endhl@grab}
{\hl@grab@A##1$##2\endhl@grab}%
}%
\long\def\hl@grab@B##1\)##2\endhl@grab%
{%
\hl@grab@ifdot{##2}
{\hlBAK{##1}}
{\hl@grab@B##1$##2\endhl@grab}%
}%
\long\def\hl@grab@ifdot##1%
{%
\ifx.##1%
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}%
}%
\zz
\begin{document}
Well, \hl{\(.e^{i\pi}=-1\) text \(2=2\).}
\hl{$a^b\)}\hl{\(a^b$}
\hl{\(a \(b$ $}
\end{document}
作为etl
一种更快但功能较少的替代方法,也可以替换l3regex
大括号内的:\(
\)
\documentclass{article}
\usepackage{xcolor,soul}
\usepackage{etl}
\NewCommandCopy\hlBAK\hl
\ExplSyntaxOn
\renewcommand\hl[1]
{
\exp_args:Ne \hlBAK
{
\etl_token_replace_all_deep:eNn
{ \etl_token_replace_all_deep:nNn {#1} \( { $ } }
\) { $ }
}
}
\cs_generate_variant:Nn \etl_token_replace_all_deep:nNn { e }
\ExplSyntaxOff
\begin{document}
\hl{\emph{Some important \( m = ath \)}}
\end{document}
答案2
使用l3regex
模块非常容易,并且适用于所有soul
命令。想法是重新定义\SOUL@start
,即根据调用宏的设置执行所有操作的宏。
\documentclass{article}
\usepackage{amsmath}
\usepackage{xcolor,soulutf8}
\ExplSyntaxOn
\tl_new:N \__l_SOUL_argument_tl
\cs_set_eq:Nc \SOUL_start:n { SOUL@start }
\cs_generate_variant:Nn \SOUL_start:n { V }
\cs_set_protected:cpn {SOUL@start} #1
{
\tl_set:Nn \__l_SOUL_argument_tl { #1 }
\regex_replace_all:nnN
{ \c{\(} (.*?) \c{\)} } % look for \(...\) (lazily)
{ \cM\$ \1 \cM\$ } % replace with $...$
\__l_SOUL_argument_tl
\SOUL_start:V \__l_SOUL_argument_tl % do the usual
}
\ExplSyntaxOff
\begin{document}
Well, \hl{\(e^{i\pi}=-1\) text \(2=2\).}
Well, \ul{\(e^{i\pi}=-1\) text \(2=2\).}
Well, \so{\(e^{i\pi}=-1\) text \(2=2\).}
Well, \caps{\(e^{i\pi}=-1\) text \(2=2\).}
Well, \st{\(e^{i\pi}=-1\) text \(2=2\).}
\end{document}
答案3
程序包不支持使用\(
和,来自\)
soul
文档:
§3数学:
例子:
\so{foo$x^3$bar}
允许使用数学公式,只要它们被 包围即可
$
。请注意,LaTeX 等效项
\(
...\)
不起作用。
因此,解决方法$
仍然是:
\hl{$e^{i\pi}=-1$}