检测空文本的正确方法

检测空文本的正确方法

如果命令传递的是空文本,我会尝试忽略它。我的用例没有那么复杂展开 ifthenelse 中的空宏@egreg 提供了一种看似很好的方法来测试传递给它的文本是否不会产生输出。但是,我似乎无法让它工作。

当以下工作时,输出应该只是名称(如果没有地址或给出空的地址):

姓名:彼得披萨

或者如果给出了非空白地址:

姓名:彼得披萨

地址:123 Main Street,Anytown,美国

xstring版本IfNoText

使用我的原始版本(已%\def\UseEgregsIfNoText{}注释掉),第 1 部分和第 3 部分是正确的。

第 2 节无法正常工作,因为Address:打印了不应该打印的。此xstring版本的\IfNoText还不允许我在\SetAddress{}(参见第二次出现的\UseEgregsIfNoText)中留空行,而这正是我想要的。

此外,第 4 节显示,如果我尝试访问,则无法编译\MandatoryName。请注意,在这种情况下它已被注释掉。

在此处输入图片描述

Egreg 的版本IfNoText

使用来自@egreg 版本的\IfNoText(取消注释\def\UseEgregsIfNoText{}展开 ifthenelse 中的空宏,我可以在 中使用空行进行编译\SetAddress{}并使用\MandatoryName宏,但无法获得所需的结果。这里案例 1 和 2 是正确的,但案例 3(在 中插入了额外的空行\SetAddress)和 4(尝试访问 的值\MandatoryName)不正确。

在此处输入图片描述

笔记:

  • 我打算\IgnoreSpacesAndImplicitePars使用\IgnoreSpacesAndAllPars寻找 \ignorespacesandpars,但它们似乎没有什么区别。这些宏包含在下面的代码中,但未使用
  • egreg 确实警告说棘手的案例可能会欺骗“”,但我不认为空行是他的意思。

代码:

\def\UseEgregsIfNoText{}% 

\documentclass{article}
\usepackage{xspace}
\usepackage{xstring}

% https://tex.stackexchange.com/questions/23100/looking-for-an-ignorespacesandpars/23110#23110
\makeatletter
\def\IgnoreSpacesAndImplicitePars{%  Not used
  \begingroup
  \catcode13=10
  \@ifnextchar\relax
    {\endgroup}%
    {\endgroup}%
}

\def\IgnoreSpacesAndAllPars{%       Not used
  \begingroup
  \catcode13=10
  \@ifnextchar\par
    {\endgroup\expandafter\IgnoreSpacesAndAllPars\@gobble}%
    {\endgroup}%
}
\makeatother

\ifdefined\UseEgregsIfNoText
    %% https://tex.stackexchange.com/questions/42280/expand-away-empty-macros-within-ifthenelse
    \newcommand{\IfNoText}[3]{%
        \sbox0{#1}%
        \ifdim\wd0=0pt %
            {#2}% if #1 is empty
        \else%
            {#3}% if #1 is not empty
        \fi%
    }
\else
    \newcommand{\IfNoText}[3]{%
        %\edef\Parameter{\IgnoreSpacesAndAllPars#1}
        %\IfStrEq{\Parameter}{\empty}{#2}{#3}%
        \IfStrEq{#1}{\empty}{#2}{#3}%
    }
\fi


\newcommand*{\MandatoryName}{\empty}%
\newcommand*{\SetName}[1]{\renewcommand*{\MandatoryName}{#1\xspace}}%

\newcommand{\OptionalAddress}{\empty}% can have line breaks, so no "*"
\newcommand{\SetAddress}[1]{%
    \IfNoText{#1}{% 
        % No printable text so ignore...
    }{%
        \renewcommand{\OptionalAddress}{\ignorespaces#1}%
    }%
}%

\newcommand*{\ShowNameAndAddress}{%
    \par\noindent\textbf{Name:}~\MandatoryName
    \IfNoText{\OptionalAddress}{}{%
        \par\noindent\textbf{Address:}~\OptionalAddress
    }%
}%
\begin{document}
\section{Name with no Address}
\SetName{Peter's Pizza}
\ShowNameAndAddress

\section{Name with Empty address}
\ifdefined\UseEgregsIfNoText
    % Want to be able to handle this:
    \SetAddress{


    }
\else
    \SetAddress{
    }
\fi

\ShowNameAndAddress


\section{Name with Address Given}

\SetAddress{
  123 Main Street,
  Anytown, USA
}

\ShowNameAndAddress

\section{Name with Address using Name}

%Verify: \verb|\MandatoryName =| \MandatoryName

\ifdefined\UseEgregsIfNoText
    % Want to be able to access value of \MandatoryName here
    \SetAddress{
      123 \MandatoryName Way,
      Anytown, USA
    }
\else
    % Can't even compile in this case with \MandatoryName 
    \SetAddress{
      123 %\MandatoryName Way,
      Anytown, USA
    }
\fi

\ShowNameAndAddress

\end{document}

答案1

以下是我的写法。

\makeatletter
\newcommand{\DoIfNoText}[1]{%
  \begingroup
  \sbox0{#1}%
  \ifdim\wd0=\z@
    \endgroup
    \expandafter\@gobble
  \else
    \endgroup
    \expandafter\@firstofone
  \fi}
\makeatother
\newcommand{\MandatoryName}{}
\newcommand{\SetName}[1]{\renewcommand{\MandatoryName}{#1}}

\newcommand{\OptionalAddress}{}
\newcommand{\SetAddress}[1]{%
  \DoIfNoText{#1}
    {\renewcommand{\OptionalAddress}{\ignorespaces#1}}%
  }

\newcommand{\ShowNameAndAddress}{%
  \par\noindent\textbf{Name:}~\MandatoryName
  \DoIfNoText{\OptionalAddress}
    {\par\noindent\textbf{Address:}~\OptionalAddress}%
  }

大概

\def\OptionalAddress{}

\ShowNameAndAddress如果要避免将 的含义\OptionalAddress延续到下一个地址,则应将其添加到。

参数中的空行\DoIfNoText是无关紧要的,因为该框是在受限的水平模式下构建的,其中\par命令被忽略。

笔记我添加了一个\begingroup-\endgroup对,以保持分配到\box0本地,从而避免在某些情况下可能发生的冲突(请参阅枚举中缺少项目编号以及 Frank Mittelbach 的回答)。

答案2

我不确定这能解决你的问题,但需要记录一下:包xifthen提供isempty。您可以像这样定义宏:

\newcommand{\ifempty}[3]{%
  \ifthenelse{\isempty{#1}}{#2}{#3}%
}

答案3

以下几点值得一提:

  • 在内部\SetAddress,您重新定义\OptionalAddress使用

    \renewcommand{\OptionalAddress}{\ignorespaces#1}
    

    此定义仅存在于 中\SetAddress。要了解为什么会出现这种情况,请\OptionalAddress在设置地址后立即使用,以查看未排版任何内容。因此,您应该使用

    \gdef\OptionalAddress{\ignorespaces#1}
    

    这是缩写\global\def。原因是您\OptionalAddress\IfNoText测试中调用 时使用\ShowNameandAddress

  • 常规空间跨越3.3333pt。但是,它没有高度或深度。因此,也许您可​​以\IfNoText将的定义更改为

    \newcommand{\IfNoText}[3]{%
      \sbox0{#1}%
      \ifdim\wd0=0pt %
        {#2}% if #1 is empty
      \else%
        \ifdim0pt=\dimexpr\ht0+\dp0\relax
          {#2}% if #1 is empty
        \else
          {#3}% if #1 is not empty
        \fi
      \fi%
    

    首先检查参数是否没有宽度,然后检查是否存在空间的总高度(高度 + 深度)。

综合以上两条建议,可以得出:

在此处输入图片描述

\def\UseEgregsIfNoText{}% 

\documentclass{article}
\usepackage{xspace}
\usepackage{xstring}

% http://tex.stackexchange.com/questions/23100/looking-for-an-ignorespacesandpars/23110#23110
\makeatletter
\def\IgnoreSpacesAndImplicitePars{%  Not used
  \begingroup
  \catcode13=10
  \@ifnextchar\relax
    {\endgroup}%
    {\endgroup}%
}

\def\IgnoreSpacesAndAllPars{%       Not used
  \begingroup
  \catcode13=10
  \@ifnextchar\par
    {\endgroup\expandafter\IgnoreSpacesAndAllPars\@gobble}%
    {\endgroup}%
}
\makeatother

\ifdefined\UseEgregsIfNoText
    %% http://tex.stackexchange.com/questions/42280/expand-away-empty-macros-within-ifthenelse
    \newcommand{\IfNoText}[3]{%
        \sbox0{#1}%
        \ifdim\wd0=0pt %
            {#2}% if #1 is empty
        \else%
          \ifdim0pt=\dimexpr\ht0+\dp0\relax
            {#2}
          \else
            {#3}% if #1 is not empty
          \fi
        \fi%
    }
\else
    \newcommand{\IfNoText}[3]{%
        %\edef\Parameter{\IgnoreSpacesAndAllPars#1}
        %\IfStrEq{\Parameter}{\empty}{#2}{#3}%
        \IfStrEq{#1}{\empty}{#2}{#3}%
    }
\fi


\newcommand*{\MandatoryName}{\empty}%
\newcommand*{\SetName}[1]{\renewcommand*{\MandatoryName}{#1\xspace}}%

\newcommand{\OptionalAddress}{\empty}% can have line breaks, so no "*"
\newcommand{\SetAddress}[1]{%
    \IfNoText{#1}{% 
        % No printable text so ignore...
    }{%
        \gdef\OptionalAddress{\ignorespaces#1}%
    }%
}%

\newcommand*{\ShowNameAndAddress}{%
    \par\noindent\textbf{Name:}~\MandatoryName
    \IfNoText{\OptionalAddress}{}{%
        \par\noindent\textbf{Address:}~\OptionalAddress
    }%
}%
\begin{document}
\section{Name with no Address}
\SetName{Peter's Pizza}
\ShowNameAndAddress

\section{Name with Empty address}
\ifdefined\UseEgregsIfNoText
    % Want to be able to handle this:
    \SetAddress{


    }
\else
    \SetAddress{
    }
\fi

\ShowNameAndAddress


\section{Name with Address Given}

\SetAddress{
  123 Main Street,
  Anytown, USA
}

\ShowNameAndAddress

\section{Name with Address using Name}

%Verify: \verb|\MandatoryName =| \MandatoryName

\ifdefined\UseEgregsIfNoText
    % Want to be able to access value of \MandatoryName here
    \SetAddress{
      123 \MandatoryName Way,
      Anytown, USA
    }
\else
    % Can't even compile in this case with \MandatoryName 
    \SetAddress{
      123 %\MandatoryName Way,
      Anytown, USA
    }
\fi

\ShowNameAndAddress

\end{document}

我并不是说这是“正确”的方法。我只是说这是“一种”方法。

答案4

这是另一个:

\usepackage{ifthen}

\newcommand{\mycommand}[1]{%
\ifthenelse{\equal{#1}{}}{%
It is empty!%
}{%
It is not empty!%
}}

相关内容