9

I want to define a command, which separates a string an later adds a different \href to the first part, than to the second (e.g. \qname{foaf:Person}). But the code as I have it doesn't work, I get ! Argument of \reserved@a has an extra }., when I try to run it.

\RequirePackage{xstring}
\RequirePackage{hyperref}
\RequirePackage{url}    

\newcommand{\prefix}{}%
\newcommand{\postfix}{}%
\newcommand{\qname}[1]{%
    \IfSubStr{#1}{:}{%
        \renewcommand{\prefix}{\StrBefore{#1}{:}}%
        \renewcommand{\postfix}{\StrBehind{#1}{:}}%
        \nolinkurl{\prefix}:\nolinkurl{\postfix}
    }{%
        \url{#1}%
    }%
}

If I just output \prefix instead of \nolinkurl{\prefix}:\nolinkurl{\postfix} it works, but I want to have it as url.

I think there is something wrong with the variable handling, but I couldn't find information about this.

white_gecko
  • 2,101

3 Answers3

6

Please always post a complete document not just a fragment.

If you add

\show\prefix

you will see it is not exactly the characters before : it is

> \prefix=\long macro:
->\StrBefore {a:b}{:}.

Which presumably does not expand to something hyperref likes.

This version just uses an expandable macro to split on :

\documentclass{article}

\RequirePackage{xstring}
\RequirePackage{hyperref}
\RequirePackage{url}    

\newcommand{\prefix}{}%
\newcommand{\postfix}{}%
\newcommand{\qname}[1]{%
    \IfSubStr{#1}{:}{%
        \renewcommand{\prefix}{\StrBefore{#1}{:}}%
        \renewcommand{\postfix}{\StrBehind{#1}{:}}%
\show\prefix
        \nolinkurl{\prefix}:\nolinkurl{\postfix}
    }{%
        \url{#1}%
    }%
}

\def\qname#1{\xqname#1:\valign:\\}

\def\xqname#1:#2:#3\\{%
  \nolinkurl{#1}%
\ifx\valign#2%
\else
:\nolinkurl{#2}%
\fi}

\begin{document}

\qname{aaa}

\qname{a:b}

\end{document}
David Carlisle
  • 757,742
  • Thank you very much for your answer. But I don't really understand, what it is doing. Does the \def part just replace my definition? (BTW: the else-case \url{#1} is not needed) – white_gecko May 16 '13 at 16:47
  • @white_gecko It splits on : by making a delimited argument so #1 is everythig up to teh first : you can not define such arguments with \newcommand. I left in your definition but with \show added, if you comment out my later definition you will see the \show output that I showed above – David Carlisle May 16 '13 at 16:50
  • ok, and what is the \valign and the #3 for? I only use #1 and #2 as I think. I have now simplified the \xqname to \def\xqname#1:#2:#3\{ \href{http://#1}{\nolinkurl{#1:}} \href{http://#1#2}{\nolinkurl{#2}} } – white_gecko May 16 '13 at 17:02
  • Your simplified version only works if there is a : the \valign is just an arbitrary token unlikely to be in the input so if that is the token after : there was no : originally and the second \nolinkur; is not used – David Carlisle May 16 '13 at 17:06
  • That is fine the argument has to contain a :. I've removed the \valign and #3 now. Am I right, that the \\ is some arbidrary char as end of the command? – white_gecko May 16 '13 at 17:16
3

It's not clear why you want to split at the colon; however, this is a different way to cope with the problem.

\documentclass{article}
\usepackage{xparse,l3regex}
\usepackage{hyperref}

\ExplSyntaxOn
\tl_new:N \l_gecko_prefix_tl
\tl_new:N \l_gecko_postfix_tl
\NewDocumentCommand{\qname}{m}
 {
  \regex_match:nnTF { \: } { #1 }
   {
    \tl_set:Nn \l_gecko_prefix_tl { #1 }
    \tl_set:Nn \l_gecko_postfix_tl { #1 }
    \regex_replace_once:nnN { \A (.*) \: (.*) \Z } { \1 } \l_gecko_prefix_tl
    \regex_replace_once:nnN { \A (.*) \: (.*) \Z } { \2 } \l_gecko_postfix_tl
    \nolinkurl{ \l_gecko_prefix_tl } : \nolinkurl{ \l_gecko_postfix_tl }
   }
   {\url{#1}}
 }\ExplSyntaxOff

\begin{document}
\qname{foo:bar}

\qname{http://tex.stackexchange.com}

\qname{127.0.0.1}
\end{document}
egreg
  • 1,121,712
1

Not sure if this addresses your issue. It uses the stringstrings package to parse the string.

\documentclass{article}
\RequirePackage{stringstrings}
\usepackage{ifthen}
\RequirePackage{hyperref}
\RequirePackage{url}    

\newcommand{\prefix}{}%
\newcommand{\postfix}{}%
\newcounter{index}
\newcommand{\qname}[1]{%
  \whereischar[q]{#1}{:}%
  \setcounter{index}{\theresult}%
  \ifthenelse{\value{index} = 0}%
    {\url{#1}}%
    {%
      \addtocounter{index}{-1}%
      \substring[q]{#1}{1}{\value{index}}%
      \edef\prefix{\thestring}%
      \addtocounter{index}{2}%
      \substring[q]{#1}{\value{index}}{$}%
      \edef\postfix{\thestring}%
      \nolinkurl{\prefix}:\nolinkurl{\postfix}
    }%
}

\begin{document}

\qname{aaa}

\qname{a:b}

\qname{http://tex.stackexchange.com}

\end{document}

enter image description here