参数中的尾随空格以 \par 分隔

参数中的尾随空格以 \par 分隔

我刚刚意识到,当我将其用作\par宏参数分隔符时,该参数包含一个尾随空格。

梅威瑟:

\def\test #1\par{\def\param{#1}}
\test test

\hbox{\vrule\param\vrule}     % prints "|test |"

\bye

这是一个错误还是标准行为?如果是后者,为什么会这样?谢谢。

回复 wipet 的回答
@wipet:谢谢,但我需要更复杂的解决方案,而且我不确定我是否能够适应你的建议。

以下是我正在做的事情。我有一个包含大量宏的文件,其中包括定义和放置图片及其说明的宏,如下所示。

% picture definition
% #1 - reference name (must be unique within a book or article, not necessarily within a volume or entire collection)
% #2 - base file name (without suffix)
% #3 - picture title
\def\picdef #1 #2 #3\par{%
    \expandafter\ifx\csname picfile-#1\endcsname\relax\else
        \errmessage{Picture definition duplicity: reference #1 already defined!}\fi
    \expandafter\def\csname picfile-#1\endcsname{\localPath/imgs/#2}%
    \expandafter\def\csname pictitle-#1\endcsname{#3\unskip}%
}


% picture description definition
% #1 - reference name
% #2 - picture description
\long\def\picdesc #1 #2\descend{%
    \expandafter\ifx\csname picfile-#1\endcsname\relax
        \errmessage{Define picture first before defining its description}%
    \else
        \expandafter\expandafter\expandafter\long\expandafter\def\csname picdesc-#1\endcsname{#2\unskip}%
    \fi
}


% user macros to actually place the picture or its description
\def\obrazek #1 {%
    \expandafter\ifx\csname picfile-#1\endcsname\relax
        \message{Warning: unknown picture reference #1 (typo or not yet defined?)!}%
    \else
        \ifhmode\par\fi
        \begin{figure}[t]
            \centerline{\includegraphics[width=0.9\textwidth]{\csname picfile-#1\endcsname}}
            \vskip 14pt
            \centerline{\large \bfseries {\csname pictitle-#1\endcsname}}
        \end{figure}
    \fi
}


\def\obrazekPopis #1 {%
    \expandafter\ifx\csname picfile-#1\endcsname\relax
        \message{Warning: unknown picture reference #1 (typo or not yet defined?)!}%
    \else
        \ifhmode\par\fi
        \csname pictitle-#1\endcsname: \csname picdesc-#1\endcsname\par
    \fi
}

然后,对于某一卷中的特定作品,有一个包含如下图片定义的文件:

\picdef
    logo-s              % small logo
    logo_min            % logo_min.pdf
    Obr. 1              % Czech for Pic. 1

\picdesc logo-s
    This is what a~small logo is supposed to look like.
\descend

\endinput

最后,在实际文本中,图片的放置方式如下:

Some text
and text

\obrazek logo-s

Some other text
etc.

\obrazekPopis logo-s

And text continues on

答案1

之所以这样,是因为事实就是这样。本质上,第一行末尾会像往常一样变成空格,第二行换行符会变成\par。正常\par行为是\unskip先删除最后一个粘合节点(通常从这个空格中删除),然后再换行。

以下有几种可能性。

\def\test #1\par{\def\param{#1}}
\test test

\hbox{\vrule\param\vrule}     % prints "|test |"

\def\testB #1 \par{\def\param{#1}}
\testB test

\hbox{\vrule\param\vrule}     % prints "|test|"

\def\testC #1\par{\def\param{#1\unskip}}
\testC test

\hbox{\vrule\param\vrule}     % prints "|test|"

\bye

\par请注意,如果您在使用中使用实际的显式,如

\test test\par

那么就没有额外的空格,所以你原来的地方就不会有多余的空格。\testB会产生错误,因为它会寻找一个\par以空格开头的空间。

答案2

还有另一种可能性。创建一个宏,将其参数读取到行尾。此解决方案灵感来自 OPmac 技巧 0121。宏程序员可以使用

\eoldef\macro#1{here is a parameter "#1"}

然后\macro text<end of line>导致“#1”为text\eoldef宏可以定义为:

\gdef\eoldef#1{\def#1{\begingroup \catcode`\^^M=12 \eoldefA#1}%
   \expandafter\def\csname\string#1:G\endcsname}
{\catcode`\^^M=12 %
 \gdef\eoldefA#1#2^^M{\endgroup\csname\string#1:G\endcsname{#2}}}

答案3

您可以使用xparseexpl3

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\test}{u{\par}}
 {
  \tl_set:Nx \param { \tl_trim_spaces:n { #1 } }
 }
\ExplSyntaxOff

\begin{document}

\test test

\mbox{\vrule\param\vrule}     % prints "|test|"

\end{document}

当然也可以使用纯 TeX 来完成,但仅限于pdftex

enter image description here

您只需做更多的工作就可以获得更复杂的宏。

\documentclass{article}
\usepackage[demo]{graphicx}
\usepackage{xparse}

\ExplSyntaxOn
% first and second argument delimited by spaces
\NewDocumentCommand{\picdef}{u{~}u{~}u{\par}}
 {
  \marcels_pic_def:nnn { #1 } { #2 } { #3 }
 }
\NewDocumentCommand{\picdesc}{u{~}u{\par}}
 {
  \marcels_pic_desc:nn { #1 } { #2 }
 }
\NewDocumentCommand{\obrazek}{u{~}}
 {
  \marcels_pic_obrazek:n { #1 }
 }
\NewDocumentCommand{\obrazekPopis}{u{~}}
 {
  \marcels_pic_popis:n { #1 }
 }

\seq_new:N \g_marcels_pic_list_seq

\cs_new_protected:Nn \marcels_pic_def:nnn
 {
  \seq_if_in:NnTF \g_marcels_pic_list_seq { #1 }
   {
    \msg_error:nnn { marcels/pic } { duplicate } { #1 }
   }
   {
    \__marcels_pic_defnew:nnn { #1 } { #2 } { #3 }
   }
 }

\cs_new_protected:Nn \__marcels_pic_defnew:nnn
 {
  \seq_gput_right:Nn \g_marcels_pic_list_seq { #1 }
  \prop_gclear_new:c { g_marcels_pic_#1_prop }
  \prop_gput:cnn { g_marcels_pic_#1_prop } { image } { \LocalPath/imgs/#2 }
  \prop_gput:cnx { g_marcels_pic_#1_prop } { title } { \tl_trim_spaces:n { #3 } }
 }

\cs_new_protected:Nn \marcels_pic_desc:nn
 {
  \seq_if_in:NnTF \g_marcels_pic_list_seq { #1 }
   {
    \prop_gput:cnn { g_marcels_pic_#1_prop } { desc } { #2 }
   }
   {
    \msg_warning:nnn { marcels/pic } { early } { #1 }
   }
 }

\cs_new_protected:Nn \marcels_pic_obrazek:n
 {
  \seq_if_in:NnTF \g_marcels_pic_list_seq { #1 }
   {
    \__marcels_pic_obrazek_out:n { #1 }
   }
   {
    \msg_warning:nnn { marcels/pic } { undefined } { #1 }
   }
 }

\cs_new_protected:Nn \__marcels_pic_obrazek_out:n
 {
  \par
  \begin{figure}[tp]
  \centering
  \includegraphics[width=0.9\textwidth]
   {
    \prop_item:cn { g_marcels_pic_#1_prop } { image }
   }
  \par\vspace{14pt}
  {\large\bfseries \prop_item:cn { g_marcels_pic_#1_prop } { title }}
  \end{figure}
 }

\cs_new_protected:Nn \marcels_pic_popis:n
 {
  \seq_if_in:NnTF \g_marcels_pic_list_seq { #1 }
   {
    \__marcels_pic_popis_out:n { #1 }
   }
   {
    \msg_warning:nnn { marcels/pic } { undefined } { #1 }
   }
 }

\cs_new_protected:Nn \__marcels_pic_popis_out:n
 {
  \par
  \prop_item:cn { g_marcels_pic_#1_prop } { title }:~
  \prop_item:cn { g_marcels_pic_#1_prop } { desc }
  \par
 }

\msg_new:nnnn { marcels/pic } { duplicate }
 {
  Picture~name~'#1'~defined
 }
 {
  The~name~'#1'~is~already~assigned;~I'll~ignore~the~new~definition
 }

\msg_new:nnn { marcels/pic } { early }
 {
  Description~before~definition~of~'#1'
 }

\msg_new:nnn { marcels/pic } { undefined }
 {
  Undefined~picture~'#1'
 }

\ExplSyntaxOff

\begin{document}

\picdef
    logo-s              % small logo
    logo_min            % logo_min.pdf
    Obr. 1              % Czech for Pic. 1

\picdesc logo-s
    This is what a~small logo is supposed to look like.

Some text
and text

\obrazek logo-s

Some other text
etc.

\obrazekPopis logo-s

And text continues on

\end{document}

enter image description here

不同的实现,但输出相同。我认为,键值接口更清晰。

\documentclass{article}
\usepackage[demo]{graphicx}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\picdef}{mm}
 {%#1 = name, #2 = key-value pairs
  \marcels_pic_def:nn { #1 } { #2 }
 }
\NewDocumentCommand{\obrazek}{m}
 {
  \marcels_pic_obrazek:n { #1 }
 }
\NewDocumentCommand{\obrazekPopis}{m}
 {
  \marcels_pic_popis:n { #1 }
 }

\keys_define:nn { marcels/pic }
 {
  image .code:n = \prop_put:Nnn \l_marcels_pic_tmp_prop { image } { \LocalPath/imgs/#1 },
  title .code:n = \prop_put:Nnn \l_marcels_pic_tmp_prop { title } { #1 },
  desc  .code:n = \prop_put:Nnn \l_marcels_pic_tmp_prop { desc } { #1 },
 }

\seq_new:N \g_marcels_pic_list_seq
\prop_new:N \l_marcels_pic_tmp_prop

\cs_new_protected:Nn \marcels_pic_def:nn
 {
  \seq_if_in:NnTF \g_marcels_pic_list_seq { #1 }
   {
    \msg_error:nnn { marcels/pic } { duplicate } { #1 }
   }
   {
    \__marcels_pic_defnew:nn { #1 } { #2 }
   }
 }

\cs_new_protected:Nn \__marcels_pic_defnew:nn
 {
  \seq_gput_right:Nn \g_marcels_pic_list_seq { #1 }
  \prop_clear:N \l_marcels_pic_tmp_prop
  \keys_set:nn { marcels/pic } { #2 }
  \prop_new:c { g_marcels_pic_#1_prop }
  \prop_gset_eq:cN { g_marcels_pic_#1_prop } \l_marcels_pic_tmp_prop
 }

\cs_new_protected:Nn \marcels_pic_desc:nn
 {
  \seq_if_in:NnTF \g_marcels_pic_list_seq { #1 }
   {
    \prop_gput:cnn { g_marcels_pic_#1_prop } { desc } { #2 }
   }
   {
    \msg_warning:nnn { marcels/pic } { early } { #1 }
   }
 }

\cs_new_protected:Nn \marcels_pic_obrazek:n
 {
  \seq_if_in:NnTF \g_marcels_pic_list_seq { #1 }
   {
    \__marcels_pic_obrazek_out:n { #1 }
   }
   {
    \msg_warning:nnn { marcels/pic } { undefined } { #1 }
   }
 }

\cs_new_protected:Nn \__marcels_pic_obrazek_out:n
 {
  \par
  \begin{figure}[tp]
  \centering
  \includegraphics[width=0.9\textwidth]
   {
    \prop_item:cn { g_marcels_pic_#1_prop } { image }
   }
  \par\vspace{14pt}
  {\large\bfseries \prop_item:cn { g_marcels_pic_#1_prop } { title }}
  \end{figure}
 }

\cs_new_protected:Nn \marcels_pic_popis:n
 {
  \seq_if_in:NnTF \g_marcels_pic_list_seq { #1 }
   {
    \__marcels_pic_popis_out:n { #1 }
   }
   {
    \msg_warning:nnn { marcels/pic } { undefined } { #1 }
   }
 }

\cs_new_protected:Nn \__marcels_pic_popis_out:n
 {
  \par
  \prop_item:cn { g_marcels_pic_#1_prop } { title }:~
  \prop_item:cn { g_marcels_pic_#1_prop } { desc }
  \par
 }

\msg_new:nnnn { marcels/pic } { duplicate }
 {
  Picture~name~'#1'~defined
 }
 {
  The~name~'#1'~is~already~assigned;~I'll~ignore~the~new~definition
 }

\msg_new:nnn { marcels/pic } { early }
 {
  Description~before~definition~of~'#1'
 }

\msg_new:nnn { marcels/pic } { undefined }
 {
  Undefined~picture~'#1'
 }

\ExplSyntaxOff

\begin{document}

\picdef{logo-s} % small logo
 {
  image=logo_min, % logo_min.pdf
  title=Obr. 1,   % Czech for Pic. 1
  desc=This is what a~small logo is supposed to look like.
 }

Some text
and text

\obrazek{logo-s}

Some other text
etc.

\obrazekPopis{logo-s}

And text continues on

\end{document}

相关内容