当两个宏紧跟另一个宏时,如何删除它们之间的空格?

当两个宏紧跟另一个宏时,如何删除它们之间的空格?

我使用以下布局,其中\sec{}标题放在边距中,\subsec{}标题和文本段落放在旁边的主列中。

但是,当 a\subsec{}紧跟在 之后时\sec{},我希望两者都从同一行开始,没有垂直空格。问题是我不能只在其中一个命令中包含负空格,因为\subsec{}当它跟在 以外的任何命令之后时仍应创建空格\sec{}。我该如何实现这一点?

这是一个显示了不需要的空间的小例子,我希望 SECTION 和 Subsection 从同一行开始,并保持所有其他间距不变:

sec 和 subsec 之间不需要空格

\documentclass{article}
\usepackage{calc}
\usepackage{changepage}
\usepackage{lipsum}

\setlength{\parskip}{.5em}
\setlength{\parindent}{0em}

\newcommand{\titlecol}{1.45in}
\newcommand{\titlesep}{0.5em}
\newcommand{\secskip}{1.6em}
\newcommand{\subsecskip}{0.6em}

\renewcommand{\sec}[1]{%
  \vspace{\secskip}\hspace{-\titlecol}%
  \parbox[t][0pt][t]{\titlecol-\titlesep}{#1\raggedright}}

\newcommand{\subsec}[1]{\vspace{\subsecskip}\textbf{#1}\par}

\begin{document}
\begin{adjustwidth}{\titlecol}{0em}

\sec{SECTION}

\subsec{Subsection}
\lipsum[1][1-2] \par
\lipsum[1][3]

\subsec{Subsection}
\lipsum[1][1-3]

\sec{ANOTHER SECTION}
\lipsum[1][1-3]

\end{adjustwidth}
\end{document}

答案1

以下纯 TeX 宏\sec以这样的方式定义:将节标题排版为节中第一段的一部分(因此不会插入分页符):

\def\sec#1{\vskip\secskip
  \noindent\llap{
  \setbox0=\vtop{\hsize\titlecol\advance\hsize by-\titlesep\raggedright#1} 
  \dp0=0pt\box0\hskip\titlesep}\ignorespaces}

如果您已经在段落中,则可以省略小节之前的垂直跳过,即仅在垂直模式下贡献垂直跳过:

\def\subsec#1{\ifvmode\vskip\subsecskip\fi\textbf{#1}\par}

\sec但是您必须避免在和之间留空行\subsec,因为这将结束该节开始的段落,从而使该小节贡献垂直跳过:

\sec{SECTION}
\subsec{Subsection}

答案2

您可以设置标题文本,然后返回到垂直模式,然后通过一组\vskips 来纠正垂直位置,然后放置一个\penalty带有特殊(不可破坏)数字(示例中为 10013)的 s。

如果情况\subsec如下,那么您可以通过 读取该数字,并在 上面\lastskip放置(或不放置) a :\vskip\subsec

\parskip=.5em
\parindent=0em

\def\titlecol{1.3in}
\def\titlesep{0.5em}
\def\secskip{1.6em}
\def\subsecskip{0.6em}
\hoffset=6cm
\hsize=12cm

\def\sec#1{%
  \vskip\secskip
  \hskip-\titlecol
  \vtop {\hsize=\dimexpr\titlecol-\titlesep\relax \rightskip=0pt plus1fil\relax #1\vss}
  \par
  \nobreak \vskip-\prevdepth \prevdepth=0pt \vskip-\baselineskip \vskip-\parskip
  \penalty10013
}

\def\subsec#1{\ifnum\lastpenalty=10013 \else \vskip\subsecskip\fi {\bf#1}\par\nobreak}


\sec{SECTION}

\subsec{Subsection}
\lipsum[1]\par
\lipsum[2]

\subsec{Subsection}
\lipsum[1]

\sec{ANOTHER SECTION}
\lipsum[1]

编辑:我尝试更详细地解释代码。\sec宏将 放在\vtop左侧(一行或多行),作为 由 完成的单行段落的一部分\par。 中的第二行和更多行\vtop累积在 的深度中。如果我们在 之后放置下一个材料\par,则该材料将位于其之后,即 的最后一行之后\vtop\prevdepth是 TeX 寄存器(只能在垂直模式下使用),我们可以在其中读取或设置最后一个设置为垂直模式的框的深度,即\vtop我们示例中的这个。\vtop-\prevdepth返回 的第一行基线处的当前排版点\vtop。我们在使用它之后将其设置为零,因为在垂直模式下下一个框的放置是根据\baselineskip或计算\lineskip\prevdepth。我们想要使用\baselineskip,我们通过 返回排版点,-\baselineskip以便下一个框的基线与 的基线相同\vtop。但下一段\parskip也会增加,所以我们也必须放置负数\parskip

\rightskip=0pt plus1fil\relax与 类似,但\raggedright右侧的粘连可无限拉伸,因此排除开始使用连字符的单词(因为我们不希望标题中出现这样的连字符)。

答案3

这假定您从不以 开始章节文本{

\documentclass{article}
\usepackage{calc}
\usepackage{changepage}
\usepackage{lipsum}

\setlength{\parskip}{.5em}
\setlength{\parindent}{0em}

\newcommand{\titlecol}{1.45in}
\newcommand{\titlesep}{0.5em}
\newcommand{\secskip}{1.6em}
\newcommand{\subsecskip}{0.6em}

\renewcommand{\sec}[1]{%
  \par
  \addvspace{\secskip}\hspace{-\titlecol}%
  \makebox[\titlecol][l]{\parbox[t][0pt][t]{\titlecol-\titlesep}{#1\raggedright}}%
  \subsecfalse
  \checksubsec
}

\makeatletter
\newcommand{\checksubsec}[1]{%
  \ifx#1\par
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {\checksubsec}% found \par, repeat
  {\checksubsec@#1}% check for \subsec
}
\newcommand{\checksubsec@}[1]{%
  \ifx#1\subsec
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {\subsectrue\subsec}% found \subsec set the conditional to true
  {#1}% reinsert the token
}
\makeatother
\newif\ifsubsec
\newcommand{\subsec}[1]{%
  \ifsubsec\else\par\addvspace{\subsecskip}\fi
  \textbf{#1}\par\nobreak
}

\begin{document}
\begin{adjustwidth}{\titlecol}{0em}

\sec{SECTION}

\subsec{Subsection}
\lipsum[1][1-2] \par
\lipsum[1][3]

\subsec{Subsection}
\lipsum[1][1-3]

\sec{ANOTHER SECTION}
\lipsum[1][1-3]

\end{adjustwidth}
\end{document}

查看第一个标记(忽略空格)。如果是,\par则将其丢弃并重复;如果是,\subsec则将条件设置为 true 并\subsec再次发出。否则,将重新插入标记并继续排版。

我做了一些更改:将章节标题设置在适当尺寸的框中,并在其中设置\parbox减小的宽度(减小的);我添加了章节或小节,以便它们不会与以下文本分离。\titlesep\nobreak

您最好使用geometry并实际设置边距中的章节标题,而不是使用全局的来伪造它adjustwidth

在此处输入图片描述

答案4

非常感谢 Heiko Theißen 建议将\sec内联排版为段落的一部分,然后检查\subsec我们是否已经在段落中,否则(\ifvmode)插入垂直空格。

我还曾经为了避免在开始新段落\@ifnextchar\par\@gobble\relax}后出现空行,而这需要将定义包装在和 中。由于我们已经忽略了段落分隔符,因此似乎不再需要了。\sec\sec\makeatletter\makeatother\ignorespaces

此外,我从纯 TeX 解决方案切换到\parbox我更熟悉的 LaTex,这样我就可以更轻松地理解和修改解决方案。还要感谢 egreg 建议使用\nobreak/\nopagebreak来防止部分与后续段落分离。

\makeatletter
\def\sec#1{%
  \vskip\secskip%
  \noindent\llap{\parbox[t][0pt][t]{\titlecol-\titlesep}{\raggedright#1}}%
  \nopagebreak\@ifnextchar\par\@gobble\relax}
\makeatother
 
\def\subsec#1{%
  \ifvmode\vskip\subsecskip\fi%
  \textbf{#1}\par\nopagebreak}

完整示例:

\documentclass{article}
\usepackage{calc}
\usepackage{changepage}
\usepackage{lipsum}

\setlength{\parskip}{.5em}
\setlength{\parindent}{0em}

\newcommand{\titlecol}{1.45in}
\newcommand{\titlesep}{0.5em}
\newcommand{\secskip}{1.6em}
\newcommand{\subsecskip}{0.6em}
 
\makeatletter
\def\sec#1{%
  \vskip\secskip%
  \noindent\llap{\parbox[t][0pt][t]{\titlecol-\titlesep}{\raggedright#1}}%
  \nobreak\@ifnextchar\par\@gobble\relax}
\makeatother
 
\def\subsec#1{%
  \ifvmode\vskip\subsecskip\fi%
  \textbf{#1}\par}

\begin{document}
\begin{adjustwidth}{\titlecol}{0em}

\sec{SECTION}

\subsec{Subsection}
\lipsum[1][1-2]\par
\lipsum[2][1-3]

\subsec{Subsection}
\lipsum[1][1-2]

\sec{ANOTHER SECTION}
\lipsum[1][1-3]

\end{adjustwidth}
\end{document}

结果:

在此处输入图片描述

相关内容