8

This is a follow-up to Should Hyperlinks include trailing puctuation as part of the link text?, and this question is about automating the processing of the trailing character. I would like to be able to have the punctuation be specified after the macro as in:

\CreateLink{<linke style>}{<link target>}{<link text>},

where I have used a comma as an example. I prefer the above instead of:

\CreateLink{<linke style>}{<link target>}{<link text>,}

for two reasons:

  1. It is more readable (punctuation is more obvious in the code).
  2. Allows me to defer the decision of the weather to include the punctuation as part of the link text or not.

So, I would like to modify the \CreateLink macro to be able to check if the subsequent character is a space or not. If not, then consider the next character as punctuation and include that character in the output of \CreateLink.

I realize that the solution will probably involve \@ifnextchar but I was not able able to get that to work. In the attempt below I output a - if a non-space character is found. Since the - is in the output for all cases, my attempt is clearly missing something.

enter image description here

References:

Code:

% The following \def allows to have one version of this code for this questions,
% and the previous question at:
% 
%    https://tex.stackexchange.com/questions/125357/should-hyperlinks-include-trailing-puctuation-as-part-of-the-link-text
%
\def\SmartVersion{}%  Should be uncommented for this question.

\documentclass{article}
\usepackage{xparse}
\usepackage{xcolor}
\usepackage{soul}
\usepackage{xstring}
\usepackage{xspace}
\usepackage[colorlinks=true]{hyperref}

%% ----------------------------------------------------------------
%%                https://tex.stackexchange.com/questions/36894/
%%                    underline-omitting-the-descenders
%%
%%
\makeatletter
\ExplSyntaxOn
    \cs_new:Npn \white_text:n #1
      {
        \fp_set:Nn \l_tmpa_fp {.01}
        \fp_mul:Nn \l_tmpa_fp {#1}
        \llap{\textcolor{white}{\the\SOUL@syllable}\hspace{\fp_to_decimal:N \l_tmpa_fp em}}
        \llap{\textcolor{white}{\the\SOUL@syllable}\hspace{-\fp_to_decimal:N \l_tmpa_fp em}}
      }
    \NewDocumentCommand{\whiten}{ m }
        {
          \int_step_function:nnnN {1}{1}{#1} \white_text:n
        }
\ExplSyntaxOff

\NewDocumentCommand{ \varul }{ D<>{5} O{0.2ex} O{0.1ex} +m } {%
\begingroup
\setul{#2}{#3}%
\def\SOUL@uleverysyllable{%
   \setbox0=\hbox{\the\SOUL@syllable}%
   \ifdim\dp0>\z@
      \SOUL@ulunderline{\phantom{\the\SOUL@syllable}}%
      \whiten{#1}%
      \llap{%
        \the\SOUL@syllable
        \SOUL@setkern\SOUL@charkern
      }%
   \else
       \SOUL@ulunderline{%
         \the\SOUL@syllable
         \SOUL@setkern\SOUL@charkern
       }%
   \fi}%
    \ul{#4}%
\endgroup
}%
\makeatother
%% ----------------------------------------------------------------

\newcommand{\CreateLinkA}[2]{%
    \hypersetup{pdfborder={0 0 1}, urlcolor=.}%
    \href{#1}{#2}%
}%
\newcommand{\CreateLinkB}[2]{%
    \hypersetup{pdfborder={0 0 0}, urlcolor=red}%
    \href{#1}{#2}%
}%
\newcommand{\CreateLinkC}[2]{%
    \hypersetup{colorlinks=false,urlcolor=.}%
    \setulcolor{blue}%
    \href{#1}{\varul[0.5pt][1.0pt]{#2}}%
}%

\makeatletter
\newcommand{\CreateLink}[3]{%
    \IfStrEqCase{#1}{%
        {1}{\CreateLinkA{#2}{#3}}%
        {2}{\CreateLinkB{#2}{#3}}%
        {3}{\CreateLinkC{#2}{#3}}%
    }%
    \ifdefined\SmartVersion% 
        % If the next character is anything other than a space, 
        % include that char as part of the text. 
        % The "-" is supposed to whatever the next character is,
        % but don't know how to get that character.  
        % Note that the "-" is shown in all cases, so this is NOT working.
        \@ifnextchar{\space}{\space}{-}%
    \else% "ELSE" clause is unused in this question
        \xspace%
    \fi
}%
\makeatother


\begin{document}
\textbf{Punctuation NOT part of link:}\medskip
\par Go and check out \CreateLink{1}{www.yahoo.com}{the yahoo}, and also\ldots
\par Go and check out \CreateLink{2}{www.yahoo.com}{the yahoo}, and also\ldots
\par Go and check out \CreateLink{3}{www.yahoo.com}{the yahoo}, and also\ldots

\bigskip
\textbf{Punctuation part of link:}\medskip
\par Go and check out \CreateLink{1}{www.yahoo.com}{the yahoo,} and also\ldots
\par Go and check out \CreateLink{2}{www.yahoo.com}{the yahoo,} and also\ldots
\par Go and check out \CreateLink{3}{www.yahoo.com}{the yahoo,} and also\ldots
\end{document}
  • Quick comment: \@ifnextchar{\space}... actually checks for the presence of a macro containing a space (since \space is a macro containing a space). Replacing by \@ifnextchar\@sptoken would not work either for a different reason: \@ifnextchar ignores spaces before comparing what follows with its first argument. Plenty of packages have probably fixed this oversight, but since you are using expl3, I'd suggest going for \peek_catcode:NTF \c_space_token { } { - } or similar (see documentation of l3token). – Bruno Le Floch Jul 27 '13 at 12:25
  • @BrunoLeFloch: Embarrassed to say this, but I am only using expl3 due to all the wonderful solutions I have obtained from this site. I am still clueless about expl3 and don't think I could easily adapt your suggestion. But will have to tackle it if a solution does not show up when this bounty ends. – Peter Grill Jul 27 '13 at 17:37
10
+200

Here is a try.

The following code only uses your first link style as the different styles didn't seem to be essential for the question. It uses the packages etoolbox for its list processing tools and its \ifblank macro, and Heiko Oberdiek's ltxcmds for its \ltx@ifnextchar that allows for checking a following space via \ltx@ifnextchar{ }{<true>}{<false>}.

The \CreateLink{<address>}{<text>} macro below checks if a space follows. If not the next token is taken and it is checked if it is in a list of tokens that is set with \setlinkpunctuation{<punctuation marks>}. This macro gives you full control which punctuation mark should be included in the link.

We get:

enter image description here

\documentclass{article}
\usepackage{xcolor}
\usepackage{etoolbox,ltxcmds}
\usepackage[colorlinks=true]{hyperref}

\makeatletter
% list parser with no separator:
\DeclareListParser*\@add@punctuation{}
% set the punctuation list (the parser does not like blank lists):
\def\setlinkpunctuation#1{%
  \def\@punctuation{}%
  \ifblank{#1}
    {}
    {\@add@punctuation{\listadd\@punctuation}{#1}}%
}

% check if a space follows; if yes, only create the link, else
% eat the next token:
\newcommand*\CreateLink[2]{%
  \ltx@ifnextchar{ }
    {\@create@link{#1}{#2}{}}
    {\@create@link{#1}{#2}}%
}

% check if #3 is among the punctuation marks
% and either place it inside the link or outside:
\def\@create@link#1#2#3{%
  \ifinlist{#3}{\@punctuation}
    {\@create@actual@link{#1}{#2#3}}
    {\@create@actual@link{#1}{#2}#3}%
}

% the actual link:
\def\@create@actual@link#1#2{%
  \hypersetup{pdfborder={0 0 1}, urlcolor=.}%
  \href{#1}{#2}%
}
\makeatother

\begin{document}

only \texttt{,}\par\medskip
\setlinkpunctuation{,}
Go and check out \CreateLink{www.yahoo.com}{the yahoo}, and also\ldots\par
Go and check out \CreateLink{www.yahoo.com}{the yahoo} and also\ldots\par
Go and check out \CreateLink{www.yahoo.com}{the yahoo}. and also\ldots\par
Go and check out \CreateLink{www.yahoo.com}{the yahoo}! and also\ldots\par

\bigskip
nothing\par\medskip
\setlinkpunctuation{}
Go and check out \CreateLink{www.yahoo.com}{the yahoo}, and also\ldots\par
Go and check out \CreateLink{www.yahoo.com}{the yahoo} and also\ldots\par
Go and check out \CreateLink{www.yahoo.com}{the yahoo}. and also\ldots\par
Go and check out \CreateLink{www.yahoo.com}{the yahoo}! and also\ldots\par

\bigskip
\texttt{,.} and \texttt{!}\par\medskip
\setlinkpunctuation{.,!}
Go and check out \CreateLink{www.yahoo.com}{the yahoo}, and also\ldots\par
Go and check out \CreateLink{www.yahoo.com}{the yahoo} and also\ldots\par
Go and check out \CreateLink{www.yahoo.com}{the yahoo}. and also\ldots\par
Go and check out \CreateLink{www.yahoo.com}{the yahoo}! and also\ldots\par

\end{document}
  • Seems to be working great. – Peter Grill Jul 28 '13 at 23:58
  • 5
    Dear downvoter: thanks for your criticism! :) I'd very much appreciate id, though, if you'd left a comment explaining why you downvoted my answer. I would be able to improve it then. Instead I am unfortunately clueless... – cgnieder Jul 29 '13 at 17:00
  • Some people will do that. What can you do? I wish @downvoter would ping them though. – dustin Jul 29 '13 at 19:17
  • @cgnieder: The question also got voted down, so perhaps a new user. Haven't integrated your code into my actual use case yet, but just realized that you have two \makeatletter so perhaps the downvoter was complaining about that? – Peter Grill Jul 29 '13 at 22:30
  • @PeterGrill Oh! That should have been a \makeatother, of course! I corrected it. – cgnieder Jul 30 '13 at 6:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.