Handling _ (underscores) in a macro's comma-separated list of arguments
You can use \detokenize
; but if you want a printed underscore, you need to load fontenc
with the T1
option.
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{etoolbox}
\usepackage{hyperref}
\usepackage{lipsum}
\newcommand{\codecitep}[1]{% cf. https://tex.stackexchange.com/a/87423/64454
[%
\def\nextitem{\def\nextitem{, }}% Separator
% How to process each item
\renewcommand*{\do}[1]{%
\nextitem\hyperref[code:##1]{\detokenize{##1}}%
}%
\docsvlist{#1}% Process list
]%
}
\begin{document}
\section{Body}
A sentence with one code-citation only \codecitep{key1}.
Another sentence with two code-citations and followed by dummy text \codecitep{key1, key2}.
A sentence with one code-citation only \codecitep{a_123}.
Another sentence with two code-citations and followed by dummy text \codecitep{a_123, bb_456}.
\lipsum[1-2]
\section{Appendix}
\lipsum[3]
\subsection{key1}
\label{code:key1}
\label{code:a_123}
\lipsum[4]
\subsection{key2}
\label{code:key2}
\label{code:bb_456}
\lipsum[5]
\end{document}
Here's an expl3
version, which doesn't need fontenc
.
\documentclass{article}
\usepackage{xparse}
\usepackage{hyperref}
\usepackage{lipsum}
\ExplSyntaxOn
% define a token list containing an underscore
\tl_const:Nx \c_ebo_codecite_us_tl { \char_generate:nn { `_ } { 8 } }
% the main macro
\NewDocumentCommand{\codecitep}{m}
{
\ebo_codecite:n { #1 }
}
% variables and variants of kernel functions
\tl_new:N \l__ebo_codecite_key_print_tl
\seq_new:N \l__ebo_codecite_refs_seq
\cs_generate_variant:Nn \tl_replace_all:Nnn { NV }
% functions
\cs_new_protected:Nn \ebo_codecite:n
{
[
% clear the sequence
\seq_clear:N \l__ebo_codecite_refs_seq
% loop through the input
\clist_map_inline:nn { #1 }
{
% for the "print part", change _ into \_
\tl_set:Nn \l__ebo_codecite_key_print_tl { ##1 }
\tl_replace_all:NVn \l__ebo_codecite_key_print_tl \c_ebo_codecite_us_tl { \_ }
% add to the sequence
\__ebo_codecitep_add:nV { ##1 } \l__ebo_codecite_key_print_tl
}
% use the sequence, items separated by "comma space"
\seq_use:Nn \l__ebo_codecite_refs_seq { ,~ }
]
}
% an auxiliary function, for expanding the second argument
\cs_new_protected:Nn \__ebo_codecitep_add:nn
{
\seq_put_right:Nn \l__ebo_codecite_refs_seq { \hyperref[code:#1]{#2} }
}
\cs_generate_variant:Nn \__ebo_codecitep_add:nn { nV }
\ExplSyntaxOff
\begin{document}
\section{Body}
A sentence with one code-citation only \codecitep{key1}.
Another sentence with two code-citations and followed by dummy text \codecitep{key1, key2}.
A sentence with one code-citation only \codecitep{a_123}.
Another sentence with two code-citations and followed by dummy text \codecitep{a_123, bb_456}.
\lipsum[1-2]
\section{Appendix}
\lipsum[3]
\subsection{key1}
\label{code:key1}
\label{code:a_123}
\lipsum[4]
\subsection{key2}
\label{code:key2}
\label{code:bb_456}
\lipsum[5]
\end{document}
The simplest way to do this is to load the url
package and define a url command to format the refnames:
\usepackage{url}
\DeclareUrlCommand{\coderefname}{\urlstyle{rm}}
\newcommand{\codecitep}[1]{% cf. https://tex.stackexchange.com/a/87423/64454
[%
\def\nextitem{\def\nextitem{, }}% Separator
\renewcommand*{\do}[1]{\nextitem{\hyperref[code:##1]{\coderefname{##1}}}}% How to process each item
\docsvlist{#1}% Process list
]%
}