我想编写一个宏,使其\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}