<=
LaTeX 如何有效地用命令替换标记\leq
?
例 1:我有以下代码:
\[
2x <= 4x - 2
\]
我希望在编译后得到以下内容:
示例 2:
\[
q --> q
\]
输出:
示例 3:
\[
Q ==> Q
\]
输出:
答案1
"8000
我认为替换应该只在数学模式下进行。然后可以通过的特殊值激活起始字符\mathcode
。这些字符在文本模式下的行为与往常一样,但在数学模式下却变得特殊。
以下示例文档提供了以下简写的解析器:
<< : \ll (latexsym/amsmath)
<> : \neq
<= : \leq
<== : \Leftarrow
<=> : \Leftrightarrow
<-- : \leftarrow
<-> : \leftrightarrow
>> : \gg (latexsym/amsmath)
>= : \geq
--> : \rightarrow
-+ : \pm
+- : \mp
... : \dots (amsmath)
== : \equiv
=. : \doteq
==> : \Rightarrow
=( : \subseteq (latexsym/amsmath)
=) : \supseteq (latexsym/amsmath)
=[ : \sqsubseteq (latexsym/amsmath)
=] : \sqsubseteq (latexsym/amsmath)
示例文件:
\documentclass{article}
%\usepackage{latexsym}
% * because of \gg, \ll, \subseteq, \supseteq, \sqsubseteq, \sqsupseteq
% * not needed if amsmath is loaded
\usepackage{amsmath}% because of \dots
\makeatletter
% LaTeX's \@ifnextchar gobbles spaces, therefore
% \msh@ifnextchar is defined that keeps spaces
\newcommand*{\msh@ifnextchar}[3]{%
\def\msh@temp{\msh@@ifnextchar{#1}{#2}{#3}}%
\futurelet\msh@token\msh@temp
}
\newcommand*{\msh@@ifnextchar}[1]{%
\ifx\msh@token#1%
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
% <<
% <>
% <=
% <==
% <=>
% <--
% <->
% >>
% >=
% -->
% -+
% +-
% ...
% ==
% =.
% ==>
% =(
% =)
% =[
% =]
% Commands that take the original meanings of the special characters
\mathchardef\msh@code@less=\mathcode`\<\relax
\mathchardef\msh@code@greater=\mathcode`\>\relax
\mathchardef\msh@code@minus=\mathcode`\-\relax
\mathchardef\msh@code@plus=\mathcode`\+\relax
\mathchardef\msh@code@equal=\mathcode`\=\relax
\mathchardef\msh@code@dot=\mathcode`\.\relax
% Macro \resetmathshorthands resets the original meaning of the
% special characters by resetting their \mathcode values
\@ifdefinable{\resetmathshorthands}{%
\edef\resetmathshorthands{%
\mathcode\number`\<=\msh@code@less
\mathcode\number`\>=\msh@code@greater
\mathcode\number`\-=\msh@code@minus
\mathcode\number`\+=\msh@code@plus
\mathcode\number`\.=\msh@code@dot
\mathcode\number`\==\msh@code@equal
}%
}
% Macro \setmathshorthands activates and defines the special
% characters
\begingroup
\catcode`\<=\active
\catcode`\>=\active
\catcode`\-=\active
\catcode`\+=\active
\catcode`\.=\active
\catcode`\==\active
\edef={\string=}%
\@ifdefinable{\setmathshorthands}{%
\xdef\setmathshorthands{%
\mathcode\number`\<="8000 %
\mathcode\number`\>="8000 %
\mathcode\number`\-="8000 %
\mathcode\number`\+="8000 %
\mathcode\number`\.="8000 %
\mathcode\number`\=="8000 %
\let\noexpand<\noexpand\msh@less
\let\noexpand>\noexpand\msh@greater
\let\noexpand-\noexpand\msh@minus
\let\noexpand+\noexpand\msh@plus
\let\noexpand.\noexpand\msh@dot
\let\noexpand=\noexpand\msh@equal
}%
}%
\endgroup
% The parsers for the math shorthands follow:
% <<
% <>
% <=
% <==
% <=>
% <--
% <->
\newcommand*{\msh@less}{%
\msh@ifnextchar<{%
\ll\@gobble
}{%
\msh@ifnextchar>{%
\neq\@gobble
}{%
\msh@ifnextchar={%
\expandafter\msh@less@equal\@gobble
}{%
\msh@ifnextchar-{%
\expandafter\msh@less@minus\@gobble
}{%
\msh@code@less
}%
}%
}%
}%
}
\newcommand*{\msh@less@equal}{%
\msh@ifnextchar={%
\Leftarrow\@gobble
}{%
\msh@ifnextchar>{%
\Leftrightarrow\@gobble
}{%
\leq
}%
}%
}
\newcommand*{\msh@less@minus}{%
\msh@ifnextchar-{%
\leftarrow\@gobble
}{%
\msh@ifnextchar>{%
\leftrightarrow\@gobble
}{%
\msh@code@less\msh@code@minus
}%
}%
}
% >>
% >=
\newcommand*{\msh@greater}{%
\msh@ifnextchar>{%
\gg\@gobble
}{%
\msh@ifnextchar={%
\geq\@gobble
}{%
\msh@code@greater
}%
}%
}
% -->
% -+
\newcommand*{\msh@minus}{%
\msh@ifnextchar-{%
\expandafter\msh@minus@minus\@gobble
}{%
\msh@ifnextchar+{%
\mp\@gobble
}{%
\msh@code@minus
}%
}%
}
\newcommand*{\msh@minus@minus}{%
\msh@ifnextchar>{%
\rightarrow\@gobble
}{%
\msh@code@minus\msh@code@minus
}%
}
% +-
\newcommand*{\msh@plus}{%
\msh@ifnextchar-{%
\pm\@gobble
}{%
\msh@code@plus
}%
}
% ...
\newcommand*{\msh@dot}{%
\msh@ifnextchar.{%
\expandafter\msh@dot@dot\@gobble
}{%
\msh@code@dot
}%
}
\newcommand*{\msh@dot@dot}{%
\msh@ifnextchar.{%
\expandafter\msh@dot@dot@dot\@gobble
}{%
\msh@code@dot
\msh@code@dot
}%
}
\newcommand*{\msh@dot@dot@dot}{%
% remove space after "...", because a space would
% disturb \dots' auto-positioning feature.
\expandafter\dots\romannumeral-`\x
}
% ==
% =.
% ==>
% =(
% =)
% =[
% =]
\newcommand*{\msh@equal}{%
\msh@ifnextchar={%
\expandafter\msh@equal@equal\@gobble
}{%
\msh@ifnextchar.{%
\doteq\@gobble
}{%
\msh@ifnextchar({%
\subseteq\@gobble
}{%
\msh@ifnextchar){%
\supseteq\@gobble
}{%
\msh@ifnextchar[{%
\sqsubseteq\@gobble
}{%
\msh@ifnextchar]{%
\sqsupseteq\@gobble
}{%
\msh@code@equal
}%
}%
}%
}%
}%
}%
}
\newcommand*{\msh@equal@equal}{%
\msh@ifnextchar>{%
\Rightarrow\@gobble
}{%
\equiv
}%
}
\makeatother
% Activate math shorthands in the math modes
\everymath{\setmathshorthands}
\everydisplay{\setmathshorthands}
\begin{document}
\centering
\newcommand*{\test}[1]{%
$#1$%
\[#1\]%
}
\test{a << b < c <= d >= e > f >> g}
\test{a <> b = c =. d == e}
\test{a <== b <-- c <-> d <=> e --> f ==> g}
\test{a +- b = -(-a -+ +b)}
\test{a, ..., z <> a + ...+ z}
\test{a =( b =) c =[ e =] f}
\end{document}
评论:
宏
\msh@ifnextchar
查找下一个标记。与 LaTeX 相反,\@ifnextchar
它不会吞噬空格。例如,这对于a + -b
(a - b) 不同于a +- b
(一个±b)。...
\dots
被包替换amsmath
,因为它具有自动检测功能。点的垂直位置取决于下一个标记。例如,在逗号分隔的列表中,\dots
变为\ldots
;如果下一个标记是+
,则\cdots
使用 。在命令标记(如 )之后,空格会被吞噬
\dots
,但在其他字符(如 )之后则不会...
。因此,\msh@dot@dot@dot
在调用 之前会删除后面的空格\dots
。否则,即使空格后的标记是 ,\dots
也会看到空格并变成。\ldots
+
建议的
_C
对\subseteq
我来说太模糊了,因为它看起来像一个普通的下标C
。而且没有合适的 ASCII 字母可用于 的简写。因此,我为正方形形式\supseteq
实现了 的简写=(
和=)
对。=[
=]
如果等号后面有圆括号或方括号,则可以用空格来防止简写替换,例如
a = (b + c)
。
答案2
这是一个有趣的问题,可以通过比接受的答案更紧凑的宏来解决:
\long\def\isnextchar#1#2#3{\begingroup\toks0={\endgroup#2}\toks1={\endgroup#3}%
\let\tmp=#1\futurelet\next\isnextcharA
}
\def\isnextcharA{\the\toks\ifx\tmp\next0\else1\fi\space}
\def\skipnext#1#2{#1}
\def\trynext#1{\trynextA#1\relax\relax}
\def\trynextA#1#2\relax#3\relax#4#5{%
\ifx\relax#2\relax \def\next{\isnextchar#1{\skipnext{#4}}{#5#3}}\else
\def\next{\isnextchar#1{\skipnext{\trynextA#2\relax#3#1\relax#4{#5}}}{#5#3}}\fi
\next
}
\def\mspecdefA#1#2#3 : #4{\ifx#2\undefined
\def#2{\trynext{#3}#4{#1}}\else
\toks0={\trynext{#3}#4}\toks1=\expandafter{#2}%
\edef#2{\the\toks0{\the\toks1}}\fi
}
\def\mspecdef#1{%
\expandafter\ifx\csname m:#1\endcsname\relax
\expandafter\mathchardef\csname m:#1\endcsname=\mathcode`#1
\fi
\mathcode`#1="8000
\begingroup \lccode`~=`#1
\lowercase{\endgroup\expandafter\mspecdefA\csname m:#1\endcsname~}%
}
\mspecdef << : \ll
\mspecdef <> : \neq
\mspecdef <= : \leq
\mspecdef <== : \Leftarrow
\mspecdef <=> : \Leftrightarrow
\mspecdef <-- : \leftarrow
\mspecdef <-> : \leftrightarrow
\mspecdef >> : \gg
\mspecdef >= : \geq
\mspecdef --> : \rightarrow
\mspecdef -+ : \pm
\mspecdef +- : \mp
\mspecdef ... : \dots
\mspecdef == : \equiv
\mspecdef =. : \doteq
\mspecdef ==> : \Rightarrow
\mspecdef =( : \subseteq
\mspecdef =) : \supseteq
\mspecdef =[ : \sqsubseteq
\mspecdef =] : \sqsubseteq
test:
$$ a << b < c <= d >= e > f >> g $$
$$ a <> b = c =. d == e $$
$$ a <== b <-- c <-> d <=> e --> f ==> g $$
$$ a +- b = -(-a -+ +b) $$
$$ a, ..., z <> a + ...+ z $$
$$ a =( b =) c =[ e =] f $$
\bye
结果与接受的答案相同。
编辑它是如何工作的?当我们
\mspecdef ax : \U \mspecdef axy : \V \mspecdef abcd : \W
则该a
字符被设置为数学活动(即\matcode
)"8000
,并定义为
\def a{\trynext{bcd}\W{\trynext{xy}\V{\trynext{x}\U{normal a}}}}
此宏会测试以下字符串是否为bcd
(使用重复调用\isnextchar
)。如果为真,则跳过宏的下一部分并\W
进行处理。否则,处理宏的下一部分。这意味着,xy
测试了。如果失败,则x
测试了,如果失败,则a
打印正常。
我们只能使用原始级别的 TeX 宏来做到这一点,而无需任何非 TeX 工具(如 lua 代码),也无需任何晦涩难懂的解决方案(如 expl3)。
答案3
以下部分摘自定义一个命令,使其仅在环境中document
有效:
\documentclass{article}
\makeatletter
\AtBeginDocument{
\begingroup\lccode`~=`<
\lowercase{\endgroup\def~{\@ifnextchar={\leq\@gobble}{<}}}%
\catcode`<=\active
}
\makeatother
\begin{document}
$2x <= 4x - 2 \leq y$
\end{document}
但使用编辑器的搜索和替换功能似乎同样合适。
答案4
虽然这个解决方案没有保持“数学化”的风格,但对于有抱负的文学程序员来说,它非常有用。好处是什么?没有 TeX hackery(您看到的),因此可以轻松自定义!
使用listings
包:
\documentclass{article}
\usepackage{listings,latexsym}
% Disclaimer: I don't actually know Pascal. It's on my todo-list.
\lstset{language=Pascal}
\begin{document}
\begin{lstlisting}[literate={<=}{{$\leq$}}1
{>=}{{$\geq$}}1
{!=}{{$\neq$}}1
{<==}{{$\Longleftarrow$}}2 % note this width was increased
{==>}{{$\Longrightarrow$}}2
{<<}{{$\ll$}}1 % the only need for `latexsym`
{+-}{{$\pm$}}1
{in}{{$\in$}}1] % and so on
if x <= 5 do stuff();
if x in {4 +- 2}
stuff << st
\end{lstlisting}
\end{document}