我制作了以下函数,去掉左、右或两个(如果存在)括号,并且在文档中使用时似乎按预期工作,即\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:nnn
1
-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}