A command challenge












7















Here's a little challenge. The goal is to create a command that takes is two or three arguments without using square brackets for optional arguments. The first and second argument are separated by a comma and a space, while the second and the third (if present) are separated by a dash. This means that both of the following inputs should be acceptable



mycommand{arg_1, arg_2}


and



mycommand{arg_1, arg_2-arg_3}


The definition of what mycommand does with the two/three arguments is irrelevant to the problem.










share|improve this question


















  • 1





    That's one argument from a TeX point of view ... I guess you want a parser for that one document-level argument.

    – Joseph Wright
    5 hours ago











  • Try defmycommand#1,space#2-#3{...}.

    – John Kormylo
    1 hour ago


















7















Here's a little challenge. The goal is to create a command that takes is two or three arguments without using square brackets for optional arguments. The first and second argument are separated by a comma and a space, while the second and the third (if present) are separated by a dash. This means that both of the following inputs should be acceptable



mycommand{arg_1, arg_2}


and



mycommand{arg_1, arg_2-arg_3}


The definition of what mycommand does with the two/three arguments is irrelevant to the problem.










share|improve this question


















  • 1





    That's one argument from a TeX point of view ... I guess you want a parser for that one document-level argument.

    – Joseph Wright
    5 hours ago











  • Try defmycommand#1,space#2-#3{...}.

    – John Kormylo
    1 hour ago
















7












7








7


2






Here's a little challenge. The goal is to create a command that takes is two or three arguments without using square brackets for optional arguments. The first and second argument are separated by a comma and a space, while the second and the third (if present) are separated by a dash. This means that both of the following inputs should be acceptable



mycommand{arg_1, arg_2}


and



mycommand{arg_1, arg_2-arg_3}


The definition of what mycommand does with the two/three arguments is irrelevant to the problem.










share|improve this question














Here's a little challenge. The goal is to create a command that takes is two or three arguments without using square brackets for optional arguments. The first and second argument are separated by a comma and a space, while the second and the third (if present) are separated by a dash. This means that both of the following inputs should be acceptable



mycommand{arg_1, arg_2}


and



mycommand{arg_1, arg_2-arg_3}


The definition of what mycommand does with the two/three arguments is irrelevant to the problem.







macros expl3 xparse






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked 5 hours ago









noibenoibe

985




985








  • 1





    That's one argument from a TeX point of view ... I guess you want a parser for that one document-level argument.

    – Joseph Wright
    5 hours ago











  • Try defmycommand#1,space#2-#3{...}.

    – John Kormylo
    1 hour ago
















  • 1





    That's one argument from a TeX point of view ... I guess you want a parser for that one document-level argument.

    – Joseph Wright
    5 hours ago











  • Try defmycommand#1,space#2-#3{...}.

    – John Kormylo
    1 hour ago










1




1





That's one argument from a TeX point of view ... I guess you want a parser for that one document-level argument.

– Joseph Wright
5 hours ago





That's one argument from a TeX point of view ... I guess you want a parser for that one document-level argument.

– Joseph Wright
5 hours ago













Try defmycommand#1,space#2-#3{...}.

– John Kormylo
1 hour ago







Try defmycommand#1,space#2-#3{...}.

– John Kormylo
1 hour ago












4 Answers
4






active

oldest

votes


















8














You can do it with xparse:



documentclass{article}
usepackage{xparse}

% split at the comma
NewDocumentCommand{mycommand}{ >{SplitArgument{1}{,}}m }{%
mycommandA#1%
}
% do something with #1 and split the second part at the hyphen
NewDocumentCommand{mycommandA}{ m >{SplitArgument{1}{-}}m }{%
Main is #1%
IfNoValueTF{#2}{.}{; mycommandB#2}%
}
% do something with the second part
NewDocumentCommand{mycommandB}{mm}{%
Secondary is #1IfValueT{#2}{ plus #2}.%
}

begin{document}

mycommand{arg1}

mycommand{arg1, arg2}

mycommand{arg1, arg2-arg3}

end{document}


enter image description here



An advantage: it's irrelevant if you forget the space after the comma.






share|improve this answer































    10














    enter image description here



    documentclass{article}

    defmycommand#1{xmycommand#1--relax}
    defxmycommand#1,#2-#3-#4relax{[#1][#2][#3]}


    begin{document}

    $mycommand{arg_1, arg_2}$

    $mycommand{arg_1, arg_2-arg3}$

    end{document}





    share|improve this answer



















    • 6





      Even without electricity. I'm impressed!

      – marmot
      5 hours ago











    • How about adding some mortar to the bricks!?

      – Werner
      5 hours ago











    • @Werner where I come from we prefer this style: derbyshireuk.net/derbyshire_drystonewalls.html

      – David Carlisle
      5 hours ago











    • @DavidCarlisle: It seems drafty... :D

      – Werner
      5 hours ago






    • 2





      @noibe oh no a disaster! I don't mind not getting the tick (I have more than enough points) but seeing points go to egreg is so depressing:)

      – David Carlisle
      4 hours ago



















    2














    A listofitems approach.



    documentclass{article}
    usepackage{listofitems}
    newcommandmycommand[1]{setsepchar{,/-}readlist*myargs{#1}%
    noindent Arg 1 is myargs[1]\
    Arg 2 is myargs[2,1]\
    Arg 3 is ifnumlistlenmyargs[2]=1relax Absentelsemyargs[2,2]fi%
    }
    begin{document}

    mycommand{arg1, arg2}

    and

    mycommand{arg1, arg2-arg3}

    end{document}


    enter image description here






    share|improve this answer































      0














      Some crocheting/knitting by hand (or whatever)... ;-)



      I suppose this question came into being while you thought about your other question: Custom cite command. In that question you ask for a customized cite-command with the same syntax.



      Be that as it may.



      The challenge is doing it in a way where desired space-removal but no undesired removal of argument-braces takes place.



      E.g., with things like mycommand{{arg_1}a, arg_2} the braces surrounding arg_1 should probably be preserved while with things like mycommand{{arg_1} , arg_2} they should probably be removed.

      Also probably only space-tokens surrounding the entire arguments/surrounding those commas and those dashes that are taken for argument-separators should get removed.



      Below is an approach where comma takes precedence over the dash where and the leftmost unhidden comma delimits the first argument from the remaining arguments and where the first unhidden dash following that comma delimits the second from the third argument.

      Exactly one level of braces will be removed in case after removing surrounding spaces it surrounds an entire argument as in that case it is assumed that the braces serve for hiding commas/dashes/spaces/emptiness. In all other cases braces will be preserved.



      E.g., with things like mycommand{ {arg_1} , {arg_2-2} - arg_3} you should get:

      First argument: arg_1

      Second argument: arg_2-2

      Third argument: arg_3.



      E.g., with things like mycommand{ {{arg 1,a} - arg 1b} , {arg 2-2} , 2 - arg 3a - arg 3b} you should get:

      First argument (left from the first unhidden comma, surrounding spaces and outermost brace-level that surrounds the entire argument removed): {arg 1,a} - arg 1b

      Second argument (right from the first unhidden comma, left from the first unhidden dash following the comma): {arg 2-2} , 2

      Third argument (the remainder, right from the first unhidden dash following the comma): arg 3a - arg 3b.



      E.g., with things like mycommand{{arg 1}, {arg 2-2} , 2 - arg 3a - arg 3b} you should get:

      First argument (left from the first unhidden comma): arg 1

      Second argument (right from the first unhidden comma, left from the first unhidden dash following the comma): {arg 2-2} , 2

      Third argument (the remainder, right from the first unhidden dash following the comma): arg 3a - arg 3b.



      You may not be familiar to methods for removing space-tokens that surround arguments, thus a quote from the manual of my deprecated labelcas-package:




      A note about removing leading and trailing spaces



      The matter of removing trailing spaces from an (almost) arbitrary
      token-sequence is elaborated in detail by Michael Downes, 'Around the
      Bend #15, answers', a summary of internet-discussion which took place
      under his guidance primarily at the INFO-TEX list, but also at
      comp.text.tex (usenet) and via private email; December 1993. Online
      archived at http://www.tug.org/tex-archive/info/arobend/answer.015.



      One basic approach suggested therein is using TeX's scanning of
      delimited parameters in order to detect and discard the ending space
      of an argument:




      ... scan for a pair of tokens: a space-token and some well-chosen
      bizarre token that can't possibly occur in the scanned text. If you
      put the bizarre token at the end of the text, and if the text has a
      trailing space, then TeX's delimiter matching will match at that point
      and not before, because the earlier occurrences of space don’t have
      the requisite other member of the pair.



      Next consider the possibility that the trailing space is absent: TeX
      will keep on scanning ahead for the pair
      ⟨space⟩⟨bizarre⟩
      until either it finds them or it decides to give up and signal a
      'Runaway argument?' error. So you must add a stop pair to catch the
      runaway argument possibility: a second instance of the bizarre
      token, preceded by a space. If TeX doesn't find a match at the
      first bizarre token, it will at the second one.




      (Look up the macros KV@@sp@def, KV@@sp@b, KV@@sp@c and KV@@sp@d in
      David Carlisle’s keyval-package for an interesting variation on this
      approach.)



      When scanning for parameters
      ##1⟨space⟩⟨bizarre⟩##2⟨B1⟩

      the sequence:
      ⟨stuff where to remove trail-space⟩⟨bizarre⟩⟨space⟩⟨bizarre⟩⟨B1⟩

      , you can fork two cases:




      1. Trailing-space:
        ##1 = ⟨stuff where to remove trail-space⟩, but with removed space. (And possibly one
        removed brace-level!)
        ##2 = ⟨space⟩⟨bizarre⟩.


      2. No trailing-space:
        ##1 = ⟨stuff where to remove trail-space⟩⟨bizarre⟩.
        ##2 is empty.



      So forking can be implemented depending on the emptiness of ##2.

      You can easily prevent the brace-removal in the first case, e.g., by adding (and
      later removing) something (e.g., a space-token) in front of the
      ⟨stuff where to remove trail-space⟩.



      You can choose ⟨B1⟩=⟨bizarre⟩⟨space⟩.




      The link in the quote is out of date.

      Nowadays you can find the entire "Around the bend" -collection at http://mirrors.ctan.org/info/challenges/AroBend/AroundTheBend.pdf.



      As you see, the methods for space-removal exhibited in the quote above do rely on some sequence of tokens that must not occur within the argument.



      In the example below it is relied on the token UD@seldom not occurring within arguments.

      In other words: You must not use the token UD@seldom within your arguments.



      If you don't like that restriction, then I can deliver space-removal-routines which do without such restrictions, but they are slower and they form another huge load of code.



      documentclass{article}

      makeatletter
      %%-----------------------------------------------------------------------------
      %% Paraphernalia ;-) :
      %%.............................................................................
      newcommandUD@firstoftwo[2]{#1}%
      newcommandUD@secondoftwo[2]{#2}%
      newcommandUD@exchange[2]{#2#1}%
      newcommandUD@removespace{}UD@firstoftwo{defUD@removespace}{} {}%
      %%-----------------------------------------------------------------------------
      %% Check whether argument is empty:
      %%.............................................................................
      %% UD@CheckWhetherNull{<Argument which is to be checked>}%
      %% {<Tokens to be delivered in case that argument
      %% which is to be checked is empty>}%
      %% {<Tokens to be delivered in case that argument
      %% which is to be checked is not empty>}%
      %% The gist of this macro comes from Robert R. Schneck's ifempty-macro:
      %% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
      %%.............................................................................
      newcommandUD@CheckWhetherNull[1]{%
      romannumeral0expandafterUD@secondoftwostring{expandafter
      UD@secondoftwoexpandafter{expandafter{string#1}expandafter
      UD@secondoftwostring}expandafterUD@firstoftwoexpandafter{expandafter
      UD@secondoftwostring}expandafterexpandafterUD@firstoftwo{ }{}%
      UD@secondoftwo}{expandafterexpandafterUD@firstoftwo{ }{}UD@firstoftwo}%
      }%
      %%-----------------------------------------------------------------------------
      %% Check whether argument's first token is a catcode-1-character
      %%.............................................................................
      %% UD@CheckWhetherBrace{<Argument which is to be checked>}%
      %% {<Tokens to be delivered in case that argument
      %% which is to be checked has leading
      %% catcode-1-token>}%
      %% {<Tokens to be delivered in case that argument
      %% which is to be checked has no leading
      %% catcode-1-token>}%
      newcommandUD@CheckWhetherBrace[1]{%
      romannumeral0expandafterUD@secondoftwoexpandafter{expandafter{%
      string#1.}expandafterUD@firstoftwoexpandafter{expandafter
      UD@secondoftwostring}expandafterexpandafterUD@firstoftwo{ }{}%
      UD@firstoftwo}{expandafterexpandafterUD@firstoftwo{ }{}UD@secondoftwo}%
      }%
      %%-----------------------------------------------------------------------------
      %% Check whether brace-balanced argument starts with a space-token
      %%.............................................................................
      %% UD@CheckWhetherLeadingSpace{<Argument which is to be checked>}%
      %% {<Tokens to be delivered in case <argument
      %% which is to be checked>'s 1st token is a
      %% space-token>}%
      %% {<Tokens to be delivered in case <argument
      %% which is to be checked>'s 1st token is not
      %% a space-token>}%
      newcommandUD@CheckWhetherLeadingSpace[1]{%
      romannumeral0UD@CheckWhetherNull{#1}%
      {expandafterexpandafterUD@firstoftwo{ }{}UD@secondoftwo}%
      {expandafterUD@secondoftwostring{UD@CheckWhetherLeadingSpaceB.#1 }{}}%
      }%
      newcommandUD@CheckWhetherLeadingSpaceB{}%
      longdefUD@CheckWhetherLeadingSpaceB#1 {%
      expandafterUD@CheckWhetherNullexpandafter{UD@secondoftwo#1{}}%
      {UD@exchange{UD@firstoftwo}}{UD@exchange{UD@secondoftwo}}%
      {UD@exchange{ }{expandafterexpandafterexpandafterexpandafter
      expandafterexpandafterexpandafter}expandafterexpandafter
      expandafter}expandafterUD@secondoftwoexpandafter{string}%
      }%
      %%-----------------------------------------------------------------------------
      %% Extract first inner undelimited argument:
      %%.............................................................................
      %% UD@ExtractFirstArg{ABCDE} yields {A}
      %%
      %% UD@ExtractFirstArg{{AB}CDE} yields {AB}
      %%.............................................................................
      newcommandUD@RemoveTillUD@SelDOm{}%
      longdefUD@RemoveTillUD@SelDOm#1#2UD@SelDOm{{#1}}%
      newcommandUD@ExtractFirstArg[1]{%
      romannumeral0%
      UD@ExtractFirstArgLoop{#1UD@SelDOm}%
      }%
      newcommandUD@ExtractFirstArgLoop[1]{%
      expandafterUD@CheckWhetherNullexpandafter{UD@firstoftwo{}#1}%
      { #1}%
      {expandafterUD@ExtractFirstArgLoopexpandafter{UD@RemoveTillUD@SelDOm#1}}%
      }%
      %%-----------------------------------------------------------------------------
      %% UD@RemoveSpaces{<argument>} removes leading and trailing spaces from
      %% <argument>.
      %% !!!! <argument> must not contain the token UD@seldom !!!!
      %%.............................................................................
      begingroup
      newcommandUD@RemoveSpacesAndOneLevelOfBraces[1]{%
      endgroup
      newcommandUD@RemoveSpacesAndOneLevelOfBraces[1]{%
      romannumeral0%
      UD@trimtrailspaceloop#1##1UD@seldom#1UD@seldomUD@seldom#1{##1}%
      }%
      newcommandUD@trimtrailspaceloop{}%
      longdefUD@trimtrailspaceloop##1#1UD@seldom##2UD@seldom#1##3{%
      UD@CheckWhetherNull{##2}{%
      UD@trimleadspaceloop{##3}%
      }{%
      UD@trimtrailspaceloop##1UD@seldom#1UD@seldomUD@seldom#1{##1}%
      }%
      }%
      }%
      UD@RemoveSpacesAndOneLevelOfBraces{ }%
      newcommandUD@trimleadspaceloop[1]{%
      UD@CheckWhetherLeadingSpace{#1}{%
      expandafterUD@trimleadspaceloopexpandafter{UD@removespace#1}%
      }{%
      UD@CheckWhetherNull{#1}{ }{%
      expandafterUD@CheckWhetherNullexpandafter{UD@firstoftwo{}#1}{%
      UD@exchange{ }{expandafter}UD@secondoftwo{}#1%
      }{ #1}%
      }%
      }%
      }%
      %%-----------------------------------------------------------------------------
      %% Check whether argument contains no comma which is not nested
      %% in braces:
      %%.............................................................................
      %% UD@CheckWhetherNoComma{<Argument which is to be checked>}%
      %% {<Tokens to be delivered in case that argument
      %% contains no comma>}%
      %% {<Tokens to be delivered in case that argument
      %% contains comma>}%
      %%
      newcommandUD@GobbleToComma{}longdefUD@GobbleToComma#1,{}%
      newcommandUD@CheckWhetherNoComma[1]{%
      expandafterUD@CheckWhetherNullexpandafter{UD@GobbleToComma#1,}%
      }%
      %%-----------------------------------------------------------------------------
      %% Check whether argument contains no dash which is not nested
      %% in braces:
      %%.............................................................................
      %% UD@CheckWhetherNoDash{<Argument which is to be checked>}%
      %% {<Tokens to be delivered in case that argument
      %% contains no dash>}%
      %% {<Tokens to be delivered in case that argument
      %% contains dash>}%
      %%
      newcommandUD@GobbleToDash{}longdefUD@GobbleToDash#1-{}%
      newcommandUD@CheckWhetherNoDash[1]{%
      expandafterUD@CheckWhetherNullexpandafter{UD@GobbleToDash#1-}%
      }%
      %%-----------------------------------------------------------------------------
      %% Take a comma-delimited/dash-delimited argument where a space was
      %% prepended for preventing brace-removal and wrap it in curly braces.
      %%.............................................................................
      newcommandUD@SplitCommaArg{}%
      longdefUD@SplitCommaArg#1,{%
      romannumeral0UD@exchange{ }{expandafter}expandafter{UD@removespace#1}%
      }%
      newcommandUD@SplitDashArg{}%
      longdefUD@SplitDashArg#1-{%
      romannumeral0UD@exchange{ }{expandafter}expandafter{UD@removespace#1}%
      }%
      %%-----------------------------------------------------------------------------
      %% Now we have the tools for creating the desired mycommand-macro:
      %%.............................................................................
      newcommandmycommand[1]{%
      romannumeral0%
      UD@CheckWhetherNoComma{#1}{%
      expandafterUD@exchangeexpandafter{%
      expandafter{%
      romannumeral0UD@exchange{ }{expandafterexpandafterexpandafter}%
      UD@RemoveSpacesAndOneLevelOfBraces{#1}%
      }%
      }{mycommand@oneargument}%
      }{%
      expandafterUD@exchangeexpandafter{expandafter%
      {%
      romannumeral0%
      UD@exchange{ }{expandafterexpandafterexpandafter}%
      expandafterUD@firstoftwoexpandafter{expandafter}%
      romannumeral0%
      UD@exchange{ }{%
      expandafterexpandafterexpandafterexpandafter
      expandafterexpandafterexpandafter
      }%
      expandafterUD@SplitCommaArg
      UD@firstoftwo{ }{}#1}%
      }{%
      expandafter@mycommand
      romannumeral0%
      UD@exchange{ }{%
      expandafterexpandafterexpandafterexpandafter
      expandafterexpandafterexpandafter
      }%
      expandafterUD@ExtractFirstArgexpandafter{%
      romannumeral0%
      UD@exchange{ }{%
      expandafterexpandafterexpandafterexpandafter
      expandafterexpandafterexpandafter
      }%
      expandafterUD@SplitCommaArg
      UD@firstoftwo{ }{}#1}%
      }%
      }%
      }%
      newcommand@mycommand[2]{%
      UD@CheckWhetherNoDash{#2}{%
      expandafterUD@exchangeexpandafter{expandafter
      {%
      romannumeral0%
      UD@exchange{ }{expandafterexpandafterexpandafter}%
      UD@RemoveSpacesAndOneLevelOfBraces{#2}%
      }%
      }{%
      expandafterUD@exchangeexpandafter{%
      expandafter{%
      romannumeral0%
      UD@exchange{ }{expandafterexpandafterexpandafter}%
      UD@RemoveSpacesAndOneLevelOfBraces{#1}%
      }%
      }{mycommand@twoarguments}%
      }%
      }{%
      expandafterUD@exchangeexpandafter{expandafter%
      {%
      romannumeral0%
      UD@exchange{ }{expandafterexpandafterexpandafter}%
      expandafterUD@firstoftwoexpandafter{expandafter}%
      romannumeral0%
      UD@exchange{ }{%
      expandafterexpandafterexpandafterexpandafter
      expandafterexpandafterexpandafter
      }%
      expandafterUD@SplitDashArg
      UD@firstoftwo{ }{}#2}%
      }{%
      expandafter@@mycommand
      romannumeral0%
      UD@exchange{ }{%
      expandafterexpandafterexpandafterexpandafter
      expandafterexpandafterexpandafter
      }%
      expandafterUD@ExtractFirstArgexpandafter{%
      romannumeral0%
      UD@exchange{ }{%
      expandafterexpandafterexpandafterexpandafter
      expandafterexpandafterexpandafter
      }%
      expandafterUD@SplitDashArg
      UD@firstoftwo{ }{}#2}%
      }%
      {#1}%
      }%
      }%
      newcommand@@mycommand[3]{%
      expandafterUD@exchangeexpandafter{%
      expandafter{%
      romannumeral0%
      UD@exchange{ }{expandafterexpandafterexpandafter}%
      UD@RemoveSpacesAndOneLevelOfBraces{#2}%
      }%
      }{%
      expandafterUD@exchangeexpandafter{%
      expandafter{%
      romannumeral0%
      UD@exchange{ }{expandafterexpandafterexpandafter}%
      UD@RemoveSpacesAndOneLevelOfBraces{#1}%
      }%
      }{%
      expandafterUD@exchangeexpandafter{%
      expandafter{%
      romannumeral0%
      UD@exchange{ }{expandafterexpandafterexpandafter}%
      UD@RemoveSpacesAndOneLevelOfBraces{#3}%
      }%
      }{mycommand@threearguments}%
      }%
      }%
      }%
      newcommandmycommand@oneargument[1]{%
      UD@secondoftwo{%
      %We need a space to stop romannumeral-expansion.
      }{ }%
      There is no comma or only empty args after the comma, thus:\
      argument 1 = printmeaning{#1}%
      }%
      newcommandmycommand@twoarguments[2]{%
      UD@CheckWhetherNull{#2}{%
      mycommand@oneargument{#1}%
      }{%
      UD@secondoftwo{%
      %We need a space to stop romannumeral-expansion.
      }{ }%
      There is a comma but either no dash or only one non-empty argument near
      the dash, thus:\
      argument 1 = printmeaning{#1}\
      argument 2 = printmeaning{#2}%
      }%
      }%
      newcommandmycommand@threearguments[3]{%
      UD@CheckWhetherNull{#2}{%
      UD@CheckWhetherNull{#3}{%
      mycommand@oneargument{#1}%
      }{%x
      mycommand@twoarguments{#1}{#3}%
      }%
      }{%
      UD@CheckWhetherNull{#3}{%
      mycommand@twoarguments{#1}{#2}%
      }{%
      UD@secondoftwo{%
      %We need a space to stop romannumeral-expansion.
      }{ }%
      There is a comma and a dash, thus:\
      argument 1 = printmeaning{#1}\
      argument 2 = printmeaning{#2}\
      argument 3 = printmeaning{#3}%
      }%
      }%
      }%

      newcommandprintmeaning[1]{%
      defUD@tempa{#1}%
      fbox{texttt{expandafterstrip@prefixmeaningUD@tempa}}%
      }%

      makeatother

      parindent=0ex
      parskip=smallskipamount

      begin{document}

      verb|mycommand{ arg 1 }|:\
      mycommand{ arg 1 }\
      nullhrulefillnull

      verb|mycommand{ arg 1 , }|:\
      mycommand{ arg 1 , }\
      nullhrulefillnull

      verb|mycommand{ arg 1 , - }|:\
      mycommand{ arg 1 , - }\
      nullhrulefillnull

      verb|mycommand{ arg 1 , arg 2 - }|:\
      mycommand{ arg 1 , arg 2 - }\
      nullhrulefillnull

      verb|mycommand{ arg 1 , arg 2 - arg 3}|:\
      mycommand{ arg 1 , arg 2 - arg 3}\
      nullhrulefillnull

      verb|mycommand{ arg 1 , - arg 3}|:\
      mycommand{ arg 1 , - arg 3}\
      nullhrulefillnull

      verb|mycommand{ {arg 1a} - arg 1b , {arg 2-2} , 2 - arg 3a - arg 3b}|:\
      mycommand{ {arg 1a} - arg 1b , {arg 2-2} , 2 - arg 3a - arg 3b}\
      nullhrulefillnull

      verb|mycommand{ {arg 1} , {arg 2-2} , 2 - arg 3a - arg 3b}|:\
      mycommand{ {arg 1} , {arg 2-2} , 2 - arg 3a - arg 3b}

      end{document}


      enter image description here






      share|improve this answer

























        Your Answer








        StackExchange.ready(function() {
        var channelOptions = {
        tags: "".split(" "),
        id: "85"
        };
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function() {
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled) {
        StackExchange.using("snippets", function() {
        createEditor();
        });
        }
        else {
        createEditor();
        }
        });

        function createEditor() {
        StackExchange.prepareEditor({
        heartbeatType: 'answer',
        autoActivateHeartbeat: false,
        convertImagesToLinks: false,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: null,
        bindNavPrevention: true,
        postfix: "",
        imageUploader: {
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        },
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        });


        }
        });














        draft saved

        draft discarded


















        StackExchange.ready(
        function () {
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f473965%2fa-command-challenge%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        4 Answers
        4






        active

        oldest

        votes








        4 Answers
        4






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        8














        You can do it with xparse:



        documentclass{article}
        usepackage{xparse}

        % split at the comma
        NewDocumentCommand{mycommand}{ >{SplitArgument{1}{,}}m }{%
        mycommandA#1%
        }
        % do something with #1 and split the second part at the hyphen
        NewDocumentCommand{mycommandA}{ m >{SplitArgument{1}{-}}m }{%
        Main is #1%
        IfNoValueTF{#2}{.}{; mycommandB#2}%
        }
        % do something with the second part
        NewDocumentCommand{mycommandB}{mm}{%
        Secondary is #1IfValueT{#2}{ plus #2}.%
        }

        begin{document}

        mycommand{arg1}

        mycommand{arg1, arg2}

        mycommand{arg1, arg2-arg3}

        end{document}


        enter image description here



        An advantage: it's irrelevant if you forget the space after the comma.






        share|improve this answer




























          8














          You can do it with xparse:



          documentclass{article}
          usepackage{xparse}

          % split at the comma
          NewDocumentCommand{mycommand}{ >{SplitArgument{1}{,}}m }{%
          mycommandA#1%
          }
          % do something with #1 and split the second part at the hyphen
          NewDocumentCommand{mycommandA}{ m >{SplitArgument{1}{-}}m }{%
          Main is #1%
          IfNoValueTF{#2}{.}{; mycommandB#2}%
          }
          % do something with the second part
          NewDocumentCommand{mycommandB}{mm}{%
          Secondary is #1IfValueT{#2}{ plus #2}.%
          }

          begin{document}

          mycommand{arg1}

          mycommand{arg1, arg2}

          mycommand{arg1, arg2-arg3}

          end{document}


          enter image description here



          An advantage: it's irrelevant if you forget the space after the comma.






          share|improve this answer


























            8












            8








            8







            You can do it with xparse:



            documentclass{article}
            usepackage{xparse}

            % split at the comma
            NewDocumentCommand{mycommand}{ >{SplitArgument{1}{,}}m }{%
            mycommandA#1%
            }
            % do something with #1 and split the second part at the hyphen
            NewDocumentCommand{mycommandA}{ m >{SplitArgument{1}{-}}m }{%
            Main is #1%
            IfNoValueTF{#2}{.}{; mycommandB#2}%
            }
            % do something with the second part
            NewDocumentCommand{mycommandB}{mm}{%
            Secondary is #1IfValueT{#2}{ plus #2}.%
            }

            begin{document}

            mycommand{arg1}

            mycommand{arg1, arg2}

            mycommand{arg1, arg2-arg3}

            end{document}


            enter image description here



            An advantage: it's irrelevant if you forget the space after the comma.






            share|improve this answer













            You can do it with xparse:



            documentclass{article}
            usepackage{xparse}

            % split at the comma
            NewDocumentCommand{mycommand}{ >{SplitArgument{1}{,}}m }{%
            mycommandA#1%
            }
            % do something with #1 and split the second part at the hyphen
            NewDocumentCommand{mycommandA}{ m >{SplitArgument{1}{-}}m }{%
            Main is #1%
            IfNoValueTF{#2}{.}{; mycommandB#2}%
            }
            % do something with the second part
            NewDocumentCommand{mycommandB}{mm}{%
            Secondary is #1IfValueT{#2}{ plus #2}.%
            }

            begin{document}

            mycommand{arg1}

            mycommand{arg1, arg2}

            mycommand{arg1, arg2-arg3}

            end{document}


            enter image description here



            An advantage: it's irrelevant if you forget the space after the comma.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered 5 hours ago









            egregegreg

            718k8719043200




            718k8719043200























                10














                enter image description here



                documentclass{article}

                defmycommand#1{xmycommand#1--relax}
                defxmycommand#1,#2-#3-#4relax{[#1][#2][#3]}


                begin{document}

                $mycommand{arg_1, arg_2}$

                $mycommand{arg_1, arg_2-arg3}$

                end{document}





                share|improve this answer



















                • 6





                  Even without electricity. I'm impressed!

                  – marmot
                  5 hours ago











                • How about adding some mortar to the bricks!?

                  – Werner
                  5 hours ago











                • @Werner where I come from we prefer this style: derbyshireuk.net/derbyshire_drystonewalls.html

                  – David Carlisle
                  5 hours ago











                • @DavidCarlisle: It seems drafty... :D

                  – Werner
                  5 hours ago






                • 2





                  @noibe oh no a disaster! I don't mind not getting the tick (I have more than enough points) but seeing points go to egreg is so depressing:)

                  – David Carlisle
                  4 hours ago
















                10














                enter image description here



                documentclass{article}

                defmycommand#1{xmycommand#1--relax}
                defxmycommand#1,#2-#3-#4relax{[#1][#2][#3]}


                begin{document}

                $mycommand{arg_1, arg_2}$

                $mycommand{arg_1, arg_2-arg3}$

                end{document}





                share|improve this answer



















                • 6





                  Even without electricity. I'm impressed!

                  – marmot
                  5 hours ago











                • How about adding some mortar to the bricks!?

                  – Werner
                  5 hours ago











                • @Werner where I come from we prefer this style: derbyshireuk.net/derbyshire_drystonewalls.html

                  – David Carlisle
                  5 hours ago











                • @DavidCarlisle: It seems drafty... :D

                  – Werner
                  5 hours ago






                • 2





                  @noibe oh no a disaster! I don't mind not getting the tick (I have more than enough points) but seeing points go to egreg is so depressing:)

                  – David Carlisle
                  4 hours ago














                10












                10








                10







                enter image description here



                documentclass{article}

                defmycommand#1{xmycommand#1--relax}
                defxmycommand#1,#2-#3-#4relax{[#1][#2][#3]}


                begin{document}

                $mycommand{arg_1, arg_2}$

                $mycommand{arg_1, arg_2-arg3}$

                end{document}





                share|improve this answer













                enter image description here



                documentclass{article}

                defmycommand#1{xmycommand#1--relax}
                defxmycommand#1,#2-#3-#4relax{[#1][#2][#3]}


                begin{document}

                $mycommand{arg_1, arg_2}$

                $mycommand{arg_1, arg_2-arg3}$

                end{document}






                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered 5 hours ago









                David CarlisleDavid Carlisle

                489k4111321880




                489k4111321880








                • 6





                  Even without electricity. I'm impressed!

                  – marmot
                  5 hours ago











                • How about adding some mortar to the bricks!?

                  – Werner
                  5 hours ago











                • @Werner where I come from we prefer this style: derbyshireuk.net/derbyshire_drystonewalls.html

                  – David Carlisle
                  5 hours ago











                • @DavidCarlisle: It seems drafty... :D

                  – Werner
                  5 hours ago






                • 2





                  @noibe oh no a disaster! I don't mind not getting the tick (I have more than enough points) but seeing points go to egreg is so depressing:)

                  – David Carlisle
                  4 hours ago














                • 6





                  Even without electricity. I'm impressed!

                  – marmot
                  5 hours ago











                • How about adding some mortar to the bricks!?

                  – Werner
                  5 hours ago











                • @Werner where I come from we prefer this style: derbyshireuk.net/derbyshire_drystonewalls.html

                  – David Carlisle
                  5 hours ago











                • @DavidCarlisle: It seems drafty... :D

                  – Werner
                  5 hours ago






                • 2





                  @noibe oh no a disaster! I don't mind not getting the tick (I have more than enough points) but seeing points go to egreg is so depressing:)

                  – David Carlisle
                  4 hours ago








                6




                6





                Even without electricity. I'm impressed!

                – marmot
                5 hours ago





                Even without electricity. I'm impressed!

                – marmot
                5 hours ago













                How about adding some mortar to the bricks!?

                – Werner
                5 hours ago





                How about adding some mortar to the bricks!?

                – Werner
                5 hours ago













                @Werner where I come from we prefer this style: derbyshireuk.net/derbyshire_drystonewalls.html

                – David Carlisle
                5 hours ago





                @Werner where I come from we prefer this style: derbyshireuk.net/derbyshire_drystonewalls.html

                – David Carlisle
                5 hours ago













                @DavidCarlisle: It seems drafty... :D

                – Werner
                5 hours ago





                @DavidCarlisle: It seems drafty... :D

                – Werner
                5 hours ago




                2




                2





                @noibe oh no a disaster! I don't mind not getting the tick (I have more than enough points) but seeing points go to egreg is so depressing:)

                – David Carlisle
                4 hours ago





                @noibe oh no a disaster! I don't mind not getting the tick (I have more than enough points) but seeing points go to egreg is so depressing:)

                – David Carlisle
                4 hours ago











                2














                A listofitems approach.



                documentclass{article}
                usepackage{listofitems}
                newcommandmycommand[1]{setsepchar{,/-}readlist*myargs{#1}%
                noindent Arg 1 is myargs[1]\
                Arg 2 is myargs[2,1]\
                Arg 3 is ifnumlistlenmyargs[2]=1relax Absentelsemyargs[2,2]fi%
                }
                begin{document}

                mycommand{arg1, arg2}

                and

                mycommand{arg1, arg2-arg3}

                end{document}


                enter image description here






                share|improve this answer




























                  2














                  A listofitems approach.



                  documentclass{article}
                  usepackage{listofitems}
                  newcommandmycommand[1]{setsepchar{,/-}readlist*myargs{#1}%
                  noindent Arg 1 is myargs[1]\
                  Arg 2 is myargs[2,1]\
                  Arg 3 is ifnumlistlenmyargs[2]=1relax Absentelsemyargs[2,2]fi%
                  }
                  begin{document}

                  mycommand{arg1, arg2}

                  and

                  mycommand{arg1, arg2-arg3}

                  end{document}


                  enter image description here






                  share|improve this answer


























                    2












                    2








                    2







                    A listofitems approach.



                    documentclass{article}
                    usepackage{listofitems}
                    newcommandmycommand[1]{setsepchar{,/-}readlist*myargs{#1}%
                    noindent Arg 1 is myargs[1]\
                    Arg 2 is myargs[2,1]\
                    Arg 3 is ifnumlistlenmyargs[2]=1relax Absentelsemyargs[2,2]fi%
                    }
                    begin{document}

                    mycommand{arg1, arg2}

                    and

                    mycommand{arg1, arg2-arg3}

                    end{document}


                    enter image description here






                    share|improve this answer













                    A listofitems approach.



                    documentclass{article}
                    usepackage{listofitems}
                    newcommandmycommand[1]{setsepchar{,/-}readlist*myargs{#1}%
                    noindent Arg 1 is myargs[1]\
                    Arg 2 is myargs[2,1]\
                    Arg 3 is ifnumlistlenmyargs[2]=1relax Absentelsemyargs[2,2]fi%
                    }
                    begin{document}

                    mycommand{arg1, arg2}

                    and

                    mycommand{arg1, arg2-arg3}

                    end{document}


                    enter image description here







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered 4 hours ago









                    Steven B. SegletesSteven B. Segletes

                    154k9198405




                    154k9198405























                        0














                        Some crocheting/knitting by hand (or whatever)... ;-)



                        I suppose this question came into being while you thought about your other question: Custom cite command. In that question you ask for a customized cite-command with the same syntax.



                        Be that as it may.



                        The challenge is doing it in a way where desired space-removal but no undesired removal of argument-braces takes place.



                        E.g., with things like mycommand{{arg_1}a, arg_2} the braces surrounding arg_1 should probably be preserved while with things like mycommand{{arg_1} , arg_2} they should probably be removed.

                        Also probably only space-tokens surrounding the entire arguments/surrounding those commas and those dashes that are taken for argument-separators should get removed.



                        Below is an approach where comma takes precedence over the dash where and the leftmost unhidden comma delimits the first argument from the remaining arguments and where the first unhidden dash following that comma delimits the second from the third argument.

                        Exactly one level of braces will be removed in case after removing surrounding spaces it surrounds an entire argument as in that case it is assumed that the braces serve for hiding commas/dashes/spaces/emptiness. In all other cases braces will be preserved.



                        E.g., with things like mycommand{ {arg_1} , {arg_2-2} - arg_3} you should get:

                        First argument: arg_1

                        Second argument: arg_2-2

                        Third argument: arg_3.



                        E.g., with things like mycommand{ {{arg 1,a} - arg 1b} , {arg 2-2} , 2 - arg 3a - arg 3b} you should get:

                        First argument (left from the first unhidden comma, surrounding spaces and outermost brace-level that surrounds the entire argument removed): {arg 1,a} - arg 1b

                        Second argument (right from the first unhidden comma, left from the first unhidden dash following the comma): {arg 2-2} , 2

                        Third argument (the remainder, right from the first unhidden dash following the comma): arg 3a - arg 3b.



                        E.g., with things like mycommand{{arg 1}, {arg 2-2} , 2 - arg 3a - arg 3b} you should get:

                        First argument (left from the first unhidden comma): arg 1

                        Second argument (right from the first unhidden comma, left from the first unhidden dash following the comma): {arg 2-2} , 2

                        Third argument (the remainder, right from the first unhidden dash following the comma): arg 3a - arg 3b.



                        You may not be familiar to methods for removing space-tokens that surround arguments, thus a quote from the manual of my deprecated labelcas-package:




                        A note about removing leading and trailing spaces



                        The matter of removing trailing spaces from an (almost) arbitrary
                        token-sequence is elaborated in detail by Michael Downes, 'Around the
                        Bend #15, answers', a summary of internet-discussion which took place
                        under his guidance primarily at the INFO-TEX list, but also at
                        comp.text.tex (usenet) and via private email; December 1993. Online
                        archived at http://www.tug.org/tex-archive/info/arobend/answer.015.



                        One basic approach suggested therein is using TeX's scanning of
                        delimited parameters in order to detect and discard the ending space
                        of an argument:




                        ... scan for a pair of tokens: a space-token and some well-chosen
                        bizarre token that can't possibly occur in the scanned text. If you
                        put the bizarre token at the end of the text, and if the text has a
                        trailing space, then TeX's delimiter matching will match at that point
                        and not before, because the earlier occurrences of space don’t have
                        the requisite other member of the pair.



                        Next consider the possibility that the trailing space is absent: TeX
                        will keep on scanning ahead for the pair
                        &langle;space&rangle;&langle;bizarre&rangle;
                        until either it finds them or it decides to give up and signal a
                        'Runaway argument?' error. So you must add a stop pair to catch the
                        runaway argument possibility: a second instance of the bizarre
                        token, preceded by a space. If TeX doesn't find a match at the
                        first bizarre token, it will at the second one.




                        (Look up the macros KV@@sp@def, KV@@sp@b, KV@@sp@c and KV@@sp@d in
                        David Carlisle’s keyval-package for an interesting variation on this
                        approach.)



                        When scanning for parameters
                        ##1&langle;space&rangle;&langle;bizarre&rangle;##2&langle;B1&rangle;

                        the sequence:
                        &langle;stuff where to remove trail-space&rangle;&langle;bizarre&rangle;&langle;space&rangle;&langle;bizarre&rangle;&langle;B1&rangle;

                        , you can fork two cases:




                        1. Trailing-space:
                          ##1 = &langle;stuff where to remove trail-space&rangle;, but with removed space. (And possibly one
                          removed brace-level!)
                          ##2 = &langle;space&rangle;&langle;bizarre&rangle;.


                        2. No trailing-space:
                          ##1 = &langle;stuff where to remove trail-space&rangle;&langle;bizarre&rangle;.
                          ##2 is empty.



                        So forking can be implemented depending on the emptiness of ##2.

                        You can easily prevent the brace-removal in the first case, e.g., by adding (and
                        later removing) something (e.g., a space-token) in front of the
                        &langle;stuff where to remove trail-space&rangle;.



                        You can choose &langle;B1&rangle;=&langle;bizarre&rangle;&langle;space&rangle;.




                        The link in the quote is out of date.

                        Nowadays you can find the entire "Around the bend" -collection at http://mirrors.ctan.org/info/challenges/AroBend/AroundTheBend.pdf.



                        As you see, the methods for space-removal exhibited in the quote above do rely on some sequence of tokens that must not occur within the argument.



                        In the example below it is relied on the token UD@seldom not occurring within arguments.

                        In other words: You must not use the token UD@seldom within your arguments.



                        If you don't like that restriction, then I can deliver space-removal-routines which do without such restrictions, but they are slower and they form another huge load of code.



                        documentclass{article}

                        makeatletter
                        %%-----------------------------------------------------------------------------
                        %% Paraphernalia ;-) :
                        %%.............................................................................
                        newcommandUD@firstoftwo[2]{#1}%
                        newcommandUD@secondoftwo[2]{#2}%
                        newcommandUD@exchange[2]{#2#1}%
                        newcommandUD@removespace{}UD@firstoftwo{defUD@removespace}{} {}%
                        %%-----------------------------------------------------------------------------
                        %% Check whether argument is empty:
                        %%.............................................................................
                        %% UD@CheckWhetherNull{<Argument which is to be checked>}%
                        %% {<Tokens to be delivered in case that argument
                        %% which is to be checked is empty>}%
                        %% {<Tokens to be delivered in case that argument
                        %% which is to be checked is not empty>}%
                        %% The gist of this macro comes from Robert R. Schneck's ifempty-macro:
                        %% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
                        %%.............................................................................
                        newcommandUD@CheckWhetherNull[1]{%
                        romannumeral0expandafterUD@secondoftwostring{expandafter
                        UD@secondoftwoexpandafter{expandafter{string#1}expandafter
                        UD@secondoftwostring}expandafterUD@firstoftwoexpandafter{expandafter
                        UD@secondoftwostring}expandafterexpandafterUD@firstoftwo{ }{}%
                        UD@secondoftwo}{expandafterexpandafterUD@firstoftwo{ }{}UD@firstoftwo}%
                        }%
                        %%-----------------------------------------------------------------------------
                        %% Check whether argument's first token is a catcode-1-character
                        %%.............................................................................
                        %% UD@CheckWhetherBrace{<Argument which is to be checked>}%
                        %% {<Tokens to be delivered in case that argument
                        %% which is to be checked has leading
                        %% catcode-1-token>}%
                        %% {<Tokens to be delivered in case that argument
                        %% which is to be checked has no leading
                        %% catcode-1-token>}%
                        newcommandUD@CheckWhetherBrace[1]{%
                        romannumeral0expandafterUD@secondoftwoexpandafter{expandafter{%
                        string#1.}expandafterUD@firstoftwoexpandafter{expandafter
                        UD@secondoftwostring}expandafterexpandafterUD@firstoftwo{ }{}%
                        UD@firstoftwo}{expandafterexpandafterUD@firstoftwo{ }{}UD@secondoftwo}%
                        }%
                        %%-----------------------------------------------------------------------------
                        %% Check whether brace-balanced argument starts with a space-token
                        %%.............................................................................
                        %% UD@CheckWhetherLeadingSpace{<Argument which is to be checked>}%
                        %% {<Tokens to be delivered in case <argument
                        %% which is to be checked>'s 1st token is a
                        %% space-token>}%
                        %% {<Tokens to be delivered in case <argument
                        %% which is to be checked>'s 1st token is not
                        %% a space-token>}%
                        newcommandUD@CheckWhetherLeadingSpace[1]{%
                        romannumeral0UD@CheckWhetherNull{#1}%
                        {expandafterexpandafterUD@firstoftwo{ }{}UD@secondoftwo}%
                        {expandafterUD@secondoftwostring{UD@CheckWhetherLeadingSpaceB.#1 }{}}%
                        }%
                        newcommandUD@CheckWhetherLeadingSpaceB{}%
                        longdefUD@CheckWhetherLeadingSpaceB#1 {%
                        expandafterUD@CheckWhetherNullexpandafter{UD@secondoftwo#1{}}%
                        {UD@exchange{UD@firstoftwo}}{UD@exchange{UD@secondoftwo}}%
                        {UD@exchange{ }{expandafterexpandafterexpandafterexpandafter
                        expandafterexpandafterexpandafter}expandafterexpandafter
                        expandafter}expandafterUD@secondoftwoexpandafter{string}%
                        }%
                        %%-----------------------------------------------------------------------------
                        %% Extract first inner undelimited argument:
                        %%.............................................................................
                        %% UD@ExtractFirstArg{ABCDE} yields {A}
                        %%
                        %% UD@ExtractFirstArg{{AB}CDE} yields {AB}
                        %%.............................................................................
                        newcommandUD@RemoveTillUD@SelDOm{}%
                        longdefUD@RemoveTillUD@SelDOm#1#2UD@SelDOm{{#1}}%
                        newcommandUD@ExtractFirstArg[1]{%
                        romannumeral0%
                        UD@ExtractFirstArgLoop{#1UD@SelDOm}%
                        }%
                        newcommandUD@ExtractFirstArgLoop[1]{%
                        expandafterUD@CheckWhetherNullexpandafter{UD@firstoftwo{}#1}%
                        { #1}%
                        {expandafterUD@ExtractFirstArgLoopexpandafter{UD@RemoveTillUD@SelDOm#1}}%
                        }%
                        %%-----------------------------------------------------------------------------
                        %% UD@RemoveSpaces{<argument>} removes leading and trailing spaces from
                        %% <argument>.
                        %% !!!! <argument> must not contain the token UD@seldom !!!!
                        %%.............................................................................
                        begingroup
                        newcommandUD@RemoveSpacesAndOneLevelOfBraces[1]{%
                        endgroup
                        newcommandUD@RemoveSpacesAndOneLevelOfBraces[1]{%
                        romannumeral0%
                        UD@trimtrailspaceloop#1##1UD@seldom#1UD@seldomUD@seldom#1{##1}%
                        }%
                        newcommandUD@trimtrailspaceloop{}%
                        longdefUD@trimtrailspaceloop##1#1UD@seldom##2UD@seldom#1##3{%
                        UD@CheckWhetherNull{##2}{%
                        UD@trimleadspaceloop{##3}%
                        }{%
                        UD@trimtrailspaceloop##1UD@seldom#1UD@seldomUD@seldom#1{##1}%
                        }%
                        }%
                        }%
                        UD@RemoveSpacesAndOneLevelOfBraces{ }%
                        newcommandUD@trimleadspaceloop[1]{%
                        UD@CheckWhetherLeadingSpace{#1}{%
                        expandafterUD@trimleadspaceloopexpandafter{UD@removespace#1}%
                        }{%
                        UD@CheckWhetherNull{#1}{ }{%
                        expandafterUD@CheckWhetherNullexpandafter{UD@firstoftwo{}#1}{%
                        UD@exchange{ }{expandafter}UD@secondoftwo{}#1%
                        }{ #1}%
                        }%
                        }%
                        }%
                        %%-----------------------------------------------------------------------------
                        %% Check whether argument contains no comma which is not nested
                        %% in braces:
                        %%.............................................................................
                        %% UD@CheckWhetherNoComma{<Argument which is to be checked>}%
                        %% {<Tokens to be delivered in case that argument
                        %% contains no comma>}%
                        %% {<Tokens to be delivered in case that argument
                        %% contains comma>}%
                        %%
                        newcommandUD@GobbleToComma{}longdefUD@GobbleToComma#1,{}%
                        newcommandUD@CheckWhetherNoComma[1]{%
                        expandafterUD@CheckWhetherNullexpandafter{UD@GobbleToComma#1,}%
                        }%
                        %%-----------------------------------------------------------------------------
                        %% Check whether argument contains no dash which is not nested
                        %% in braces:
                        %%.............................................................................
                        %% UD@CheckWhetherNoDash{<Argument which is to be checked>}%
                        %% {<Tokens to be delivered in case that argument
                        %% contains no dash>}%
                        %% {<Tokens to be delivered in case that argument
                        %% contains dash>}%
                        %%
                        newcommandUD@GobbleToDash{}longdefUD@GobbleToDash#1-{}%
                        newcommandUD@CheckWhetherNoDash[1]{%
                        expandafterUD@CheckWhetherNullexpandafter{UD@GobbleToDash#1-}%
                        }%
                        %%-----------------------------------------------------------------------------
                        %% Take a comma-delimited/dash-delimited argument where a space was
                        %% prepended for preventing brace-removal and wrap it in curly braces.
                        %%.............................................................................
                        newcommandUD@SplitCommaArg{}%
                        longdefUD@SplitCommaArg#1,{%
                        romannumeral0UD@exchange{ }{expandafter}expandafter{UD@removespace#1}%
                        }%
                        newcommandUD@SplitDashArg{}%
                        longdefUD@SplitDashArg#1-{%
                        romannumeral0UD@exchange{ }{expandafter}expandafter{UD@removespace#1}%
                        }%
                        %%-----------------------------------------------------------------------------
                        %% Now we have the tools for creating the desired mycommand-macro:
                        %%.............................................................................
                        newcommandmycommand[1]{%
                        romannumeral0%
                        UD@CheckWhetherNoComma{#1}{%
                        expandafterUD@exchangeexpandafter{%
                        expandafter{%
                        romannumeral0UD@exchange{ }{expandafterexpandafterexpandafter}%
                        UD@RemoveSpacesAndOneLevelOfBraces{#1}%
                        }%
                        }{mycommand@oneargument}%
                        }{%
                        expandafterUD@exchangeexpandafter{expandafter%
                        {%
                        romannumeral0%
                        UD@exchange{ }{expandafterexpandafterexpandafter}%
                        expandafterUD@firstoftwoexpandafter{expandafter}%
                        romannumeral0%
                        UD@exchange{ }{%
                        expandafterexpandafterexpandafterexpandafter
                        expandafterexpandafterexpandafter
                        }%
                        expandafterUD@SplitCommaArg
                        UD@firstoftwo{ }{}#1}%
                        }{%
                        expandafter@mycommand
                        romannumeral0%
                        UD@exchange{ }{%
                        expandafterexpandafterexpandafterexpandafter
                        expandafterexpandafterexpandafter
                        }%
                        expandafterUD@ExtractFirstArgexpandafter{%
                        romannumeral0%
                        UD@exchange{ }{%
                        expandafterexpandafterexpandafterexpandafter
                        expandafterexpandafterexpandafter
                        }%
                        expandafterUD@SplitCommaArg
                        UD@firstoftwo{ }{}#1}%
                        }%
                        }%
                        }%
                        newcommand@mycommand[2]{%
                        UD@CheckWhetherNoDash{#2}{%
                        expandafterUD@exchangeexpandafter{expandafter
                        {%
                        romannumeral0%
                        UD@exchange{ }{expandafterexpandafterexpandafter}%
                        UD@RemoveSpacesAndOneLevelOfBraces{#2}%
                        }%
                        }{%
                        expandafterUD@exchangeexpandafter{%
                        expandafter{%
                        romannumeral0%
                        UD@exchange{ }{expandafterexpandafterexpandafter}%
                        UD@RemoveSpacesAndOneLevelOfBraces{#1}%
                        }%
                        }{mycommand@twoarguments}%
                        }%
                        }{%
                        expandafterUD@exchangeexpandafter{expandafter%
                        {%
                        romannumeral0%
                        UD@exchange{ }{expandafterexpandafterexpandafter}%
                        expandafterUD@firstoftwoexpandafter{expandafter}%
                        romannumeral0%
                        UD@exchange{ }{%
                        expandafterexpandafterexpandafterexpandafter
                        expandafterexpandafterexpandafter
                        }%
                        expandafterUD@SplitDashArg
                        UD@firstoftwo{ }{}#2}%
                        }{%
                        expandafter@@mycommand
                        romannumeral0%
                        UD@exchange{ }{%
                        expandafterexpandafterexpandafterexpandafter
                        expandafterexpandafterexpandafter
                        }%
                        expandafterUD@ExtractFirstArgexpandafter{%
                        romannumeral0%
                        UD@exchange{ }{%
                        expandafterexpandafterexpandafterexpandafter
                        expandafterexpandafterexpandafter
                        }%
                        expandafterUD@SplitDashArg
                        UD@firstoftwo{ }{}#2}%
                        }%
                        {#1}%
                        }%
                        }%
                        newcommand@@mycommand[3]{%
                        expandafterUD@exchangeexpandafter{%
                        expandafter{%
                        romannumeral0%
                        UD@exchange{ }{expandafterexpandafterexpandafter}%
                        UD@RemoveSpacesAndOneLevelOfBraces{#2}%
                        }%
                        }{%
                        expandafterUD@exchangeexpandafter{%
                        expandafter{%
                        romannumeral0%
                        UD@exchange{ }{expandafterexpandafterexpandafter}%
                        UD@RemoveSpacesAndOneLevelOfBraces{#1}%
                        }%
                        }{%
                        expandafterUD@exchangeexpandafter{%
                        expandafter{%
                        romannumeral0%
                        UD@exchange{ }{expandafterexpandafterexpandafter}%
                        UD@RemoveSpacesAndOneLevelOfBraces{#3}%
                        }%
                        }{mycommand@threearguments}%
                        }%
                        }%
                        }%
                        newcommandmycommand@oneargument[1]{%
                        UD@secondoftwo{%
                        %We need a space to stop romannumeral-expansion.
                        }{ }%
                        There is no comma or only empty args after the comma, thus:\
                        argument 1 = printmeaning{#1}%
                        }%
                        newcommandmycommand@twoarguments[2]{%
                        UD@CheckWhetherNull{#2}{%
                        mycommand@oneargument{#1}%
                        }{%
                        UD@secondoftwo{%
                        %We need a space to stop romannumeral-expansion.
                        }{ }%
                        There is a comma but either no dash or only one non-empty argument near
                        the dash, thus:\
                        argument 1 = printmeaning{#1}\
                        argument 2 = printmeaning{#2}%
                        }%
                        }%
                        newcommandmycommand@threearguments[3]{%
                        UD@CheckWhetherNull{#2}{%
                        UD@CheckWhetherNull{#3}{%
                        mycommand@oneargument{#1}%
                        }{%x
                        mycommand@twoarguments{#1}{#3}%
                        }%
                        }{%
                        UD@CheckWhetherNull{#3}{%
                        mycommand@twoarguments{#1}{#2}%
                        }{%
                        UD@secondoftwo{%
                        %We need a space to stop romannumeral-expansion.
                        }{ }%
                        There is a comma and a dash, thus:\
                        argument 1 = printmeaning{#1}\
                        argument 2 = printmeaning{#2}\
                        argument 3 = printmeaning{#3}%
                        }%
                        }%
                        }%

                        newcommandprintmeaning[1]{%
                        defUD@tempa{#1}%
                        fbox{texttt{expandafterstrip@prefixmeaningUD@tempa}}%
                        }%

                        makeatother

                        parindent=0ex
                        parskip=smallskipamount

                        begin{document}

                        verb|mycommand{ arg 1 }|:\
                        mycommand{ arg 1 }\
                        nullhrulefillnull

                        verb|mycommand{ arg 1 , }|:\
                        mycommand{ arg 1 , }\
                        nullhrulefillnull

                        verb|mycommand{ arg 1 , - }|:\
                        mycommand{ arg 1 , - }\
                        nullhrulefillnull

                        verb|mycommand{ arg 1 , arg 2 - }|:\
                        mycommand{ arg 1 , arg 2 - }\
                        nullhrulefillnull

                        verb|mycommand{ arg 1 , arg 2 - arg 3}|:\
                        mycommand{ arg 1 , arg 2 - arg 3}\
                        nullhrulefillnull

                        verb|mycommand{ arg 1 , - arg 3}|:\
                        mycommand{ arg 1 , - arg 3}\
                        nullhrulefillnull

                        verb|mycommand{ {arg 1a} - arg 1b , {arg 2-2} , 2 - arg 3a - arg 3b}|:\
                        mycommand{ {arg 1a} - arg 1b , {arg 2-2} , 2 - arg 3a - arg 3b}\
                        nullhrulefillnull

                        verb|mycommand{ {arg 1} , {arg 2-2} , 2 - arg 3a - arg 3b}|:\
                        mycommand{ {arg 1} , {arg 2-2} , 2 - arg 3a - arg 3b}

                        end{document}


                        enter image description here






                        share|improve this answer






























                          0














                          Some crocheting/knitting by hand (or whatever)... ;-)



                          I suppose this question came into being while you thought about your other question: Custom cite command. In that question you ask for a customized cite-command with the same syntax.



                          Be that as it may.



                          The challenge is doing it in a way where desired space-removal but no undesired removal of argument-braces takes place.



                          E.g., with things like mycommand{{arg_1}a, arg_2} the braces surrounding arg_1 should probably be preserved while with things like mycommand{{arg_1} , arg_2} they should probably be removed.

                          Also probably only space-tokens surrounding the entire arguments/surrounding those commas and those dashes that are taken for argument-separators should get removed.



                          Below is an approach where comma takes precedence over the dash where and the leftmost unhidden comma delimits the first argument from the remaining arguments and where the first unhidden dash following that comma delimits the second from the third argument.

                          Exactly one level of braces will be removed in case after removing surrounding spaces it surrounds an entire argument as in that case it is assumed that the braces serve for hiding commas/dashes/spaces/emptiness. In all other cases braces will be preserved.



                          E.g., with things like mycommand{ {arg_1} , {arg_2-2} - arg_3} you should get:

                          First argument: arg_1

                          Second argument: arg_2-2

                          Third argument: arg_3.



                          E.g., with things like mycommand{ {{arg 1,a} - arg 1b} , {arg 2-2} , 2 - arg 3a - arg 3b} you should get:

                          First argument (left from the first unhidden comma, surrounding spaces and outermost brace-level that surrounds the entire argument removed): {arg 1,a} - arg 1b

                          Second argument (right from the first unhidden comma, left from the first unhidden dash following the comma): {arg 2-2} , 2

                          Third argument (the remainder, right from the first unhidden dash following the comma): arg 3a - arg 3b.



                          E.g., with things like mycommand{{arg 1}, {arg 2-2} , 2 - arg 3a - arg 3b} you should get:

                          First argument (left from the first unhidden comma): arg 1

                          Second argument (right from the first unhidden comma, left from the first unhidden dash following the comma): {arg 2-2} , 2

                          Third argument (the remainder, right from the first unhidden dash following the comma): arg 3a - arg 3b.



                          You may not be familiar to methods for removing space-tokens that surround arguments, thus a quote from the manual of my deprecated labelcas-package:




                          A note about removing leading and trailing spaces



                          The matter of removing trailing spaces from an (almost) arbitrary
                          token-sequence is elaborated in detail by Michael Downes, 'Around the
                          Bend #15, answers', a summary of internet-discussion which took place
                          under his guidance primarily at the INFO-TEX list, but also at
                          comp.text.tex (usenet) and via private email; December 1993. Online
                          archived at http://www.tug.org/tex-archive/info/arobend/answer.015.



                          One basic approach suggested therein is using TeX's scanning of
                          delimited parameters in order to detect and discard the ending space
                          of an argument:




                          ... scan for a pair of tokens: a space-token and some well-chosen
                          bizarre token that can't possibly occur in the scanned text. If you
                          put the bizarre token at the end of the text, and if the text has a
                          trailing space, then TeX's delimiter matching will match at that point
                          and not before, because the earlier occurrences of space don’t have
                          the requisite other member of the pair.



                          Next consider the possibility that the trailing space is absent: TeX
                          will keep on scanning ahead for the pair
                          &langle;space&rangle;&langle;bizarre&rangle;
                          until either it finds them or it decides to give up and signal a
                          'Runaway argument?' error. So you must add a stop pair to catch the
                          runaway argument possibility: a second instance of the bizarre
                          token, preceded by a space. If TeX doesn't find a match at the
                          first bizarre token, it will at the second one.




                          (Look up the macros KV@@sp@def, KV@@sp@b, KV@@sp@c and KV@@sp@d in
                          David Carlisle’s keyval-package for an interesting variation on this
                          approach.)



                          When scanning for parameters
                          ##1&langle;space&rangle;&langle;bizarre&rangle;##2&langle;B1&rangle;

                          the sequence:
                          &langle;stuff where to remove trail-space&rangle;&langle;bizarre&rangle;&langle;space&rangle;&langle;bizarre&rangle;&langle;B1&rangle;

                          , you can fork two cases:




                          1. Trailing-space:
                            ##1 = &langle;stuff where to remove trail-space&rangle;, but with removed space. (And possibly one
                            removed brace-level!)
                            ##2 = &langle;space&rangle;&langle;bizarre&rangle;.


                          2. No trailing-space:
                            ##1 = &langle;stuff where to remove trail-space&rangle;&langle;bizarre&rangle;.
                            ##2 is empty.



                          So forking can be implemented depending on the emptiness of ##2.

                          You can easily prevent the brace-removal in the first case, e.g., by adding (and
                          later removing) something (e.g., a space-token) in front of the
                          &langle;stuff where to remove trail-space&rangle;.



                          You can choose &langle;B1&rangle;=&langle;bizarre&rangle;&langle;space&rangle;.




                          The link in the quote is out of date.

                          Nowadays you can find the entire "Around the bend" -collection at http://mirrors.ctan.org/info/challenges/AroBend/AroundTheBend.pdf.



                          As you see, the methods for space-removal exhibited in the quote above do rely on some sequence of tokens that must not occur within the argument.



                          In the example below it is relied on the token UD@seldom not occurring within arguments.

                          In other words: You must not use the token UD@seldom within your arguments.



                          If you don't like that restriction, then I can deliver space-removal-routines which do without such restrictions, but they are slower and they form another huge load of code.



                          documentclass{article}

                          makeatletter
                          %%-----------------------------------------------------------------------------
                          %% Paraphernalia ;-) :
                          %%.............................................................................
                          newcommandUD@firstoftwo[2]{#1}%
                          newcommandUD@secondoftwo[2]{#2}%
                          newcommandUD@exchange[2]{#2#1}%
                          newcommandUD@removespace{}UD@firstoftwo{defUD@removespace}{} {}%
                          %%-----------------------------------------------------------------------------
                          %% Check whether argument is empty:
                          %%.............................................................................
                          %% UD@CheckWhetherNull{<Argument which is to be checked>}%
                          %% {<Tokens to be delivered in case that argument
                          %% which is to be checked is empty>}%
                          %% {<Tokens to be delivered in case that argument
                          %% which is to be checked is not empty>}%
                          %% The gist of this macro comes from Robert R. Schneck's ifempty-macro:
                          %% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
                          %%.............................................................................
                          newcommandUD@CheckWhetherNull[1]{%
                          romannumeral0expandafterUD@secondoftwostring{expandafter
                          UD@secondoftwoexpandafter{expandafter{string#1}expandafter
                          UD@secondoftwostring}expandafterUD@firstoftwoexpandafter{expandafter
                          UD@secondoftwostring}expandafterexpandafterUD@firstoftwo{ }{}%
                          UD@secondoftwo}{expandafterexpandafterUD@firstoftwo{ }{}UD@firstoftwo}%
                          }%
                          %%-----------------------------------------------------------------------------
                          %% Check whether argument's first token is a catcode-1-character
                          %%.............................................................................
                          %% UD@CheckWhetherBrace{<Argument which is to be checked>}%
                          %% {<Tokens to be delivered in case that argument
                          %% which is to be checked has leading
                          %% catcode-1-token>}%
                          %% {<Tokens to be delivered in case that argument
                          %% which is to be checked has no leading
                          %% catcode-1-token>}%
                          newcommandUD@CheckWhetherBrace[1]{%
                          romannumeral0expandafterUD@secondoftwoexpandafter{expandafter{%
                          string#1.}expandafterUD@firstoftwoexpandafter{expandafter
                          UD@secondoftwostring}expandafterexpandafterUD@firstoftwo{ }{}%
                          UD@firstoftwo}{expandafterexpandafterUD@firstoftwo{ }{}UD@secondoftwo}%
                          }%
                          %%-----------------------------------------------------------------------------
                          %% Check whether brace-balanced argument starts with a space-token
                          %%.............................................................................
                          %% UD@CheckWhetherLeadingSpace{<Argument which is to be checked>}%
                          %% {<Tokens to be delivered in case <argument
                          %% which is to be checked>'s 1st token is a
                          %% space-token>}%
                          %% {<Tokens to be delivered in case <argument
                          %% which is to be checked>'s 1st token is not
                          %% a space-token>}%
                          newcommandUD@CheckWhetherLeadingSpace[1]{%
                          romannumeral0UD@CheckWhetherNull{#1}%
                          {expandafterexpandafterUD@firstoftwo{ }{}UD@secondoftwo}%
                          {expandafterUD@secondoftwostring{UD@CheckWhetherLeadingSpaceB.#1 }{}}%
                          }%
                          newcommandUD@CheckWhetherLeadingSpaceB{}%
                          longdefUD@CheckWhetherLeadingSpaceB#1 {%
                          expandafterUD@CheckWhetherNullexpandafter{UD@secondoftwo#1{}}%
                          {UD@exchange{UD@firstoftwo}}{UD@exchange{UD@secondoftwo}}%
                          {UD@exchange{ }{expandafterexpandafterexpandafterexpandafter
                          expandafterexpandafterexpandafter}expandafterexpandafter
                          expandafter}expandafterUD@secondoftwoexpandafter{string}%
                          }%
                          %%-----------------------------------------------------------------------------
                          %% Extract first inner undelimited argument:
                          %%.............................................................................
                          %% UD@ExtractFirstArg{ABCDE} yields {A}
                          %%
                          %% UD@ExtractFirstArg{{AB}CDE} yields {AB}
                          %%.............................................................................
                          newcommandUD@RemoveTillUD@SelDOm{}%
                          longdefUD@RemoveTillUD@SelDOm#1#2UD@SelDOm{{#1}}%
                          newcommandUD@ExtractFirstArg[1]{%
                          romannumeral0%
                          UD@ExtractFirstArgLoop{#1UD@SelDOm}%
                          }%
                          newcommandUD@ExtractFirstArgLoop[1]{%
                          expandafterUD@CheckWhetherNullexpandafter{UD@firstoftwo{}#1}%
                          { #1}%
                          {expandafterUD@ExtractFirstArgLoopexpandafter{UD@RemoveTillUD@SelDOm#1}}%
                          }%
                          %%-----------------------------------------------------------------------------
                          %% UD@RemoveSpaces{<argument>} removes leading and trailing spaces from
                          %% <argument>.
                          %% !!!! <argument> must not contain the token UD@seldom !!!!
                          %%.............................................................................
                          begingroup
                          newcommandUD@RemoveSpacesAndOneLevelOfBraces[1]{%
                          endgroup
                          newcommandUD@RemoveSpacesAndOneLevelOfBraces[1]{%
                          romannumeral0%
                          UD@trimtrailspaceloop#1##1UD@seldom#1UD@seldomUD@seldom#1{##1}%
                          }%
                          newcommandUD@trimtrailspaceloop{}%
                          longdefUD@trimtrailspaceloop##1#1UD@seldom##2UD@seldom#1##3{%
                          UD@CheckWhetherNull{##2}{%
                          UD@trimleadspaceloop{##3}%
                          }{%
                          UD@trimtrailspaceloop##1UD@seldom#1UD@seldomUD@seldom#1{##1}%
                          }%
                          }%
                          }%
                          UD@RemoveSpacesAndOneLevelOfBraces{ }%
                          newcommandUD@trimleadspaceloop[1]{%
                          UD@CheckWhetherLeadingSpace{#1}{%
                          expandafterUD@trimleadspaceloopexpandafter{UD@removespace#1}%
                          }{%
                          UD@CheckWhetherNull{#1}{ }{%
                          expandafterUD@CheckWhetherNullexpandafter{UD@firstoftwo{}#1}{%
                          UD@exchange{ }{expandafter}UD@secondoftwo{}#1%
                          }{ #1}%
                          }%
                          }%
                          }%
                          %%-----------------------------------------------------------------------------
                          %% Check whether argument contains no comma which is not nested
                          %% in braces:
                          %%.............................................................................
                          %% UD@CheckWhetherNoComma{<Argument which is to be checked>}%
                          %% {<Tokens to be delivered in case that argument
                          %% contains no comma>}%
                          %% {<Tokens to be delivered in case that argument
                          %% contains comma>}%
                          %%
                          newcommandUD@GobbleToComma{}longdefUD@GobbleToComma#1,{}%
                          newcommandUD@CheckWhetherNoComma[1]{%
                          expandafterUD@CheckWhetherNullexpandafter{UD@GobbleToComma#1,}%
                          }%
                          %%-----------------------------------------------------------------------------
                          %% Check whether argument contains no dash which is not nested
                          %% in braces:
                          %%.............................................................................
                          %% UD@CheckWhetherNoDash{<Argument which is to be checked>}%
                          %% {<Tokens to be delivered in case that argument
                          %% contains no dash>}%
                          %% {<Tokens to be delivered in case that argument
                          %% contains dash>}%
                          %%
                          newcommandUD@GobbleToDash{}longdefUD@GobbleToDash#1-{}%
                          newcommandUD@CheckWhetherNoDash[1]{%
                          expandafterUD@CheckWhetherNullexpandafter{UD@GobbleToDash#1-}%
                          }%
                          %%-----------------------------------------------------------------------------
                          %% Take a comma-delimited/dash-delimited argument where a space was
                          %% prepended for preventing brace-removal and wrap it in curly braces.
                          %%.............................................................................
                          newcommandUD@SplitCommaArg{}%
                          longdefUD@SplitCommaArg#1,{%
                          romannumeral0UD@exchange{ }{expandafter}expandafter{UD@removespace#1}%
                          }%
                          newcommandUD@SplitDashArg{}%
                          longdefUD@SplitDashArg#1-{%
                          romannumeral0UD@exchange{ }{expandafter}expandafter{UD@removespace#1}%
                          }%
                          %%-----------------------------------------------------------------------------
                          %% Now we have the tools for creating the desired mycommand-macro:
                          %%.............................................................................
                          newcommandmycommand[1]{%
                          romannumeral0%
                          UD@CheckWhetherNoComma{#1}{%
                          expandafterUD@exchangeexpandafter{%
                          expandafter{%
                          romannumeral0UD@exchange{ }{expandafterexpandafterexpandafter}%
                          UD@RemoveSpacesAndOneLevelOfBraces{#1}%
                          }%
                          }{mycommand@oneargument}%
                          }{%
                          expandafterUD@exchangeexpandafter{expandafter%
                          {%
                          romannumeral0%
                          UD@exchange{ }{expandafterexpandafterexpandafter}%
                          expandafterUD@firstoftwoexpandafter{expandafter}%
                          romannumeral0%
                          UD@exchange{ }{%
                          expandafterexpandafterexpandafterexpandafter
                          expandafterexpandafterexpandafter
                          }%
                          expandafterUD@SplitCommaArg
                          UD@firstoftwo{ }{}#1}%
                          }{%
                          expandafter@mycommand
                          romannumeral0%
                          UD@exchange{ }{%
                          expandafterexpandafterexpandafterexpandafter
                          expandafterexpandafterexpandafter
                          }%
                          expandafterUD@ExtractFirstArgexpandafter{%
                          romannumeral0%
                          UD@exchange{ }{%
                          expandafterexpandafterexpandafterexpandafter
                          expandafterexpandafterexpandafter
                          }%
                          expandafterUD@SplitCommaArg
                          UD@firstoftwo{ }{}#1}%
                          }%
                          }%
                          }%
                          newcommand@mycommand[2]{%
                          UD@CheckWhetherNoDash{#2}{%
                          expandafterUD@exchangeexpandafter{expandafter
                          {%
                          romannumeral0%
                          UD@exchange{ }{expandafterexpandafterexpandafter}%
                          UD@RemoveSpacesAndOneLevelOfBraces{#2}%
                          }%
                          }{%
                          expandafterUD@exchangeexpandafter{%
                          expandafter{%
                          romannumeral0%
                          UD@exchange{ }{expandafterexpandafterexpandafter}%
                          UD@RemoveSpacesAndOneLevelOfBraces{#1}%
                          }%
                          }{mycommand@twoarguments}%
                          }%
                          }{%
                          expandafterUD@exchangeexpandafter{expandafter%
                          {%
                          romannumeral0%
                          UD@exchange{ }{expandafterexpandafterexpandafter}%
                          expandafterUD@firstoftwoexpandafter{expandafter}%
                          romannumeral0%
                          UD@exchange{ }{%
                          expandafterexpandafterexpandafterexpandafter
                          expandafterexpandafterexpandafter
                          }%
                          expandafterUD@SplitDashArg
                          UD@firstoftwo{ }{}#2}%
                          }{%
                          expandafter@@mycommand
                          romannumeral0%
                          UD@exchange{ }{%
                          expandafterexpandafterexpandafterexpandafter
                          expandafterexpandafterexpandafter
                          }%
                          expandafterUD@ExtractFirstArgexpandafter{%
                          romannumeral0%
                          UD@exchange{ }{%
                          expandafterexpandafterexpandafterexpandafter
                          expandafterexpandafterexpandafter
                          }%
                          expandafterUD@SplitDashArg
                          UD@firstoftwo{ }{}#2}%
                          }%
                          {#1}%
                          }%
                          }%
                          newcommand@@mycommand[3]{%
                          expandafterUD@exchangeexpandafter{%
                          expandafter{%
                          romannumeral0%
                          UD@exchange{ }{expandafterexpandafterexpandafter}%
                          UD@RemoveSpacesAndOneLevelOfBraces{#2}%
                          }%
                          }{%
                          expandafterUD@exchangeexpandafter{%
                          expandafter{%
                          romannumeral0%
                          UD@exchange{ }{expandafterexpandafterexpandafter}%
                          UD@RemoveSpacesAndOneLevelOfBraces{#1}%
                          }%
                          }{%
                          expandafterUD@exchangeexpandafter{%
                          expandafter{%
                          romannumeral0%
                          UD@exchange{ }{expandafterexpandafterexpandafter}%
                          UD@RemoveSpacesAndOneLevelOfBraces{#3}%
                          }%
                          }{mycommand@threearguments}%
                          }%
                          }%
                          }%
                          newcommandmycommand@oneargument[1]{%
                          UD@secondoftwo{%
                          %We need a space to stop romannumeral-expansion.
                          }{ }%
                          There is no comma or only empty args after the comma, thus:\
                          argument 1 = printmeaning{#1}%
                          }%
                          newcommandmycommand@twoarguments[2]{%
                          UD@CheckWhetherNull{#2}{%
                          mycommand@oneargument{#1}%
                          }{%
                          UD@secondoftwo{%
                          %We need a space to stop romannumeral-expansion.
                          }{ }%
                          There is a comma but either no dash or only one non-empty argument near
                          the dash, thus:\
                          argument 1 = printmeaning{#1}\
                          argument 2 = printmeaning{#2}%
                          }%
                          }%
                          newcommandmycommand@threearguments[3]{%
                          UD@CheckWhetherNull{#2}{%
                          UD@CheckWhetherNull{#3}{%
                          mycommand@oneargument{#1}%
                          }{%x
                          mycommand@twoarguments{#1}{#3}%
                          }%
                          }{%
                          UD@CheckWhetherNull{#3}{%
                          mycommand@twoarguments{#1}{#2}%
                          }{%
                          UD@secondoftwo{%
                          %We need a space to stop romannumeral-expansion.
                          }{ }%
                          There is a comma and a dash, thus:\
                          argument 1 = printmeaning{#1}\
                          argument 2 = printmeaning{#2}\
                          argument 3 = printmeaning{#3}%
                          }%
                          }%
                          }%

                          newcommandprintmeaning[1]{%
                          defUD@tempa{#1}%
                          fbox{texttt{expandafterstrip@prefixmeaningUD@tempa}}%
                          }%

                          makeatother

                          parindent=0ex
                          parskip=smallskipamount

                          begin{document}

                          verb|mycommand{ arg 1 }|:\
                          mycommand{ arg 1 }\
                          nullhrulefillnull

                          verb|mycommand{ arg 1 , }|:\
                          mycommand{ arg 1 , }\
                          nullhrulefillnull

                          verb|mycommand{ arg 1 , - }|:\
                          mycommand{ arg 1 , - }\
                          nullhrulefillnull

                          verb|mycommand{ arg 1 , arg 2 - }|:\
                          mycommand{ arg 1 , arg 2 - }\
                          nullhrulefillnull

                          verb|mycommand{ arg 1 , arg 2 - arg 3}|:\
                          mycommand{ arg 1 , arg 2 - arg 3}\
                          nullhrulefillnull

                          verb|mycommand{ arg 1 , - arg 3}|:\
                          mycommand{ arg 1 , - arg 3}\
                          nullhrulefillnull

                          verb|mycommand{ {arg 1a} - arg 1b , {arg 2-2} , 2 - arg 3a - arg 3b}|:\
                          mycommand{ {arg 1a} - arg 1b , {arg 2-2} , 2 - arg 3a - arg 3b}\
                          nullhrulefillnull

                          verb|mycommand{ {arg 1} , {arg 2-2} , 2 - arg 3a - arg 3b}|:\
                          mycommand{ {arg 1} , {arg 2-2} , 2 - arg 3a - arg 3b}

                          end{document}


                          enter image description here






                          share|improve this answer




























                            0












                            0








                            0







                            Some crocheting/knitting by hand (or whatever)... ;-)



                            I suppose this question came into being while you thought about your other question: Custom cite command. In that question you ask for a customized cite-command with the same syntax.



                            Be that as it may.



                            The challenge is doing it in a way where desired space-removal but no undesired removal of argument-braces takes place.



                            E.g., with things like mycommand{{arg_1}a, arg_2} the braces surrounding arg_1 should probably be preserved while with things like mycommand{{arg_1} , arg_2} they should probably be removed.

                            Also probably only space-tokens surrounding the entire arguments/surrounding those commas and those dashes that are taken for argument-separators should get removed.



                            Below is an approach where comma takes precedence over the dash where and the leftmost unhidden comma delimits the first argument from the remaining arguments and where the first unhidden dash following that comma delimits the second from the third argument.

                            Exactly one level of braces will be removed in case after removing surrounding spaces it surrounds an entire argument as in that case it is assumed that the braces serve for hiding commas/dashes/spaces/emptiness. In all other cases braces will be preserved.



                            E.g., with things like mycommand{ {arg_1} , {arg_2-2} - arg_3} you should get:

                            First argument: arg_1

                            Second argument: arg_2-2

                            Third argument: arg_3.



                            E.g., with things like mycommand{ {{arg 1,a} - arg 1b} , {arg 2-2} , 2 - arg 3a - arg 3b} you should get:

                            First argument (left from the first unhidden comma, surrounding spaces and outermost brace-level that surrounds the entire argument removed): {arg 1,a} - arg 1b

                            Second argument (right from the first unhidden comma, left from the first unhidden dash following the comma): {arg 2-2} , 2

                            Third argument (the remainder, right from the first unhidden dash following the comma): arg 3a - arg 3b.



                            E.g., with things like mycommand{{arg 1}, {arg 2-2} , 2 - arg 3a - arg 3b} you should get:

                            First argument (left from the first unhidden comma): arg 1

                            Second argument (right from the first unhidden comma, left from the first unhidden dash following the comma): {arg 2-2} , 2

                            Third argument (the remainder, right from the first unhidden dash following the comma): arg 3a - arg 3b.



                            You may not be familiar to methods for removing space-tokens that surround arguments, thus a quote from the manual of my deprecated labelcas-package:




                            A note about removing leading and trailing spaces



                            The matter of removing trailing spaces from an (almost) arbitrary
                            token-sequence is elaborated in detail by Michael Downes, 'Around the
                            Bend #15, answers', a summary of internet-discussion which took place
                            under his guidance primarily at the INFO-TEX list, but also at
                            comp.text.tex (usenet) and via private email; December 1993. Online
                            archived at http://www.tug.org/tex-archive/info/arobend/answer.015.



                            One basic approach suggested therein is using TeX's scanning of
                            delimited parameters in order to detect and discard the ending space
                            of an argument:




                            ... scan for a pair of tokens: a space-token and some well-chosen
                            bizarre token that can't possibly occur in the scanned text. If you
                            put the bizarre token at the end of the text, and if the text has a
                            trailing space, then TeX's delimiter matching will match at that point
                            and not before, because the earlier occurrences of space don’t have
                            the requisite other member of the pair.



                            Next consider the possibility that the trailing space is absent: TeX
                            will keep on scanning ahead for the pair
                            &langle;space&rangle;&langle;bizarre&rangle;
                            until either it finds them or it decides to give up and signal a
                            'Runaway argument?' error. So you must add a stop pair to catch the
                            runaway argument possibility: a second instance of the bizarre
                            token, preceded by a space. If TeX doesn't find a match at the
                            first bizarre token, it will at the second one.




                            (Look up the macros KV@@sp@def, KV@@sp@b, KV@@sp@c and KV@@sp@d in
                            David Carlisle’s keyval-package for an interesting variation on this
                            approach.)



                            When scanning for parameters
                            ##1&langle;space&rangle;&langle;bizarre&rangle;##2&langle;B1&rangle;

                            the sequence:
                            &langle;stuff where to remove trail-space&rangle;&langle;bizarre&rangle;&langle;space&rangle;&langle;bizarre&rangle;&langle;B1&rangle;

                            , you can fork two cases:




                            1. Trailing-space:
                              ##1 = &langle;stuff where to remove trail-space&rangle;, but with removed space. (And possibly one
                              removed brace-level!)
                              ##2 = &langle;space&rangle;&langle;bizarre&rangle;.


                            2. No trailing-space:
                              ##1 = &langle;stuff where to remove trail-space&rangle;&langle;bizarre&rangle;.
                              ##2 is empty.



                            So forking can be implemented depending on the emptiness of ##2.

                            You can easily prevent the brace-removal in the first case, e.g., by adding (and
                            later removing) something (e.g., a space-token) in front of the
                            &langle;stuff where to remove trail-space&rangle;.



                            You can choose &langle;B1&rangle;=&langle;bizarre&rangle;&langle;space&rangle;.




                            The link in the quote is out of date.

                            Nowadays you can find the entire "Around the bend" -collection at http://mirrors.ctan.org/info/challenges/AroBend/AroundTheBend.pdf.



                            As you see, the methods for space-removal exhibited in the quote above do rely on some sequence of tokens that must not occur within the argument.



                            In the example below it is relied on the token UD@seldom not occurring within arguments.

                            In other words: You must not use the token UD@seldom within your arguments.



                            If you don't like that restriction, then I can deliver space-removal-routines which do without such restrictions, but they are slower and they form another huge load of code.



                            documentclass{article}

                            makeatletter
                            %%-----------------------------------------------------------------------------
                            %% Paraphernalia ;-) :
                            %%.............................................................................
                            newcommandUD@firstoftwo[2]{#1}%
                            newcommandUD@secondoftwo[2]{#2}%
                            newcommandUD@exchange[2]{#2#1}%
                            newcommandUD@removespace{}UD@firstoftwo{defUD@removespace}{} {}%
                            %%-----------------------------------------------------------------------------
                            %% Check whether argument is empty:
                            %%.............................................................................
                            %% UD@CheckWhetherNull{<Argument which is to be checked>}%
                            %% {<Tokens to be delivered in case that argument
                            %% which is to be checked is empty>}%
                            %% {<Tokens to be delivered in case that argument
                            %% which is to be checked is not empty>}%
                            %% The gist of this macro comes from Robert R. Schneck's ifempty-macro:
                            %% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
                            %%.............................................................................
                            newcommandUD@CheckWhetherNull[1]{%
                            romannumeral0expandafterUD@secondoftwostring{expandafter
                            UD@secondoftwoexpandafter{expandafter{string#1}expandafter
                            UD@secondoftwostring}expandafterUD@firstoftwoexpandafter{expandafter
                            UD@secondoftwostring}expandafterexpandafterUD@firstoftwo{ }{}%
                            UD@secondoftwo}{expandafterexpandafterUD@firstoftwo{ }{}UD@firstoftwo}%
                            }%
                            %%-----------------------------------------------------------------------------
                            %% Check whether argument's first token is a catcode-1-character
                            %%.............................................................................
                            %% UD@CheckWhetherBrace{<Argument which is to be checked>}%
                            %% {<Tokens to be delivered in case that argument
                            %% which is to be checked has leading
                            %% catcode-1-token>}%
                            %% {<Tokens to be delivered in case that argument
                            %% which is to be checked has no leading
                            %% catcode-1-token>}%
                            newcommandUD@CheckWhetherBrace[1]{%
                            romannumeral0expandafterUD@secondoftwoexpandafter{expandafter{%
                            string#1.}expandafterUD@firstoftwoexpandafter{expandafter
                            UD@secondoftwostring}expandafterexpandafterUD@firstoftwo{ }{}%
                            UD@firstoftwo}{expandafterexpandafterUD@firstoftwo{ }{}UD@secondoftwo}%
                            }%
                            %%-----------------------------------------------------------------------------
                            %% Check whether brace-balanced argument starts with a space-token
                            %%.............................................................................
                            %% UD@CheckWhetherLeadingSpace{<Argument which is to be checked>}%
                            %% {<Tokens to be delivered in case <argument
                            %% which is to be checked>'s 1st token is a
                            %% space-token>}%
                            %% {<Tokens to be delivered in case <argument
                            %% which is to be checked>'s 1st token is not
                            %% a space-token>}%
                            newcommandUD@CheckWhetherLeadingSpace[1]{%
                            romannumeral0UD@CheckWhetherNull{#1}%
                            {expandafterexpandafterUD@firstoftwo{ }{}UD@secondoftwo}%
                            {expandafterUD@secondoftwostring{UD@CheckWhetherLeadingSpaceB.#1 }{}}%
                            }%
                            newcommandUD@CheckWhetherLeadingSpaceB{}%
                            longdefUD@CheckWhetherLeadingSpaceB#1 {%
                            expandafterUD@CheckWhetherNullexpandafter{UD@secondoftwo#1{}}%
                            {UD@exchange{UD@firstoftwo}}{UD@exchange{UD@secondoftwo}}%
                            {UD@exchange{ }{expandafterexpandafterexpandafterexpandafter
                            expandafterexpandafterexpandafter}expandafterexpandafter
                            expandafter}expandafterUD@secondoftwoexpandafter{string}%
                            }%
                            %%-----------------------------------------------------------------------------
                            %% Extract first inner undelimited argument:
                            %%.............................................................................
                            %% UD@ExtractFirstArg{ABCDE} yields {A}
                            %%
                            %% UD@ExtractFirstArg{{AB}CDE} yields {AB}
                            %%.............................................................................
                            newcommandUD@RemoveTillUD@SelDOm{}%
                            longdefUD@RemoveTillUD@SelDOm#1#2UD@SelDOm{{#1}}%
                            newcommandUD@ExtractFirstArg[1]{%
                            romannumeral0%
                            UD@ExtractFirstArgLoop{#1UD@SelDOm}%
                            }%
                            newcommandUD@ExtractFirstArgLoop[1]{%
                            expandafterUD@CheckWhetherNullexpandafter{UD@firstoftwo{}#1}%
                            { #1}%
                            {expandafterUD@ExtractFirstArgLoopexpandafter{UD@RemoveTillUD@SelDOm#1}}%
                            }%
                            %%-----------------------------------------------------------------------------
                            %% UD@RemoveSpaces{<argument>} removes leading and trailing spaces from
                            %% <argument>.
                            %% !!!! <argument> must not contain the token UD@seldom !!!!
                            %%.............................................................................
                            begingroup
                            newcommandUD@RemoveSpacesAndOneLevelOfBraces[1]{%
                            endgroup
                            newcommandUD@RemoveSpacesAndOneLevelOfBraces[1]{%
                            romannumeral0%
                            UD@trimtrailspaceloop#1##1UD@seldom#1UD@seldomUD@seldom#1{##1}%
                            }%
                            newcommandUD@trimtrailspaceloop{}%
                            longdefUD@trimtrailspaceloop##1#1UD@seldom##2UD@seldom#1##3{%
                            UD@CheckWhetherNull{##2}{%
                            UD@trimleadspaceloop{##3}%
                            }{%
                            UD@trimtrailspaceloop##1UD@seldom#1UD@seldomUD@seldom#1{##1}%
                            }%
                            }%
                            }%
                            UD@RemoveSpacesAndOneLevelOfBraces{ }%
                            newcommandUD@trimleadspaceloop[1]{%
                            UD@CheckWhetherLeadingSpace{#1}{%
                            expandafterUD@trimleadspaceloopexpandafter{UD@removespace#1}%
                            }{%
                            UD@CheckWhetherNull{#1}{ }{%
                            expandafterUD@CheckWhetherNullexpandafter{UD@firstoftwo{}#1}{%
                            UD@exchange{ }{expandafter}UD@secondoftwo{}#1%
                            }{ #1}%
                            }%
                            }%
                            }%
                            %%-----------------------------------------------------------------------------
                            %% Check whether argument contains no comma which is not nested
                            %% in braces:
                            %%.............................................................................
                            %% UD@CheckWhetherNoComma{<Argument which is to be checked>}%
                            %% {<Tokens to be delivered in case that argument
                            %% contains no comma>}%
                            %% {<Tokens to be delivered in case that argument
                            %% contains comma>}%
                            %%
                            newcommandUD@GobbleToComma{}longdefUD@GobbleToComma#1,{}%
                            newcommandUD@CheckWhetherNoComma[1]{%
                            expandafterUD@CheckWhetherNullexpandafter{UD@GobbleToComma#1,}%
                            }%
                            %%-----------------------------------------------------------------------------
                            %% Check whether argument contains no dash which is not nested
                            %% in braces:
                            %%.............................................................................
                            %% UD@CheckWhetherNoDash{<Argument which is to be checked>}%
                            %% {<Tokens to be delivered in case that argument
                            %% contains no dash>}%
                            %% {<Tokens to be delivered in case that argument
                            %% contains dash>}%
                            %%
                            newcommandUD@GobbleToDash{}longdefUD@GobbleToDash#1-{}%
                            newcommandUD@CheckWhetherNoDash[1]{%
                            expandafterUD@CheckWhetherNullexpandafter{UD@GobbleToDash#1-}%
                            }%
                            %%-----------------------------------------------------------------------------
                            %% Take a comma-delimited/dash-delimited argument where a space was
                            %% prepended for preventing brace-removal and wrap it in curly braces.
                            %%.............................................................................
                            newcommandUD@SplitCommaArg{}%
                            longdefUD@SplitCommaArg#1,{%
                            romannumeral0UD@exchange{ }{expandafter}expandafter{UD@removespace#1}%
                            }%
                            newcommandUD@SplitDashArg{}%
                            longdefUD@SplitDashArg#1-{%
                            romannumeral0UD@exchange{ }{expandafter}expandafter{UD@removespace#1}%
                            }%
                            %%-----------------------------------------------------------------------------
                            %% Now we have the tools for creating the desired mycommand-macro:
                            %%.............................................................................
                            newcommandmycommand[1]{%
                            romannumeral0%
                            UD@CheckWhetherNoComma{#1}{%
                            expandafterUD@exchangeexpandafter{%
                            expandafter{%
                            romannumeral0UD@exchange{ }{expandafterexpandafterexpandafter}%
                            UD@RemoveSpacesAndOneLevelOfBraces{#1}%
                            }%
                            }{mycommand@oneargument}%
                            }{%
                            expandafterUD@exchangeexpandafter{expandafter%
                            {%
                            romannumeral0%
                            UD@exchange{ }{expandafterexpandafterexpandafter}%
                            expandafterUD@firstoftwoexpandafter{expandafter}%
                            romannumeral0%
                            UD@exchange{ }{%
                            expandafterexpandafterexpandafterexpandafter
                            expandafterexpandafterexpandafter
                            }%
                            expandafterUD@SplitCommaArg
                            UD@firstoftwo{ }{}#1}%
                            }{%
                            expandafter@mycommand
                            romannumeral0%
                            UD@exchange{ }{%
                            expandafterexpandafterexpandafterexpandafter
                            expandafterexpandafterexpandafter
                            }%
                            expandafterUD@ExtractFirstArgexpandafter{%
                            romannumeral0%
                            UD@exchange{ }{%
                            expandafterexpandafterexpandafterexpandafter
                            expandafterexpandafterexpandafter
                            }%
                            expandafterUD@SplitCommaArg
                            UD@firstoftwo{ }{}#1}%
                            }%
                            }%
                            }%
                            newcommand@mycommand[2]{%
                            UD@CheckWhetherNoDash{#2}{%
                            expandafterUD@exchangeexpandafter{expandafter
                            {%
                            romannumeral0%
                            UD@exchange{ }{expandafterexpandafterexpandafter}%
                            UD@RemoveSpacesAndOneLevelOfBraces{#2}%
                            }%
                            }{%
                            expandafterUD@exchangeexpandafter{%
                            expandafter{%
                            romannumeral0%
                            UD@exchange{ }{expandafterexpandafterexpandafter}%
                            UD@RemoveSpacesAndOneLevelOfBraces{#1}%
                            }%
                            }{mycommand@twoarguments}%
                            }%
                            }{%
                            expandafterUD@exchangeexpandafter{expandafter%
                            {%
                            romannumeral0%
                            UD@exchange{ }{expandafterexpandafterexpandafter}%
                            expandafterUD@firstoftwoexpandafter{expandafter}%
                            romannumeral0%
                            UD@exchange{ }{%
                            expandafterexpandafterexpandafterexpandafter
                            expandafterexpandafterexpandafter
                            }%
                            expandafterUD@SplitDashArg
                            UD@firstoftwo{ }{}#2}%
                            }{%
                            expandafter@@mycommand
                            romannumeral0%
                            UD@exchange{ }{%
                            expandafterexpandafterexpandafterexpandafter
                            expandafterexpandafterexpandafter
                            }%
                            expandafterUD@ExtractFirstArgexpandafter{%
                            romannumeral0%
                            UD@exchange{ }{%
                            expandafterexpandafterexpandafterexpandafter
                            expandafterexpandafterexpandafter
                            }%
                            expandafterUD@SplitDashArg
                            UD@firstoftwo{ }{}#2}%
                            }%
                            {#1}%
                            }%
                            }%
                            newcommand@@mycommand[3]{%
                            expandafterUD@exchangeexpandafter{%
                            expandafter{%
                            romannumeral0%
                            UD@exchange{ }{expandafterexpandafterexpandafter}%
                            UD@RemoveSpacesAndOneLevelOfBraces{#2}%
                            }%
                            }{%
                            expandafterUD@exchangeexpandafter{%
                            expandafter{%
                            romannumeral0%
                            UD@exchange{ }{expandafterexpandafterexpandafter}%
                            UD@RemoveSpacesAndOneLevelOfBraces{#1}%
                            }%
                            }{%
                            expandafterUD@exchangeexpandafter{%
                            expandafter{%
                            romannumeral0%
                            UD@exchange{ }{expandafterexpandafterexpandafter}%
                            UD@RemoveSpacesAndOneLevelOfBraces{#3}%
                            }%
                            }{mycommand@threearguments}%
                            }%
                            }%
                            }%
                            newcommandmycommand@oneargument[1]{%
                            UD@secondoftwo{%
                            %We need a space to stop romannumeral-expansion.
                            }{ }%
                            There is no comma or only empty args after the comma, thus:\
                            argument 1 = printmeaning{#1}%
                            }%
                            newcommandmycommand@twoarguments[2]{%
                            UD@CheckWhetherNull{#2}{%
                            mycommand@oneargument{#1}%
                            }{%
                            UD@secondoftwo{%
                            %We need a space to stop romannumeral-expansion.
                            }{ }%
                            There is a comma but either no dash or only one non-empty argument near
                            the dash, thus:\
                            argument 1 = printmeaning{#1}\
                            argument 2 = printmeaning{#2}%
                            }%
                            }%
                            newcommandmycommand@threearguments[3]{%
                            UD@CheckWhetherNull{#2}{%
                            UD@CheckWhetherNull{#3}{%
                            mycommand@oneargument{#1}%
                            }{%x
                            mycommand@twoarguments{#1}{#3}%
                            }%
                            }{%
                            UD@CheckWhetherNull{#3}{%
                            mycommand@twoarguments{#1}{#2}%
                            }{%
                            UD@secondoftwo{%
                            %We need a space to stop romannumeral-expansion.
                            }{ }%
                            There is a comma and a dash, thus:\
                            argument 1 = printmeaning{#1}\
                            argument 2 = printmeaning{#2}\
                            argument 3 = printmeaning{#3}%
                            }%
                            }%
                            }%

                            newcommandprintmeaning[1]{%
                            defUD@tempa{#1}%
                            fbox{texttt{expandafterstrip@prefixmeaningUD@tempa}}%
                            }%

                            makeatother

                            parindent=0ex
                            parskip=smallskipamount

                            begin{document}

                            verb|mycommand{ arg 1 }|:\
                            mycommand{ arg 1 }\
                            nullhrulefillnull

                            verb|mycommand{ arg 1 , }|:\
                            mycommand{ arg 1 , }\
                            nullhrulefillnull

                            verb|mycommand{ arg 1 , - }|:\
                            mycommand{ arg 1 , - }\
                            nullhrulefillnull

                            verb|mycommand{ arg 1 , arg 2 - }|:\
                            mycommand{ arg 1 , arg 2 - }\
                            nullhrulefillnull

                            verb|mycommand{ arg 1 , arg 2 - arg 3}|:\
                            mycommand{ arg 1 , arg 2 - arg 3}\
                            nullhrulefillnull

                            verb|mycommand{ arg 1 , - arg 3}|:\
                            mycommand{ arg 1 , - arg 3}\
                            nullhrulefillnull

                            verb|mycommand{ {arg 1a} - arg 1b , {arg 2-2} , 2 - arg 3a - arg 3b}|:\
                            mycommand{ {arg 1a} - arg 1b , {arg 2-2} , 2 - arg 3a - arg 3b}\
                            nullhrulefillnull

                            verb|mycommand{ {arg 1} , {arg 2-2} , 2 - arg 3a - arg 3b}|:\
                            mycommand{ {arg 1} , {arg 2-2} , 2 - arg 3a - arg 3b}

                            end{document}


                            enter image description here






                            share|improve this answer















                            Some crocheting/knitting by hand (or whatever)... ;-)



                            I suppose this question came into being while you thought about your other question: Custom cite command. In that question you ask for a customized cite-command with the same syntax.



                            Be that as it may.



                            The challenge is doing it in a way where desired space-removal but no undesired removal of argument-braces takes place.



                            E.g., with things like mycommand{{arg_1}a, arg_2} the braces surrounding arg_1 should probably be preserved while with things like mycommand{{arg_1} , arg_2} they should probably be removed.

                            Also probably only space-tokens surrounding the entire arguments/surrounding those commas and those dashes that are taken for argument-separators should get removed.



                            Below is an approach where comma takes precedence over the dash where and the leftmost unhidden comma delimits the first argument from the remaining arguments and where the first unhidden dash following that comma delimits the second from the third argument.

                            Exactly one level of braces will be removed in case after removing surrounding spaces it surrounds an entire argument as in that case it is assumed that the braces serve for hiding commas/dashes/spaces/emptiness. In all other cases braces will be preserved.



                            E.g., with things like mycommand{ {arg_1} , {arg_2-2} - arg_3} you should get:

                            First argument: arg_1

                            Second argument: arg_2-2

                            Third argument: arg_3.



                            E.g., with things like mycommand{ {{arg 1,a} - arg 1b} , {arg 2-2} , 2 - arg 3a - arg 3b} you should get:

                            First argument (left from the first unhidden comma, surrounding spaces and outermost brace-level that surrounds the entire argument removed): {arg 1,a} - arg 1b

                            Second argument (right from the first unhidden comma, left from the first unhidden dash following the comma): {arg 2-2} , 2

                            Third argument (the remainder, right from the first unhidden dash following the comma): arg 3a - arg 3b.



                            E.g., with things like mycommand{{arg 1}, {arg 2-2} , 2 - arg 3a - arg 3b} you should get:

                            First argument (left from the first unhidden comma): arg 1

                            Second argument (right from the first unhidden comma, left from the first unhidden dash following the comma): {arg 2-2} , 2

                            Third argument (the remainder, right from the first unhidden dash following the comma): arg 3a - arg 3b.



                            You may not be familiar to methods for removing space-tokens that surround arguments, thus a quote from the manual of my deprecated labelcas-package:




                            A note about removing leading and trailing spaces



                            The matter of removing trailing spaces from an (almost) arbitrary
                            token-sequence is elaborated in detail by Michael Downes, 'Around the
                            Bend #15, answers', a summary of internet-discussion which took place
                            under his guidance primarily at the INFO-TEX list, but also at
                            comp.text.tex (usenet) and via private email; December 1993. Online
                            archived at http://www.tug.org/tex-archive/info/arobend/answer.015.



                            One basic approach suggested therein is using TeX's scanning of
                            delimited parameters in order to detect and discard the ending space
                            of an argument:




                            ... scan for a pair of tokens: a space-token and some well-chosen
                            bizarre token that can't possibly occur in the scanned text. If you
                            put the bizarre token at the end of the text, and if the text has a
                            trailing space, then TeX's delimiter matching will match at that point
                            and not before, because the earlier occurrences of space don’t have
                            the requisite other member of the pair.



                            Next consider the possibility that the trailing space is absent: TeX
                            will keep on scanning ahead for the pair
                            &langle;space&rangle;&langle;bizarre&rangle;
                            until either it finds them or it decides to give up and signal a
                            'Runaway argument?' error. So you must add a stop pair to catch the
                            runaway argument possibility: a second instance of the bizarre
                            token, preceded by a space. If TeX doesn't find a match at the
                            first bizarre token, it will at the second one.




                            (Look up the macros KV@@sp@def, KV@@sp@b, KV@@sp@c and KV@@sp@d in
                            David Carlisle’s keyval-package for an interesting variation on this
                            approach.)



                            When scanning for parameters
                            ##1&langle;space&rangle;&langle;bizarre&rangle;##2&langle;B1&rangle;

                            the sequence:
                            &langle;stuff where to remove trail-space&rangle;&langle;bizarre&rangle;&langle;space&rangle;&langle;bizarre&rangle;&langle;B1&rangle;

                            , you can fork two cases:




                            1. Trailing-space:
                              ##1 = &langle;stuff where to remove trail-space&rangle;, but with removed space. (And possibly one
                              removed brace-level!)
                              ##2 = &langle;space&rangle;&langle;bizarre&rangle;.


                            2. No trailing-space:
                              ##1 = &langle;stuff where to remove trail-space&rangle;&langle;bizarre&rangle;.
                              ##2 is empty.



                            So forking can be implemented depending on the emptiness of ##2.

                            You can easily prevent the brace-removal in the first case, e.g., by adding (and
                            later removing) something (e.g., a space-token) in front of the
                            &langle;stuff where to remove trail-space&rangle;.



                            You can choose &langle;B1&rangle;=&langle;bizarre&rangle;&langle;space&rangle;.




                            The link in the quote is out of date.

                            Nowadays you can find the entire "Around the bend" -collection at http://mirrors.ctan.org/info/challenges/AroBend/AroundTheBend.pdf.



                            As you see, the methods for space-removal exhibited in the quote above do rely on some sequence of tokens that must not occur within the argument.



                            In the example below it is relied on the token UD@seldom not occurring within arguments.

                            In other words: You must not use the token UD@seldom within your arguments.



                            If you don't like that restriction, then I can deliver space-removal-routines which do without such restrictions, but they are slower and they form another huge load of code.



                            documentclass{article}

                            makeatletter
                            %%-----------------------------------------------------------------------------
                            %% Paraphernalia ;-) :
                            %%.............................................................................
                            newcommandUD@firstoftwo[2]{#1}%
                            newcommandUD@secondoftwo[2]{#2}%
                            newcommandUD@exchange[2]{#2#1}%
                            newcommandUD@removespace{}UD@firstoftwo{defUD@removespace}{} {}%
                            %%-----------------------------------------------------------------------------
                            %% Check whether argument is empty:
                            %%.............................................................................
                            %% UD@CheckWhetherNull{<Argument which is to be checked>}%
                            %% {<Tokens to be delivered in case that argument
                            %% which is to be checked is empty>}%
                            %% {<Tokens to be delivered in case that argument
                            %% which is to be checked is not empty>}%
                            %% The gist of this macro comes from Robert R. Schneck's ifempty-macro:
                            %% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
                            %%.............................................................................
                            newcommandUD@CheckWhetherNull[1]{%
                            romannumeral0expandafterUD@secondoftwostring{expandafter
                            UD@secondoftwoexpandafter{expandafter{string#1}expandafter
                            UD@secondoftwostring}expandafterUD@firstoftwoexpandafter{expandafter
                            UD@secondoftwostring}expandafterexpandafterUD@firstoftwo{ }{}%
                            UD@secondoftwo}{expandafterexpandafterUD@firstoftwo{ }{}UD@firstoftwo}%
                            }%
                            %%-----------------------------------------------------------------------------
                            %% Check whether argument's first token is a catcode-1-character
                            %%.............................................................................
                            %% UD@CheckWhetherBrace{<Argument which is to be checked>}%
                            %% {<Tokens to be delivered in case that argument
                            %% which is to be checked has leading
                            %% catcode-1-token>}%
                            %% {<Tokens to be delivered in case that argument
                            %% which is to be checked has no leading
                            %% catcode-1-token>}%
                            newcommandUD@CheckWhetherBrace[1]{%
                            romannumeral0expandafterUD@secondoftwoexpandafter{expandafter{%
                            string#1.}expandafterUD@firstoftwoexpandafter{expandafter
                            UD@secondoftwostring}expandafterexpandafterUD@firstoftwo{ }{}%
                            UD@firstoftwo}{expandafterexpandafterUD@firstoftwo{ }{}UD@secondoftwo}%
                            }%
                            %%-----------------------------------------------------------------------------
                            %% Check whether brace-balanced argument starts with a space-token
                            %%.............................................................................
                            %% UD@CheckWhetherLeadingSpace{<Argument which is to be checked>}%
                            %% {<Tokens to be delivered in case <argument
                            %% which is to be checked>'s 1st token is a
                            %% space-token>}%
                            %% {<Tokens to be delivered in case <argument
                            %% which is to be checked>'s 1st token is not
                            %% a space-token>}%
                            newcommandUD@CheckWhetherLeadingSpace[1]{%
                            romannumeral0UD@CheckWhetherNull{#1}%
                            {expandafterexpandafterUD@firstoftwo{ }{}UD@secondoftwo}%
                            {expandafterUD@secondoftwostring{UD@CheckWhetherLeadingSpaceB.#1 }{}}%
                            }%
                            newcommandUD@CheckWhetherLeadingSpaceB{}%
                            longdefUD@CheckWhetherLeadingSpaceB#1 {%
                            expandafterUD@CheckWhetherNullexpandafter{UD@secondoftwo#1{}}%
                            {UD@exchange{UD@firstoftwo}}{UD@exchange{UD@secondoftwo}}%
                            {UD@exchange{ }{expandafterexpandafterexpandafterexpandafter
                            expandafterexpandafterexpandafter}expandafterexpandafter
                            expandafter}expandafterUD@secondoftwoexpandafter{string}%
                            }%
                            %%-----------------------------------------------------------------------------
                            %% Extract first inner undelimited argument:
                            %%.............................................................................
                            %% UD@ExtractFirstArg{ABCDE} yields {A}
                            %%
                            %% UD@ExtractFirstArg{{AB}CDE} yields {AB}
                            %%.............................................................................
                            newcommandUD@RemoveTillUD@SelDOm{}%
                            longdefUD@RemoveTillUD@SelDOm#1#2UD@SelDOm{{#1}}%
                            newcommandUD@ExtractFirstArg[1]{%
                            romannumeral0%
                            UD@ExtractFirstArgLoop{#1UD@SelDOm}%
                            }%
                            newcommandUD@ExtractFirstArgLoop[1]{%
                            expandafterUD@CheckWhetherNullexpandafter{UD@firstoftwo{}#1}%
                            { #1}%
                            {expandafterUD@ExtractFirstArgLoopexpandafter{UD@RemoveTillUD@SelDOm#1}}%
                            }%
                            %%-----------------------------------------------------------------------------
                            %% UD@RemoveSpaces{<argument>} removes leading and trailing spaces from
                            %% <argument>.
                            %% !!!! <argument> must not contain the token UD@seldom !!!!
                            %%.............................................................................
                            begingroup
                            newcommandUD@RemoveSpacesAndOneLevelOfBraces[1]{%
                            endgroup
                            newcommandUD@RemoveSpacesAndOneLevelOfBraces[1]{%
                            romannumeral0%
                            UD@trimtrailspaceloop#1##1UD@seldom#1UD@seldomUD@seldom#1{##1}%
                            }%
                            newcommandUD@trimtrailspaceloop{}%
                            longdefUD@trimtrailspaceloop##1#1UD@seldom##2UD@seldom#1##3{%
                            UD@CheckWhetherNull{##2}{%
                            UD@trimleadspaceloop{##3}%
                            }{%
                            UD@trimtrailspaceloop##1UD@seldom#1UD@seldomUD@seldom#1{##1}%
                            }%
                            }%
                            }%
                            UD@RemoveSpacesAndOneLevelOfBraces{ }%
                            newcommandUD@trimleadspaceloop[1]{%
                            UD@CheckWhetherLeadingSpace{#1}{%
                            expandafterUD@trimleadspaceloopexpandafter{UD@removespace#1}%
                            }{%
                            UD@CheckWhetherNull{#1}{ }{%
                            expandafterUD@CheckWhetherNullexpandafter{UD@firstoftwo{}#1}{%
                            UD@exchange{ }{expandafter}UD@secondoftwo{}#1%
                            }{ #1}%
                            }%
                            }%
                            }%
                            %%-----------------------------------------------------------------------------
                            %% Check whether argument contains no comma which is not nested
                            %% in braces:
                            %%.............................................................................
                            %% UD@CheckWhetherNoComma{<Argument which is to be checked>}%
                            %% {<Tokens to be delivered in case that argument
                            %% contains no comma>}%
                            %% {<Tokens to be delivered in case that argument
                            %% contains comma>}%
                            %%
                            newcommandUD@GobbleToComma{}longdefUD@GobbleToComma#1,{}%
                            newcommandUD@CheckWhetherNoComma[1]{%
                            expandafterUD@CheckWhetherNullexpandafter{UD@GobbleToComma#1,}%
                            }%
                            %%-----------------------------------------------------------------------------
                            %% Check whether argument contains no dash which is not nested
                            %% in braces:
                            %%.............................................................................
                            %% UD@CheckWhetherNoDash{<Argument which is to be checked>}%
                            %% {<Tokens to be delivered in case that argument
                            %% contains no dash>}%
                            %% {<Tokens to be delivered in case that argument
                            %% contains dash>}%
                            %%
                            newcommandUD@GobbleToDash{}longdefUD@GobbleToDash#1-{}%
                            newcommandUD@CheckWhetherNoDash[1]{%
                            expandafterUD@CheckWhetherNullexpandafter{UD@GobbleToDash#1-}%
                            }%
                            %%-----------------------------------------------------------------------------
                            %% Take a comma-delimited/dash-delimited argument where a space was
                            %% prepended for preventing brace-removal and wrap it in curly braces.
                            %%.............................................................................
                            newcommandUD@SplitCommaArg{}%
                            longdefUD@SplitCommaArg#1,{%
                            romannumeral0UD@exchange{ }{expandafter}expandafter{UD@removespace#1}%
                            }%
                            newcommandUD@SplitDashArg{}%
                            longdefUD@SplitDashArg#1-{%
                            romannumeral0UD@exchange{ }{expandafter}expandafter{UD@removespace#1}%
                            }%
                            %%-----------------------------------------------------------------------------
                            %% Now we have the tools for creating the desired mycommand-macro:
                            %%.............................................................................
                            newcommandmycommand[1]{%
                            romannumeral0%
                            UD@CheckWhetherNoComma{#1}{%
                            expandafterUD@exchangeexpandafter{%
                            expandafter{%
                            romannumeral0UD@exchange{ }{expandafterexpandafterexpandafter}%
                            UD@RemoveSpacesAndOneLevelOfBraces{#1}%
                            }%
                            }{mycommand@oneargument}%
                            }{%
                            expandafterUD@exchangeexpandafter{expandafter%
                            {%
                            romannumeral0%
                            UD@exchange{ }{expandafterexpandafterexpandafter}%
                            expandafterUD@firstoftwoexpandafter{expandafter}%
                            romannumeral0%
                            UD@exchange{ }{%
                            expandafterexpandafterexpandafterexpandafter
                            expandafterexpandafterexpandafter
                            }%
                            expandafterUD@SplitCommaArg
                            UD@firstoftwo{ }{}#1}%
                            }{%
                            expandafter@mycommand
                            romannumeral0%
                            UD@exchange{ }{%
                            expandafterexpandafterexpandafterexpandafter
                            expandafterexpandafterexpandafter
                            }%
                            expandafterUD@ExtractFirstArgexpandafter{%
                            romannumeral0%
                            UD@exchange{ }{%
                            expandafterexpandafterexpandafterexpandafter
                            expandafterexpandafterexpandafter
                            }%
                            expandafterUD@SplitCommaArg
                            UD@firstoftwo{ }{}#1}%
                            }%
                            }%
                            }%
                            newcommand@mycommand[2]{%
                            UD@CheckWhetherNoDash{#2}{%
                            expandafterUD@exchangeexpandafter{expandafter
                            {%
                            romannumeral0%
                            UD@exchange{ }{expandafterexpandafterexpandafter}%
                            UD@RemoveSpacesAndOneLevelOfBraces{#2}%
                            }%
                            }{%
                            expandafterUD@exchangeexpandafter{%
                            expandafter{%
                            romannumeral0%
                            UD@exchange{ }{expandafterexpandafterexpandafter}%
                            UD@RemoveSpacesAndOneLevelOfBraces{#1}%
                            }%
                            }{mycommand@twoarguments}%
                            }%
                            }{%
                            expandafterUD@exchangeexpandafter{expandafter%
                            {%
                            romannumeral0%
                            UD@exchange{ }{expandafterexpandafterexpandafter}%
                            expandafterUD@firstoftwoexpandafter{expandafter}%
                            romannumeral0%
                            UD@exchange{ }{%
                            expandafterexpandafterexpandafterexpandafter
                            expandafterexpandafterexpandafter
                            }%
                            expandafterUD@SplitDashArg
                            UD@firstoftwo{ }{}#2}%
                            }{%
                            expandafter@@mycommand
                            romannumeral0%
                            UD@exchange{ }{%
                            expandafterexpandafterexpandafterexpandafter
                            expandafterexpandafterexpandafter
                            }%
                            expandafterUD@ExtractFirstArgexpandafter{%
                            romannumeral0%
                            UD@exchange{ }{%
                            expandafterexpandafterexpandafterexpandafter
                            expandafterexpandafterexpandafter
                            }%
                            expandafterUD@SplitDashArg
                            UD@firstoftwo{ }{}#2}%
                            }%
                            {#1}%
                            }%
                            }%
                            newcommand@@mycommand[3]{%
                            expandafterUD@exchangeexpandafter{%
                            expandafter{%
                            romannumeral0%
                            UD@exchange{ }{expandafterexpandafterexpandafter}%
                            UD@RemoveSpacesAndOneLevelOfBraces{#2}%
                            }%
                            }{%
                            expandafterUD@exchangeexpandafter{%
                            expandafter{%
                            romannumeral0%
                            UD@exchange{ }{expandafterexpandafterexpandafter}%
                            UD@RemoveSpacesAndOneLevelOfBraces{#1}%
                            }%
                            }{%
                            expandafterUD@exchangeexpandafter{%
                            expandafter{%
                            romannumeral0%
                            UD@exchange{ }{expandafterexpandafterexpandafter}%
                            UD@RemoveSpacesAndOneLevelOfBraces{#3}%
                            }%
                            }{mycommand@threearguments}%
                            }%
                            }%
                            }%
                            newcommandmycommand@oneargument[1]{%
                            UD@secondoftwo{%
                            %We need a space to stop romannumeral-expansion.
                            }{ }%
                            There is no comma or only empty args after the comma, thus:\
                            argument 1 = printmeaning{#1}%
                            }%
                            newcommandmycommand@twoarguments[2]{%
                            UD@CheckWhetherNull{#2}{%
                            mycommand@oneargument{#1}%
                            }{%
                            UD@secondoftwo{%
                            %We need a space to stop romannumeral-expansion.
                            }{ }%
                            There is a comma but either no dash or only one non-empty argument near
                            the dash, thus:\
                            argument 1 = printmeaning{#1}\
                            argument 2 = printmeaning{#2}%
                            }%
                            }%
                            newcommandmycommand@threearguments[3]{%
                            UD@CheckWhetherNull{#2}{%
                            UD@CheckWhetherNull{#3}{%
                            mycommand@oneargument{#1}%
                            }{%x
                            mycommand@twoarguments{#1}{#3}%
                            }%
                            }{%
                            UD@CheckWhetherNull{#3}{%
                            mycommand@twoarguments{#1}{#2}%
                            }{%
                            UD@secondoftwo{%
                            %We need a space to stop romannumeral-expansion.
                            }{ }%
                            There is a comma and a dash, thus:\
                            argument 1 = printmeaning{#1}\
                            argument 2 = printmeaning{#2}\
                            argument 3 = printmeaning{#3}%
                            }%
                            }%
                            }%

                            newcommandprintmeaning[1]{%
                            defUD@tempa{#1}%
                            fbox{texttt{expandafterstrip@prefixmeaningUD@tempa}}%
                            }%

                            makeatother

                            parindent=0ex
                            parskip=smallskipamount

                            begin{document}

                            verb|mycommand{ arg 1 }|:\
                            mycommand{ arg 1 }\
                            nullhrulefillnull

                            verb|mycommand{ arg 1 , }|:\
                            mycommand{ arg 1 , }\
                            nullhrulefillnull

                            verb|mycommand{ arg 1 , - }|:\
                            mycommand{ arg 1 , - }\
                            nullhrulefillnull

                            verb|mycommand{ arg 1 , arg 2 - }|:\
                            mycommand{ arg 1 , arg 2 - }\
                            nullhrulefillnull

                            verb|mycommand{ arg 1 , arg 2 - arg 3}|:\
                            mycommand{ arg 1 , arg 2 - arg 3}\
                            nullhrulefillnull

                            verb|mycommand{ arg 1 , - arg 3}|:\
                            mycommand{ arg 1 , - arg 3}\
                            nullhrulefillnull

                            verb|mycommand{ {arg 1a} - arg 1b , {arg 2-2} , 2 - arg 3a - arg 3b}|:\
                            mycommand{ {arg 1a} - arg 1b , {arg 2-2} , 2 - arg 3a - arg 3b}\
                            nullhrulefillnull

                            verb|mycommand{ {arg 1} , {arg 2-2} , 2 - arg 3a - arg 3b}|:\
                            mycommand{ {arg 1} , {arg 2-2} , 2 - arg 3a - arg 3b}

                            end{document}


                            enter image description here







                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited 6 mins ago

























                            answered 32 mins ago









                            Ulrich DiezUlrich Diez

                            4,510616




                            4,510616






























                                draft saved

                                draft discarded




















































                                Thanks for contributing an answer to TeX - LaTeX Stack Exchange!


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function () {
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f473965%2fa-command-challenge%23new-answer', 'question_page');
                                }
                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                Popular posts from this blog

                                Усть-Каменогорск

                                Халкинская богословская школа

                                Where does the word Sparryheid come from and mean?