解析点分字符串,提取最后一部分

解析点分字符串,提取最后一部分

我想要一个宏,将像“1.2.3”这样的字符串分成两部分:直到最后一个点的部分(称为语境) 和最后一个数字。这似乎是辅助宏和的一个非常基本的应用程序\expandafter,但我无法让它终止。

这是我的 MWE,其中包含一些调试宏:

\documentclass{article}

\makeatletter
\newcommand{\parse}[1]{%
    Parsing #1:\par%
    \let\my@context\@empty%
    \let\my@number\@empty%
    \expandafter\@parse#1.\@nil
    Context: \my@context\par
    Number: \my@number
}
\def\@parse#1.#2\@nil{%
    \if#2\@empty%
        \edef\my@number{#1}%
        \show\my@number%
    \else%
        \edef\my@context{\if\my@context\@empty\else\my@context.\fi#1}%
        \show\my@context%
        \expandafter\@parse#2\@nil%
    \fi
}
\makeatother

\begin{document}
\tracingmacros=1
\parse{1.2.3}

\parse{4.5.6.7}

\parse{1.2}
\tracingmacros=0

\end{document}

当我编译它时,我得到了应该是终止的情况,但它没有成功。这是日志文件:

\parse #1->Parsing #1:\par \let \my@context \@empty \let \my@number \@empty \ex
pandafter \@parse #1.\@nil Context: \my@context \par Number: \my@number 
#1<-1.2.3

\@parse #1.#2\@nil ->\if #2\@empty \edef \my@number {#1}\show \my@number \else 
\edef \my@context {\if \my@context \@empty \else \my@context .\fi #1}\show \my@
context \expandafter \@parse #2\@nil \fi 
#1<-1
#2<-2.3.

\my@context ->

\@empty ->

> \my@context=macro:
->1.
\@parse ... \my@context .\fi #1}\show \my@context 
                                                  \expandafter \@parse #2\@n...
l.30 \parse{1.2.3}

? 

\@parse #1.#2\@nil ->\if #2\@empty \edef \my@number {#1}\show \my@number \else 
\edef \my@context {\if \my@context \@empty \else \my@context .\fi #1}\show \my@
context \expandafter \@parse #2\@nil \fi 
#1<-2
#2<-3.

\my@context ->1

\@empty ->

\my@context ->1
> \my@context=macro:
->1.2.
\@parse ... \my@context .\fi #1}\show \my@context 
                                                  \expandafter \@parse #2\@n...
l.30 \parse{1.2.3}

? 

\@parse #1.#2\@nil ->\if #2\@empty \edef \my@number {#1}\show \my@number \else 
\edef \my@context {\if \my@context \@empty \else \my@context .\fi #1}\show \my@
context \expandafter \@parse #2\@nil \fi 
#1<-3
#2<-

\@empty ->

\my@number ->

\my@context ->1.2

\my@context ->1.2
> \my@context=macro:
->1.2.3.
\@parse ... \my@context .\fi #1}\show \my@context 
                                                  \expandafter \@parse #2\@n...
l.30 \parse{1.2.3}

? 
! Undefined control sequence.
\@parse ...y@context \expandafter \@parse #2\@nil 
                                                  \fi 
l.30 \parse{1.2.3}

? 

在最后一次成功的扩展中\@parse#1是“3”,#2是“”。似乎\@empty也扩展为“”。那么为什么不成功呢\if#2\empty

我欢迎奇特的xparse解决l3regex方案,但也希望有一个基本的。有些简单的东西我不明白。

答案1

代码存在问题原样是以下行:

\if#2\@empty

假设第二个参数为空。当 TeX 替换参数文本时,它会将第二个参数插入到 的位置#2,因此#2它不是扩展为参数文本的宏。它参数文本。因此流变成\if\empty,并且 TeX 尝试找到下一个要比较\empty的东西(在这种情况\edef下,测试失败)。

解决此问题的一种方法是将内容存储#2在宏中,然后测试该宏,只需对代码进行最少的更改即可。由于我们现在正在测试宏,\ifx所以这是正确的选择。所以现在您需要:

\def\arg@two{#2}%
\ifx\arg@two\@empty

这将按照您的需要测试它是否#2为空。

在全:

\documentclass{article}

\makeatletter
\newcommand{\parse}[1]{%
    Parsing #1:\par%
    \let\my@context\@empty%
    \let\my@number\@empty%
    \expandafter\@parse#1.\@nil
    Context: \my@context\par
    Number: \my@number
}
\def\@parse#1.#2\@nil{%
  \def\arg@two{#2}%
    \ifx\arg@two\@empty%
        \edef\my@number{#1}%
        \show\my@number%
    \else%
        \edef\my@context{\if\my@context\@empty\else\my@context.\fi#1}%
        \show\my@context%
        \expandafter\@parse#2\@nil%
    \fi
}
\makeatother

\begin{document}
\tracingmacros=1
\parse{1.2.3}

\parse{4.5.6.7}

\parse{1.2}
\tracingmacros=0

\end{document}

生成:

解析字符串

答案2

听了巫师们的讲解后,我们来看一下一个实用的解决方案:

\documentclass{article}
\usepackage{xstring}
\newcommand{\parse}[1]{
    Parsing #1:\par%
\StrCount{#1}{.}[\dotnum]
Context : \StrBefore[\dotnum]{#1}{.}\par
Number:  \StrBehind[\dotnum]{#1}{.}
}
\begin{document}

\parse{1.2.3}

\parse{4.5.6.7}

\parse{1.2}
\end{document}

在此处输入图片描述

答案3

一个简单的 TeX 解决方案:

\def\parse#1{%
\def\a{}%
\def\b{}%
\xparse#1.\relax.}

\def\xparse#1.#2.{%
\ifx\relax#2
  \def\b{#1}%
  \expandafter\parsestop
 \else
   \edef\a{\a\ifx\a\empty\else.\fi#1}%
  \expandafter\xparse
 \fi
 #2.}

\def\parsestop\relax.{%
  \immediate\write20{[a=\a] [b=\b]}}


\parse{1}

\parse{1.2.3}

\parse{4.5.6.7}

\parse{1.2}

\bye

产生

[a=] [b=1]
[a=1.2] [b=3]
[a=4.5.6] [b=7]
[a=1] [b=2]
 )
No pages of output.

答案4

这是 David Carlisle 解决方案的另一种变体。在此解决方案中,命令\parsestop不是必需的,并且\a是作用域内的。此外,我们还要留意空/空标记。

\documentclass{article}
\def\parse#1{\begingroup\def\a{}\xparse#1.\relax.}
\def\xparse#1.#2.{%
  \ifx\relax#2%
    \edef\xparse\relax.{%
      \endgroup\ifx\a\empty\else[a=\a]\space\fi\ifx\\#1\\\else[b=#1]\fi
    }%
  \else
    \ifx\\#1\\\else
      \edef\a{\a\ifx\a\empty\else.\fi#1}%
    \fi
  \fi
  \xparse#2.%
}

\begin{document}
\parse{}

\parse{1}

\parse{1.2.3}

\parse{1..2..3}

\parse{4.5.6.7}

\parse{1.2}
\end{document} 

相关内容