如何从宏参数中解析#?

如何从宏参数中解析#?

我想编写一个宏,使其\ghpr{myrepo#1234}扩展为\href{https://github.com/my-username/myrepo/pull/1234}{myrepo#1234}。 (我知道如何对 执行此操作\ghpr{myrepo}{1234},但如果可能的话,我更愿意保留#分隔符。)

我尝试这样做:

\documentclass{standalone}

\usepackage{xstring}
\usepackage{hyperref}
\newcommand*\ghpr[1]{%
  \StrSubstitute{#1}{##}{/pull/}[\tmpurl]%
  \href{https://github.com/my-username/\tmpurl}{#1}%
}

\begin{document}
\ghpr{myrepo#1234}
\end{document}

但是Illegal parameter number in definition of \xs_arg_ii当我尝试使用它时就会产生这种情况。

我认为这里的问题是我没有#正确地逃避;我应该如何写这个命令?

答案1

我可以理解您希望将其#作为参数分隔符,但请注意,由于其作为参数标记的性质,这在 TeX 中很难解析字符。

无论如何,下面提出了 3 种解决方案来实现这一点。

  • \ghprDetok会破坏参数中的任何宏或特殊字符(阅读:pdfTeX 中的非 ASCII),但它是其中最快的
  • \ghprEtl是第二快的(但稳定)
  • \ghprRegex最慢(但稳定)

在这三种情况下,我都没有检查是否真的是参数的一部分(这将导致和#中的低级 TeX 错误,并导致中的数字部分为空)。如果您在这里需要检测,我可以为所有三个变体添加它。\ghprDetok\ghprEtl\ghprRegex

\ghprEtl体重用了的内部\ghprDetok,这不是必需的,但它需要辅助,所以为什么不重用另一个呢。

\documentclass{article}

\usepackage{hyperref}
\usepackage{etl}

\newcommand*\ghprfastest[2]
  {\href{https://github.com/my-username/#1/pull/#2}{#1\##2}}%

\newcommand*\ghprDetok[1]
  {\expandafter\ghprDetokAUX\detokenize{#1}\stop}
\expanded{\unexpanded{\def\ghprDetokAUX#1}\string#\string#}#2\stop
  {\ghprfastest{#1}{#2}}

\ExplSyntaxOn
\cs_new_protected_nopar:Npn \ghprEtl #1
  {%
    \exp_last_unbraced:Ne \ghprDetokAUX
      { \etl_token_replace_once:nNe {#1} ## { \c_hash_str\c_hash_str } }
    \stop
  }
\cs_generate_variant:Nn \etl_token_replace_once:nNn { nNe }

\cs_new_protected_nopar:Npn \ghprRegex #1
  {
    \regex_split:nnN { \# } {#1} \l_tmpa_seq
    \exp_args:Nee \ghprfastest
      { \seq_item:Nn \l_tmpa_seq 1 }
      { \seq_item:Nn \l_tmpa_seq 2 }
  }
\ExplSyntaxOff

\begin{document}
\ghprfastest{myrepo}{1234}

\ghprDetok{myrepo#1234}

\ghprEtl{myrepo#1234}

\ghprRegex{myrepo#1234}
\end{document}

答案2

您可以在本地更改 catcode #

\def\ghpr{\bgroup \catcode`\#=12 \ghprA}
\def\ghprA #1{\egroup \href{https://github.com/my-username/myrepo/pull/1234}{#1}}

\ghpr{myrepo#1234} % expands to \href{https://github.com/my-username/myrepo/pull/1234}{myrepo#1234}

相关内容