在tikz 声明函数和 babel 法语选项它涉及到 TeX 含义中局部和全局之间的区别的问题。
在链接的问题中,;
应该在 a 中停用babel 简写{tikzpicture}
,这可以通过以下方式完成
\begin{tikzpicture}
\shorthandoff{;}
...
\end{tikzpicture}
答案1
概念全球的和当地的与为标记分配含义或为寄存器分配值有关。
代币及其含义
标记是 TeX 的基本食物,有两种:字符标记和象征性标记粗略的说,后者就是我们用“反斜杠+字符”来表示的。
字符标记的含义取决于该字符的“字符代码”和“类别代码”的组合;例如,在正常设置下,字符A
对应于对 (65,11),而{
对应于对 (123,1)。类别代码 1 赋予{
其作为组和参数分隔符的特殊含义。类似地,\
对应于 (92,0),因此反斜杠充当符号标记的标记。
许多代币都有预定义意思是 TeX 开始工作的时候。每个字符标记都有一个字符代码(不能更改)和一个类别代码(可以稍后更改);一些符号标记是原始,这样 TeX 就不会从零开始。
作业
任何时候,都可以为新的符号标记赋予含义,或者可以更改已知标记的含义(对于字符标记,仅更改类别代码)。TeX 对标记的操作取决于上下文。例如,\tracingmacros
是一个(原始)整数寄存器;
\tracingmacros=1
TeX 将分配将值 1 存入整数寄存器,而
\count255=\tracingmacros
存储的当前值\tracingmacros
将被赋值为存储在整数寄存器中的值\count255
。
两者都是作业每次修改存储在寄存器或数组中的标记或值的含义时,我们都在进行赋值。列出所有类型的赋值会太长。除了前面显示的类型外,基本类型还包括:
\def\cs<parameter text>{<replacement text>}
\let\cs=<token>
\catcode<8 bit number>=<4 bit number>
<font selector>
(当使用 LuaTeX 或 XeTeX 时, 为<8 bit number>
)<21 bit number>
。最后一种类型表示选择字体作为当前字体的符号标记(当使用或 时,<font selector>
LaTeX 会在后台执行此类分配)。还有更多,但这样说太过分了。\bfseries
\textit
准确地说,作业不能真正地完成任何\edef
时间。TeX 仅在执行命令时才执行赋值(扩展宏时除外);特别是在计算替换文本时或写出操作结果时,它不会执行赋值\write
。
活跃角色
字符标记的一种特殊类型是类别代码为 13 的标记。当 TeX 发现这样的字符时,它会将其视为符号标记来查找其含义,并且必须用\def
或 (或其变体)来分配该含义\let
。这是众所周知的 的情况~
。
群组
按规定每一个赋值(几乎每个赋值,参见“例外”部分)都是有作用域的,当当前组结束。什么是组?TeX 可以通过多种方式打开组:
使用
{
不具有参数分隔符作用的 ;该组将以}
同一括号级别的 结尾。可以使用\bgroup
for{
或\egroup
for}
获得相同效果(简单组)。使用
\begingroup
; 当前组将以相应的\endgroup
(结束半单群)。\vbox
当要排版为、\vtop
或\vcenter
的文本\hbox
被吸收时(箱体组)。当对齐单元格的文本被吸收时;它几乎与框组相同(对齐组)。
当
$
或$$
启动数学公式时(数学公式组)。开始或结束数学显示的
标记$$
由 LaTeX 自动提供;切勿$$...$$
在 LaTeX 中直接使用其他特殊情况可以在 TeXbook 或 TeX by Topic 中找到(例如,
\left
开始一个组,以匹配的 结束\right
)。
因此\begingroup\tensl ABC \endgroup DEF
将打印“ABCDEF”,因为当前字体的赋值在 时结束其生效\endgroup
。相反
\def\my#1{-- #1 --}
\my{\tensl ABC} DEF
将打印“--ABC--防御“并继续使用倾斜的字体,因为\tensl
在组内还未看到该声明。
全球任务
每个赋值都可以以 and 为前缀,在这种情况下,其效果将超越当前组。 is ; so\global
的缩写\global\def
\gdef
\begingroup
\catcode`-=\active % \active here means 13
\gdef-{not a hyphen}
\endgroup
同时显示两种分配方式。 的类别代码-
仅在本地更改,但 的含义-
作为活动字符被全局分配。每当 TeX 找到 (45,13) 对时, 的定义-
将用作活动字符,但-
在 之后将不再默认为活动字符\endgroup
。稍后将对此进行详细介绍。
乳胶
在 LaTeX 中,什么才算是组?除了上述一般的 TeX 构造之外,环境也会形成组,这是因为 LaTeX 实现\begin
和的方式不同\end
,\begingroup
前者和\endgroup
后者都存在。但有一个明显的例外,即环境document
,但这仅从理论角度来看很重要,因为只能有一个环境。但是,、、、、和的document
参数也将被吸收为组,因为它们在内部使用、或。类似地,或环境中的每个单元格都会自己组成一个组,这是对齐组的特殊情况。\mbox
\makebox
\fbox
\framebox
\sbox
\savebox
\parbox
\hbox
\vbox
\vtop
\vcenter
tabular
tabbing
LaTeX 命令\newcommand
、、\renewcommand
和\newenvironment
是\renewenvironment
的包装器\def
,因此它们仅作用于本地,但不能以 开头\global
。因此,除了使用较低级别的命令外,基本上没有办法在 LaTeX 中进行全局分配。LaTeX 的分配是一个例外计数器它们始终是全局的(见底部)。
法语分号的问题
为了应对法语排版的特殊性,babel
将一些字符更改为类别代码 13(活动)。这可能会导致 TikZ 出现问题,因为它使用分号作为语句分隔符,但也使用冒号作为语法分隔符。TikZ 的开发人员已尽最大努力避免此设置出现问题,但有时可能会出错。
\usepackage[french]{babel}
具体做什么?细节相当复杂,但除其他事项外,基本上将执行以下操作(然而,这是一个非常广泛的简化):
\begingroup
\catcode`;=\active % \active here means 13
\gdef;{\unskip\penalty10000 \thinspace\string;}
\catcode`:=\active % \active here means 13
\gdef:{\unskip~\string:}
\endgroup
\AtBeginDocument{\catcode`;=\active \catcode`:=\active}
那么当;
或:
在文档中找到不是例如,TikZ 对语句分隔符的期望。
\documentclass{article}
\usepackage[french]{babel}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\tikzset{declare function={Carre(\t)=\t*\t;}}
\draw plot [domain=-1:1] (\x,{Carre(\x)});
\end{tikzpicture}
\end{document}
语句分隔符的分号\draw
被正确解释,因为 TikZ 知道在这种情况下如何处理活动分号。但语句分隔符\tikzset
被视为这样却为时已晚。
为了解决这个问题,有两种方法:
将
\tikzset
声明放在序言中,其中分号不是积极的。使用本地赋值使分号在
tikzpicture
环境中处于非活动状态
因此
\documentclass{article}
\usepackage[french]{babel}
\usepackage{tikz}
\tikzset{declare function={Carre(\t)=\t*\t;}}
\begin{document}
\begin{tikzpicture}
\draw plot [domain=-1:1] (\x,{Carre(\x)});
\end{tikzpicture}
\end{document}
和
\documentclass{article}
\usepackage[french]{babel}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\shorthandoff{;}
\tikzset{declare function={Carre(\t)=\t*\t;}}
\draw plot [domain=-1:1] (\x,{Carre(\x)});
\end{tikzpicture}
\end{document}
可以工作;\shorthandoff{;}
这是 Babel 在本地关闭字符标记活动特性的方式,基本上意味着
\catcode`;=<whatever category code ; had at the start of the job>
而不必强迫我们知道要使用的代码是 12。由于分配是本地的,它将在 结束\end{tikzpicture}
,因此此后该字符;
将再次处于活动状态。
随着 TikZ 3.00 版本的推出,该babel
库已被引入,因此当
\usetikzlibrary{babel}
用来。(添加于 2015-01-02)
本地分配的其他用途
假设有人希望除了“一般”定理之外,还有“命名定理”。例如,在某人写的书中,计划有
秩零定理 1.4
格拉姆-施密特定理 2.3
在其他明确标记的声明中定理。一种策略是为每个名称定义一个新的类定理环境,与普通theorem
环境共享计数器。不过,可以做得更好:
\newtheorem{theorem}{Theorem}[chapter]
\newtheorem{namedtheoremaux}[theorem]{\protect\thistheoremname}
\newcommand{\thistheoremname}{}
\newenvironment{namedtheorem}[1]
{\renewcommand{\thistheoremname}{#1}\begin{namedtheoremaux}}
{\end{namedtheoremaux}}
这样输入就可以
\begin{namedtheorem}{Rank-nullity theorem}
...
\end{namedtheorem}
...
\begin{namedtheorem}{Gram-Schmidt theorem}
...
\end{namedtheorem}
定义中的对于LaTeX 的标准或 提供的标准\protect
来说不是必需的;它是用于并且 否则不会造成任何损害。\newtheorem
amsthm
ntheorem
的重新定义\thistheoremname
是局部的,因此它只会影响当前namedtheorem
环境。
例外
TeX 所做的一些分配是本质上是全球性的. 最常用的此类任务是
\hyphenchar\font=`-
\hyphenchar\font=-1
第一个告诉 TeX,在当前字体中排版时用作连字符的字符应该是普通连字符;第二个告诉 TeX,此字体的连字符被抑制。
说出来不是个好主意
This is a normal paragraph and the following word must not be
{\hyphenchar\font=-1 hyphenated} but others can
因为不段落中以及后面使用相同字体的单词将被连字符连接,因为即使前面没有 ,分配也是全局的\global
;然而
This is a normal paragraph and the following word must not be
\hyphenchar\font=-1 hyphenated \hyphenchar\font=`- but others can
也不起作用,因为 TeX 对一个字体仅使用一个连字符,即段落结束时与之关联的连字符。
再次使用 LaTeX
计数器上的 LaTeX 操作
\setcounter
\addtocounter
\stepcounter
和\refstepcounter
实现为全球的作业。相反,\setlength
在本地操作(并且在其前面加上\global
不起作用)。
答案2
Tobi 的回答并不准确。
你\shorthandsoff{;}
真的不重新定义 ;
,你将 catcode 更改为 ,;
以便active
它other
里面根本tikzpicture
不会执行。
这意味着tikzpicture
它在内部可以正常工作,但在内部\textbf{...}
(或任何其他接受参数的命令)则不行。这是因为字符是在读取时使用 catcode 读取的,而不是在执行时。另一方面,宏赋值( \def
、\newcommand
、 、 ...)是在执行时完成的,因此即使在宏参数中也能正常工作。\let
请注意,如果命令没有将其参数括在组中( 、\begingroup...\endgroup
或{...}
)\bgroup...\egroup
,则不会使赋值“在参数内部局部化”,而是“在宏的范围内局部化”。请参阅以下示例:
\newcommand\mparen[1]{(#1)}
\def\A{a}
\textbf{\A\ \def\A{b}\A}\ \A % result: a b a
\mparen{\A\ \def\A{b}\A}\ \A % result: a b b
因此,最好在定义中添加分组\mparen
:
\newcommand\mparen[1]{({#1})}
最后一条注释展示了 catcode 赋值与宏赋值的区别。该命令\makeatletter
会赋值@
一个 catcode letter
,以便可以在宏名称中使用它。该命令\makeatother
会还原此操作。因此,请尝试以下示例:
\makeatletter
\newcommand\mparen[1]{(#1)}
\def\A{a}
\def\A@B{b}
\makeatother
\begin{bfseries}
\makeatletter
\A\ \A@B % result: a b
\end{bfseries}
\A\ \A@B % result: a a@B
\textbf{\makeatletter \A\ \A@B}% result: a a@B
\A\ \A@B % result: a a@B
\mparen{\makeatletter \A\ \A@B}% result: a a@B
\A\ \A@B % result: a b
我被要求解释一下最后三行发生了什么。我会一步一步地解释。我r:
标记了 TeXReads。o:
我标记的是哦输出并处理。m:
我标记了宏的含义
r: \A
m: \A -> a
r: a % we now read the definition of \A
o: letter `a`
r: \
o: space
r: \A % remember, @ is not a letter
m: \A -> a
r: a
o: letter `a`
r: @
o: symbol `@`
r: B
o: letter `B`
r: empty line
o: end of paragraph
r: \mparen
m: \mparen#1 -> (#1)
r: {\makeatletter \A\ \A@B} % at this moment, TeX core reads
% the arguments. Since @ is still not a letter, sequence \A@B
% comprises three tokens, `\A` `@` `B`
r: (
o: symbol `(`
r: #1
r: \makeatletter
o: change of catcode of `@` % notice we ARE NOT IN A GROUP
r: \A
m: \A -> a
r: a
o: letter `a`
r: \
o: space
r: \A
m: \A -> a
r: a
o: letter `a`
r: @ % catcode is now "letter", but it was actually read
% couple steps before where catcode was "other"
o: symbol `@`
r: B
o: letter `B`
r: )
o: symbol `)`
r: empty line
o: end of paragraph
r: \A
m: \A -> a
r: a
o: letter `a`
r: \
o: space
r: \A@B % catcode of @ is "letter" now so it's treatened as a part
% of macro name
m: \A@B -> b
r: b
o: letter `b`
答案3
在 TeX 中,每个赋值(定义、计数器更改、catcode 更改等)都是本地的,即,它的作用域位于所谓的“组”内,除非明确将其设为全局。组是两个括号之间的所有内容,即
outside {inside} outside
(括号中括号界定参数的情况除外),环境中的所有内容,即
outside
\begin{env}
inside
\end{env}
outside
或介于\begingroup
和之间的任意值\endgroup
,
outside
\begingroup
inside
\endgroup
outside
后者在\begin#1
和的定义中使用\end#1
。
举个例子可以说明:
\documentclass{article}
\newcommand{\A}{A}
\begin{document}
\A\ expands to A
\begin{center}
\A\ expands to A \\
\renewcommand{\A}{AA}
\A\ expands to AA
\newcommand{\B}{B}
\B\ expands to B
\end{center}
\A\ expands to A and not AA!
\B\ is undefined outside the group here
\end{document}
它的实际用途是保持定义的改变在本地,或者,例如,设置某些单词的字体,如normal {\tiny tiny} normal
。
问题在于
\begin{tikzpicture}
\shorthandoff{;}
...
\end{tikzpicture}
是必须添加\shorthandoff
在每个{tikzpicture}
因为它是停用的(即 catcode 更改,请参阅tohecz 答案) 保持在当前 的本地{tikzpicture}
。当然,可以将 添加\shorthandoff
到前言中,但随后也会切换到普通文本。可以使用 ' 将停用宏添加到 的\begin{tikzpicture}
定义etoolbox
中\AtBeginEnvironment
\AtBeginEnvironment{tikzpicture}{\shorthandoff{;}}
或者在这种情况下使用 TikZ 风格,就像 Jake 说的:
\tikzset{
every picture/.prefix style={
execute at begin picture=\shorthandoff{;}
}
}