我编写了一个名为的个人命令\compo
,它允许您在文本旁边放置一个图形:\compo[.4]{ text }{ figure };
使用 tikz calc 库创建图形时出现以下错误:
! Package tikz Error: + or - expected.
我安装了tikz babel library
和,也使用了\shorthandoff
和\shortandon
命令,但这并没有改变任何东西。我猜问题出在我的宏上。他的代码如下:
%----------------------------------------
% new command \compo to place a figure next to a text
%----------------------------------------
\newlength{\colG}\newlength{\colD}
\newcommand{\compo}[3][0.5]{
\setlength{\colG}{#1\linewidth}
\setlength{\colD}{\linewidth}%
\addtolength{\colD}{-\colG}
\addtolength{\colG}{-10pt}
\addtolength{\colD}{-10pt}%
\par \noindent%
\begin{minipage}[t]{\colG}\vspace{0cm}#2\end{minipage}\hfill\vrule\hfill%
\begin{minipage}[t]{\colD}\vspace{0cm}#3\end{minipage}\par}
以下是一个 MCE:
\documentclass[a4paper, 11pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[french]{babel}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{babel}
%----------------------------------------
% new command \compo to place a figure next to a text
%----------------------------------------
\newlength{\colG}\newlength{\colD}
\newcommand{\compo}[3][0.5]{
\setlength{\colG}{#1\linewidth}
\setlength{\colD}{\linewidth}%
\addtolength{\colD}{-\colG}
\addtolength{\colG}{-10pt}
\addtolength{\colD}{-10pt}%
\par \noindent%
\begin{minipage}[t]{\colG}\vspace{0cm}#2\end{minipage}\hfill\vrule\hfill%
\begin{minipage}[t]{\colD}\vspace{0cm}#3\end{minipage}\par}
\begin{document}
\compo[.5]{
Un triangle
}{
\shorthandoff{!:}
\begin{tikzpicture}[handle active characters in code]
\draw(-1,-1) rectangle (4,4);
\coordinate (B) at (0,0);
\coordinate (C) at (3,0);
\coordinate(D) at (2,0);
\draw(B)--(C)--(D)--cycle;
\coordinate (Ap) at ($(C)!.35!-90:(B)$);
\draw (Ap)--(B)--(C)--cycle;
\end{tikzpicture}
\shorthandon{!:}
}
\end{document}
此宏的代码中有什么错误\compo
?我该如何纠正此错误?
答案1
该问题是一个 catcode 问题。下面是一个更简单的演示:
\documentclass{article}
\usepackage[french]{babel}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{babel}
\newcommand\compo[1]{#1} % compo does nothing but return it's argument
\begin{document}
%%% Works:
\shorthandoff{!}
\compo{
\begin{tikzpicture}[]
\coordinate (Ap) at ($(0,0)!0!(3,0)$);
\end{tikzpicture}
}
\shorthandon{!}
%%% Breaks:
\compo{
\shorthandoff{!} % \shorthandoff doesn't do anything because characters in
\begin{tikzpicture} % argument have already had their catcodes assigned
\coordinate (Ap) at ($(0,0)!0!(3,0)$); % so the active ! causes an error here
\end{tikzpicture}
\shorthandon{!}
}
\end{document}
请注意,我已将您的命令替换为一个只返回其参数而不执行任何操作的命令,但仍然会导致问题。为什么会导致问题?因为字符的 catcode 是在第一次解析时分配的。通常,在命令从 catcode active 更改为 catcode other!
之后,会解析 tikzpicture 主体中的。但是,当在命令的参数中出现 时,会在评估任何主体之前解析整个命令主体。因此,已经处于活动状态,并且命令导致的 catcode 更改不执行任何操作。最好的解决方法是在命令内部执行 catcode 更改并调用 helpre 命令来获取参数:\shorthandoff{!}
!
!
!
\shorthandoff{!}
\compo
\documentclass{article}
\usepackage[french]{babel}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{babel}
% The wrapper command doesn't take any arguments, it just makes the catcode change and
% calls the helper.
\newcommand\compo{\shorthandoff{!}\compohelper}
% The helper does all the work.
\newcommand\compohelper[1]{#1\shorthandon{!}}
\begin{document}
\compo{
\begin{tikzpicture}
\coordinate (Ap) at ($(0,0)!0!(3,0)$);
\end{tikzpicture}
}
\end{document}
现在您可以使用原始定义\compohelper
并且它可以按预期工作:
\documentclass{article}
\usepackage[french]{babel}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{babel}
\newlength{\colG}\newlength{\colD}
% Wrapper command just changes catcodes and calls helper
\newcommand\compo{%
\shorthandoff{!:}% Change the catcodes
\compohelper % call helper to grab arguments
}
\newcommand{\compohelper}[3][0.5]{% do actual work
\setlength{\colG}{#1\linewidth}%
\setlength{\colD}{\linewidth}%
\addtolength{\colD}{-\colG}%
\addtolength{\colG}{-10pt}%
\addtolength{\colD}{-10pt}%
\par \noindent%
\begin{minipage}[t]{\colG}#2\end{minipage}\hfill\vrule\hfill%
\begin{minipage}[t]{\colD}#3\end{minipage}%
\par
\shorthandon{!:}% restore catcodes
}
\begin{document}
\compo[.5]{
Un triangle
}{
\begin{tikzpicture}
\draw(-1,-1) rectangle (4,4);
\coordinate (B) at (0,0);
\coordinate (C) at (3,0);
\coordinate(D) at (2,0);
\draw(B)--(C)--(D)--cycle;
\coordinate (Ap) at ($(C)!.35!-90:(B)$);
\draw (Ap)--(B)--(C)--cycle;
\end{tikzpicture}
}
\end{document}