我可以在文档的序言中添加一些内容,以便在数学环境中(例如$NP$
)没有空格的多个字母之间没有额外的空格,并且不被视为多个不同的变量?现在,我必须使用来防止任何额外的间距,但我觉得如果它们是不同的变量( ),$\mathit{NP}$
在字母之间添加空格更自然。$N P$
例如,如果我想要多字母变量NP
,我希望能够说出$NP$
它会自动被 替换$\mathit{NP}$
。如果我想要N
和P
具有适当的变量间间距,我希望只有当它们被空格分隔时才这样做,如下所示:$N P$
。
有办法实现这个吗?这会破坏我不知道的东西吗?
编辑:
以下屏幕截图可以说明我的意思:
所以基本上,线路 1 是否可以自动给我线路 3,而线路 2 是否可以自动给我线路 2?
答案1
它是理论上可以让 LaTeX 识别字母簇并对其进行排版,就像它们是作为参数输入的一样\mathit
,但速度会非常慢:每个字母字符都应该变成一个“数学活动”字符,它会检查后面的项目是否是字母字符;如果是,它应该排版自身,\mathit
如果它是第一个,则从它开始,然后将相同的控制权传递给下一个字符;如果后面不是字母字符,它应该结束\mathit
。
最好这样做
\newcommand{\mli}[1]{\mathit{#1}}
其中\mli
代表多字母标识符; 使用任何控制序列名称。然后输入
$\mli{P}=\mli{NP}$
这有很多优点,但主要保存有关输入的信息。
笔记:我对上述陈述有一个很好的证明,但不幸的是该网站的帖子有长度限制。
Heiko 的解决方案expl3
。
\documentclass[fleqn]{article}
\usepackage{xcolor}
\usepackage{amsmath}
\usepackage{xparse}
\ExplSyntaxOn
% 1. Define an equivalent for each letter
\cs_new_protected:Nn \__egreg_letter_loop:nn
{
\int_step_inline:nnn { `#1 } { `#2 }
{
\exp_args:Nc \mathchardef
{ __egreg_letter_code_##1: } % generate the old code
=
\mathcode##1 % the old code
\scan_stop:
\cs_new_protected:cx { __egreg_letter_act_##1: }
{
\exp_not:N \__egreg_letter_scan:nw { ##1 }
}
\char_set_active_eq:nc { ##1 } { __egreg_letter_act_##1: }
}
}
\__egreg_letter_loop:nn { A } { Z }
\__egreg_letter_loop:nn { a } { z }
% 2. Define the main macro that does the scanning
\tl_new:N \l__egreg_letter_scanned_tl
\cs_new_protected:Npn \__egreg_letter_scan:nw #1
{
\tl_if_empty:NT \l__egreg_letter_scanned_tl { \c_group_begin_token } % to be closed later
\tl_put_right:Nx \l__egreg_letter_scanned_tl { \exp_not:c { __egreg_letter_code_#1: } }
\peek_catcode:NF A
{% next char is not a letter
\__egreg_letter_deliver:V \l__egreg_letter_scanned_tl
}
}
\cs_new_protected:Nn \__egreg_letter_deliver:n
{
\tl_if_single:nTF { #1 }
{
\__egreg_letter_single:n { #1 }
}
{
\__egreg_letter_group:n { #1 }
}
\c_group_end_token % finish the group
}
\cs_generate_variant:Nn \__egreg_letter_deliver:n { V }
% 3. The interface for defining the actions
\NewDocumentCommand{\definelettersingle}{m}
{
\cs_set_protected:Nn \__egreg_letter_single:n { { #1 } }
}
\NewDocumentCommand{\definelettergroup}{m}
{
\cs_set_protected:Nn \__egreg_letter_group:n { { #1 } }
}
% 4. Make all letters math active
\int_step_inline:nnn { `A } { `Z } { \mathcode#1="8000 }
\int_step_inline:nnn { `a } { `z } { \mathcode#1="8000 }
\ExplSyntaxOff
% initialize
\definelettersingle{#1}
\definelettergroup{\mathit{#1}}
\begin{document}
First a standard formula $NP\ne N P$
\bigskip
Now \textcolor{blue}{single letters are set in blue},
\textcolor{red}{multiple letters in red}.
\begin{itemize}
\item Multiple letters are put in \verb|\mathit|:
\definelettersingle{{\color{blue}#1}}%
\definelettergroup{\mathit{\color{red}#1}}%
\[ NP \neq N P \]
\item Multiple letters are put in \verb|\mathrm|:
\definelettersingle{{\color{blue}#1}}%
\definelettergroup{\mathrm{\color{red}#1}}%
\[ NP\ (text) \neq N P\ (two\ variables) \]
\[ F_force = m_mass a_acceleration \]
\end{itemize}
\end{document}
答案2
这是“的解决方案egreg 为读者准备的练习“。以下示例使字母“math active”具有以下功能:
- 收集字母,直到遇到非字母为止。单个字母传递给宏
\mprintsingle
,多个字母传递给宏\mprintmulti
。两个宏都有两个参数。第一个用于以数学模式输出结果,第二个可用于文本模式。 - 还将结果放入使用
\bgroup
和的子公式中\egroup
。这样可以将多个字母放入索引和下标中而无需使用花括号,例如F_strong
。
两个应用:
OP 可能会使用类似这样的方法:
\renewcommand*{\mprintsingle}[2]{#1}% the default \renewcommand*{\mprintmulti}[2]{\mathit{#1}}
通常多个字母是文本单词而不是变量,应该直立打印。这可以通过以下方式实现:
\usepackage{amstext}
\renewcommand*{\mprintsingle}[2]{#1}% the default
\renewcommand*{\mprintmulti}[2]{\text{#2}}
显示两个应用程序的完整示例文件:
\documentclass[fleqn]{article}
\makeatletter
\usepackage{etexcmds}
\newtoks\m@toks@math
\newtoks\m@toks@text
\edef\m@tmp@restore{%
\lccode\number`\X=\the\lccode`\X\relax
\lccode\number`\~=\the\lccode`\~\relax
}
\newcommand*{\m@activate}{}
\newcommand*{\m@check@letter}{}
\newcommand*{\m@check@fi}{}
\newif\ifm@single
\let\m@start\relax
\def\m@loop{%
\lccode`\X=\count@
\lccode`\~=\count@
\lowercase{%
\expandafter\mathchardef\csname m@code@X\endcsname=\mathcode\count@
\edef\m@activate{%
\etex@unexpanded\expandafter{\m@activate}%
\mathcode\the\count@="8000\relax
\def\noexpand~{\m@start\csname m@code@X\endcsname X}%
}%
\g@addto@macro\m@check@letter{%
\ifx\@let@token X\else
}%
}%
\g@addto@macro\m@check@fi{\fi}%
\advance\count@\@ne
}
% A-Z
\count@=`\A\relax
\@whilenum\count@<\numexpr`\Z+1\relax\do{\m@loop}
% a-z
\count@=`\a\relax
\@whilenum\count@<\numexpr`\z+1\relax\do{\m@loop}
\newcommand*{\m@start}[2]{%
\bgroup
\m@toks@math{#1}%
\m@toks@text{#2}%
\m@singletrue
\futurelet\@let@token\m@check
}
\edef\m@check{%
\etex@unexpanded{%
\let\m@next\m@add
\ifx\@let@token\space
\let\m@next\m@finish
\else
\ifx\@let@token\egroup
\let\m@next\m@finish
\else
}%
\etex@unexpanded\expandafter{%
\m@check@letter
}%
\etex@unexpanded{%
\let\m@next\m@finish
}%
\etex@unexpanded\expandafter{%
\m@check@fi
}%
\etex@unexpanded{%
\fi
\fi
\m@next
}%
}
\newcommand*{\m@add}[1]{%
\m@singlefalse
\m@toks@math\expandafter{%
\the\expandafter\m@toks@math
\csname m@code@#1\endcsname
}%
\m@toks@text\expandafter{%
\the\m@toks@text
#1%
}%
\futurelet\@let@token\m@check
}
\newcommand*{\m@finish}{%
\ifm@single
\expandafter\mprintsingle\expandafter{%
\the\expandafter\m@toks@math\expandafter
}\expandafter{%
\the\expandafter\m@toks@text\expandafter
}%
\else
\expandafter\mprintmulti\expandafter{%
\the\expandafter\m@toks@math\expandafter
}\expandafter{%
\the\expandafter\m@toks@text\expandafter
}%
\fi
\egroup
}
\let\mprintsingle\@firstoftwo
\let\mprintmulti\@firstoftwo
\everymath{\m@activate}
\everydisplay{\m@activate}
\m@tmp@restore
\makeatother
\usepackage{color}
\usepackage{amstext}
\begin{document}
\textcolor{blue}{Single letters are set in blue},
\textcolor{red}{multiple letters in red}.
\begin{itemize}
\item Multiple letters are put in \verb|\mathit|:
\renewcommand*{\mprintsingle}[2]{{\color{blue}#1}}%
\renewcommand*{\mprintmulti}[2]{\mathit{\color{red}#1}}%
\[ NP \neq N P \]
\item Multiple letters are put in \verb|\text|:
\renewcommand*{\mprintsingle}[2]{{\color{blue}#1}}%
\renewcommand*{\mprintmulti}[2]{\text{\color{red}#2}}%
\[ NP\ (text) \neq N P\ (two\ variables) \]
\[ F_force = m_mass * a_acceleration \]
\end{itemize}
\end{document}
答案3
在评论中要求扩展我关于字体的评论。
TeX 不控制数学模式下字母之间的间距,出现明显的间距是因为通常数学斜体字体比文本斜体具有更宽的边距和字母间字距(并且字符本身通常更宽)。
\documentclass{article}
\begin{document}
\showoutput
\textit{NP ffiv} $NP ffiv$ $\mathit{NP ffiv}$
\end{document}
生产
并在日志中:
...\hbox(6.94444+1.94444)x345.0, glue set 224.80687fil
....\hbox(0.0+0.0)x15.0
....\OT1/cmr/m/it/10 N
....\OT1/cmr/m/it/10 P
....\glue 3.57774 plus 1.53178 minus 1.02322
....\OT1/cmr/m/it/10 ^^N (ligature ffi)
....\OT1/cmr/m/it/10 v
....\kern 1.07637
....\glue 3.33333 plus 1.66666 minus 1.11111
....\mathon
....\OML/cmm/m/it/10 N
....\kern1.09026
....\OML/cmm/m/it/10 P
....\kern1.3889
....\OML/cmm/m/it/10 f
....\kern1.0764
....\OML/cmm/m/it/10 f
....\kern1.0764
....\OML/cmm/m/it/10 i
....\OML/cmm/m/it/10 v
....\kern0.35878
....\mathoff
....\glue 3.33333 plus 1.66666 minus 1.11111
....\mathon
....\hbox(6.94444+1.94444)x28.70953
.....\OT1/cmr/m/it/10 N
.....\OT1/cmr/m/it/10 P
.....\OT1/cmr/m/it/10 ^^N
.....\OT1/cmr/m/it/10 v
.....\kern1.07637
....\mathoff
....\penalty 10000
查看日志,您会看到第三个示例使用.\OT1/cmr/m/it/10
与第一个示例相同的字体(这是默认计算机现代字体设置的选择,其他字体包在使用\mathit
与主数学字体相同的字体\textit
或选择与主数学字体匹配的字体方面可能会有所不同)。
中间示例中N 和 P 之间的字距为 1.09026pt(并且没有ffi
连字符),这不受 TeX 控制(或从 luatex 以外的 TeX 宏中可见),这是字体度量的属性。不仅字距和侧边距不同,字母形状也不同:在v
此示例中最明显。当然,如果字体包将文本字体更改为非现代计算机字体,但数学字体保持不变,则\mathit
和之间的差异\textit
会更加明显。
答案4
该unicode-math
软件包区分数学模式中的单词(\mathit
、\mathbfit
等)和连续的数学符号(\symit
、\symbfit
等)。前者可以使用 和\setmathrm
常用的BoldFont=
、UprightFont=
选项进行设置,但默认为主文本字体。后者可以使用 选项range=
进行设置\setmathfont
。