StrGobble 不适用于 \numexpr

StrGobble 不适用于 \numexpr

我制作了以下函数,去掉左、右或两个(如果存在)括号,并且在文档中使用时似乎按预期工作,即\stripp{1},,并且所有输出都\strip{(1)}只是。\strip{1)}\strip{(1)}1

\def\stripp#1{%
\IfEndWith{#1}{)}{%
\StrGobbleRight{#1}{1}[\result]%
\IfBeginWith{\result}{(}{%
\StrGobbleLeft{\result}{1}[\result]%
\result}%
{\result}%
}{%
\IfBeginWith{#1}{(}{%
\StrGobbleLeft{#1}{1}[\result]%
\result%
}%
{#1}%
}%
}

但是,当\stripp在块内使用时\numexpr,它会抛出“缺失数字,视为零”错误。问题似乎是由\StrGobbleLeft' or '\StrGobbleRight单独的行为引起的,因为它们在内部也会抛出相同的错误\numexpr。这里出了什么问题,如何修复?MWE:

\documentclass{article}
\usepackage{xstring}

\def\stripp#1{%
\IfEndWith{#1}{)}{%
\StrGobbleRight{#1}{1}[\result]%
\IfBeginWith{\result}{(}{%
\StrGobbleLeft{\result}{1}[\result]%
\result}%
{\result}%
}{%
\IfBeginWith{#1}{(}{%
\StrGobbleLeft{#1}{1}[\result]%
\result%
}%
{#1}%
}%
}

\begin{document}
\stripp{(1)}%\works as intended

\the\numexpr\stripp{(1)}+1\relax %throws an error

\the\numexpr\StrGobbleLeft{(1}{1}+1\relax %error again

\end{document}

答案1

这些xstring命令不是“完全可扩展的”,所以它无法在\numexpr需要数字而不是打印指令的情况下工作。

您可以使用不同的方法解决您的问题expl3

\documentclass{article}

\ExplSyntaxOn
\NewExpandableDocumentCommand{\stripp}{m}
 {
  \tomasz_stripp:e { #1 }
 }

\cs_new:Nn \tomasz_stripp:n
 {
  % remove a leading (
  \str_if_eq:eeTF { ( } { \str_head:n { #1 } }
   {% there is a leading (
    \tomasz_strip_right:e { \tl_tail:n { #1 } }
   }
   {% no leading (
    \tomasz_strip_right:n { #1 }
   }
 }
\cs_generate_variant:Nn \tomasz_stripp:n { e }

\cs_new:Nn \tomasz_strip_right:n
 {
  \str_if_eq:eeTF { ) } { \str_item:nn { #1 } { -1 } }
   {% there is a trailing )
    \tl_range:nnn { #1 } { 1 } { -2 }
   }
   {% no trailing )
    #1
   }
 }
\cs_generate_variant:Nn \tomasz_strip_right:n { e }

\ExplSyntaxOff

\begin{document}

1: \the\numexpr\stripp{1}+1\relax

(1): \the\numexpr\stripp{(1)}+1\relax

1): \the\numexpr\stripp{1)}+1\relax

(1: \the\numexpr\stripp{(1}+1\relax

\newcommand{\test}{1}
\test: \the\numexpr\stripp{\test}+1\relax

\renewcommand{\test}{(1)}
\test: \the\numexpr\stripp{\test}+1\relax

\renewcommand{\test}{1)}
\test: \the\numexpr\stripp{\test}+1\relax

\renewcommand{\test}{(1}
\test: \the\numexpr\stripp{\test}+1\relax

\end{document}

如您所见,您还可以使用宏作为的参数\stripp,只要它最终扩展为带有可能的前导或尾随括号的数字。

在此处输入图片描述

这是如何工作的?\str_if_eq:eeTF检查给定的字符串并对其进行完全扩展。我们首先查看(扩展)参数中的第一个项\stripp;如果它的第一个标记是,(我们将其剥离并传递\tl_trail:n到下一个阶段。

)下一阶段通过查看带有\str_item:nn和位置参数的最后一项来去除可能的尾随-1。如果有,我们将使用和位置参数和)输出从第一个到倒数第二个的项。\tl_range:nnn1-2

如果你在 2020-10-01 版本之前使用 LaTeX,你还需要

\usepackage{xparse}

如果您也这样做\usepackage{xfp},您可以\the\numexpr...\relax\inteval{...}更紧凑的版本进行替换。

\documentclass{article}
\usepackage{xfp}

\ExplSyntaxOn
\NewExpandableDocumentCommand{\stripp}{m}
 {
  \tomasz_stripp:e { #1 }
 }

\cs_new:Nn \tomasz_stripp:n
 {
  % remove a leading (
  \str_if_eq:eeTF { ( } { \str_head:n { #1 } }
   {% there is a leading (
    \tomasz_strip_right:e { \tl_tail:n { #1 } }
   }
   {% no leading (
    \tomasz_strip_right:n { #1 }
   }
 }
\cs_generate_variant:Nn \tomasz_stripp:n { e }

\cs_new:Nn \tomasz_strip_right:n
 {
  \str_if_eq:eeTF { ) } { \str_item:nn { #1 } { -1 } }
   {% there is a trailing )
    \tl_range:nnn { #1 } { 1 } { -2 }
   }
   {% no trailing )
    #1
   }
 }
\cs_generate_variant:Nn \tomasz_strip_right:n { e }

\ExplSyntaxOff

\begin{document}

1: \inteval{\stripp{1}+1}

(1): \inteval{\stripp{(1)}+1}

1): \inteval{\stripp{1)}+1}

(1: \inteval{\stripp{(1}+1}

\newcommand{\test}{1}
\test: \inteval{\stripp\test+1}

\renewcommand{\test}{(1)}
\test: \inteval{\stripp\test+1}

\renewcommand{\test}{1)}
\test: \inteval{\stripp\test+1}

\renewcommand{\test}{(1}
\test: \inteval{\stripp\test+1}

\end{document}

相关内容