A command challenge












10















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


















  • 2





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

    – Joseph Wright
    Feb 8 at 17:46











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

    – John Kormylo
    Feb 8 at 21:41













  • Since I assume this is more or less a follow-up to tex.stackexchange.com/q/473949/35864, let me please re-iterate that I believe that the usual biblatex syntax is not really inferior to this syntax. In fact the syntax proposed here has the serious drawback that it removes the ability to cite several entries in one cite command autocite{sugfridsson,worman,nussbaum} as that uses the comma-separated syntax in one argument already.

    – moewe
    Feb 9 at 8:00
















10















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


















  • 2





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

    – Joseph Wright
    Feb 8 at 17:46











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

    – John Kormylo
    Feb 8 at 21:41













  • Since I assume this is more or less a follow-up to tex.stackexchange.com/q/473949/35864, let me please re-iterate that I believe that the usual biblatex syntax is not really inferior to this syntax. In fact the syntax proposed here has the serious drawback that it removes the ability to cite several entries in one cite command autocite{sugfridsson,worman,nussbaum} as that uses the comma-separated syntax in one argument already.

    – moewe
    Feb 9 at 8:00














10












10








10


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 Feb 8 at 17:42









noibenoibe

32010




32010








  • 2





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

    – Joseph Wright
    Feb 8 at 17:46











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

    – John Kormylo
    Feb 8 at 21:41













  • Since I assume this is more or less a follow-up to tex.stackexchange.com/q/473949/35864, let me please re-iterate that I believe that the usual biblatex syntax is not really inferior to this syntax. In fact the syntax proposed here has the serious drawback that it removes the ability to cite several entries in one cite command autocite{sugfridsson,worman,nussbaum} as that uses the comma-separated syntax in one argument already.

    – moewe
    Feb 9 at 8:00














  • 2





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

    – Joseph Wright
    Feb 8 at 17:46











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

    – John Kormylo
    Feb 8 at 21:41













  • Since I assume this is more or less a follow-up to tex.stackexchange.com/q/473949/35864, let me please re-iterate that I believe that the usual biblatex syntax is not really inferior to this syntax. In fact the syntax proposed here has the serious drawback that it removes the ability to cite several entries in one cite command autocite{sugfridsson,worman,nussbaum} as that uses the comma-separated syntax in one argument already.

    – moewe
    Feb 9 at 8:00








2




2





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

– Joseph Wright
Feb 8 at 17:46





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

– Joseph Wright
Feb 8 at 17:46













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

– John Kormylo
Feb 8 at 21:41







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

– John Kormylo
Feb 8 at 21:41















Since I assume this is more or less a follow-up to tex.stackexchange.com/q/473949/35864, let me please re-iterate that I believe that the usual biblatex syntax is not really inferior to this syntax. In fact the syntax proposed here has the serious drawback that it removes the ability to cite several entries in one cite command autocite{sugfridsson,worman,nussbaum} as that uses the comma-separated syntax in one argument already.

– moewe
Feb 9 at 8:00





Since I assume this is more or less a follow-up to tex.stackexchange.com/q/473949/35864, let me please re-iterate that I believe that the usual biblatex syntax is not really inferior to this syntax. In fact the syntax proposed here has the serious drawback that it removes the ability to cite several entries in one cite command autocite{sugfridsson,worman,nussbaum} as that uses the comma-separated syntax in one argument already.

– moewe
Feb 9 at 8:00










5 Answers
5






active

oldest

votes


















11














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































    18














    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
      Feb 8 at 17:53











    • How about adding some mortar to the bricks!?

      – Werner
      Feb 8 at 18:06











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

      – David Carlisle
      Feb 8 at 18:12






    • 5





      @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
      Feb 8 at 18:49






    • 2





      No zzz? :'-(

      – Henri Menke
      Feb 9 at 6:02



















    6














    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 and where 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 pair of matching curly 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 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}
    %%
    %% !!! The argument of UD@ExtractFirstArg must not be empty. !!!
    %% You can check for emptiness via UD@CheckWhetherNull before applying
    %% UD@ExtractFirstArg.
    %%.............................................................................
    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@RemoveSpacesAndOneLevelOfBraces{<argument>} removes leading and
    %% trailing spaces from <argument>.
    %% If after that the <argument> is something that is entirely nested
    %% between at least one pair of matching curly braces, the outermost
    %% pair of these braces will be removed.
    %%
    %% !!!! <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}{%
    expandaftermycommand@oneargumentexpandafter{%
    romannumeral0UD@exchange{ }{expandafterexpandafterexpandafter}%
    UD@RemoveSpacesAndOneLevelOfBraces{#1}%
    }%
    }{%
    expandafterUD@exchangeexpandafter{expandafter
    {UD@GobbleToComma#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}%
    }%
    }{%
    expandaftermycommand@twoargumentsexpandafter{%
    romannumeral0%
    UD@exchange{ }{expandafterexpandafterexpandafter}%
    UD@RemoveSpacesAndOneLevelOfBraces{#1}%
    }%
    }%
    }{%
    expandafterUD@exchangeexpandafter{expandafter%
    {UD@GobbleToDash#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}%
    }%
    }{%
    expandaftermycommand@threeargumentsexpandafter{%
    romannumeral0%
    UD@exchange{ }{expandafterexpandafterexpandafter}%
    UD@RemoveSpacesAndOneLevelOfBraces{#3}%
    }%
    }%
    }%
    }%
    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
    pagestyle{empty}%


    begin{document}
    vspace*{-3.5cm}%
    enlargethispage{7cm}%

    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}} }\
    (Be aware that (only) the outermost braces get removed from
    an argument if surrounding the entire argument after removal
    of surrounding spaces.)\
    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

































      4














      A listofitems approach.



      By setting a nested parsing with setsepchar{,/-} prior to reading the list into myargs, everything to the left of the 1st comma is read into myargs[1], everything to the right of the comma (and before the next comma) is read into myargs[2].



      Within myargs[2], everything to the left of the first dash is assigned to myargs[2,1], and everything after the dash (and before the next dash) is assigned to myargs[2,2].



      The number of sub-elements within myargs[2] is available through listlenmyargs[2].



      All these elements and list length variables are fully expandable.



      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

































        1














        One more:



        documentclass{article}
        usepackage{xstring}
        defmycommand#1,#2 {IfSubStr{#2}{-}{[[#1],
        [StrBefore{#2}{-}]-[StrBehind{#2}{-}]] }{[[#1],[#2]]}}
        begin{document}
        mycommand aaa,bbb-ccc
        mycommand aaa,bbb
        end{document}


        mwe






        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

























          5 Answers
          5






          active

          oldest

          votes








          5 Answers
          5






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          11














          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




























            11














            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


























              11












              11








              11







              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 Feb 8 at 18:22









              egregegreg

              720k8719093208




              720k8719093208























                  18














                  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
                    Feb 8 at 17:53











                  • How about adding some mortar to the bricks!?

                    – Werner
                    Feb 8 at 18:06











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

                    – David Carlisle
                    Feb 8 at 18:12






                  • 5





                    @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
                    Feb 8 at 18:49






                  • 2





                    No zzz? :'-(

                    – Henri Menke
                    Feb 9 at 6:02
















                  18














                  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
                    Feb 8 at 17:53











                  • How about adding some mortar to the bricks!?

                    – Werner
                    Feb 8 at 18:06











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

                    – David Carlisle
                    Feb 8 at 18:12






                  • 5





                    @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
                    Feb 8 at 18:49






                  • 2





                    No zzz? :'-(

                    – Henri Menke
                    Feb 9 at 6:02














                  18












                  18








                  18







                  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 Feb 8 at 17:48









                  David CarlisleDavid Carlisle

                  490k4111341883




                  490k4111341883








                  • 6





                    Even without electricity. I'm impressed!

                    – marmot
                    Feb 8 at 17:53











                  • How about adding some mortar to the bricks!?

                    – Werner
                    Feb 8 at 18:06











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

                    – David Carlisle
                    Feb 8 at 18:12






                  • 5





                    @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
                    Feb 8 at 18:49






                  • 2





                    No zzz? :'-(

                    – Henri Menke
                    Feb 9 at 6:02














                  • 6





                    Even without electricity. I'm impressed!

                    – marmot
                    Feb 8 at 17:53











                  • How about adding some mortar to the bricks!?

                    – Werner
                    Feb 8 at 18:06











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

                    – David Carlisle
                    Feb 8 at 18:12






                  • 5





                    @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
                    Feb 8 at 18:49






                  • 2





                    No zzz? :'-(

                    – Henri Menke
                    Feb 9 at 6:02








                  6




                  6





                  Even without electricity. I'm impressed!

                  – marmot
                  Feb 8 at 17:53





                  Even without electricity. I'm impressed!

                  – marmot
                  Feb 8 at 17:53













                  How about adding some mortar to the bricks!?

                  – Werner
                  Feb 8 at 18:06





                  How about adding some mortar to the bricks!?

                  – Werner
                  Feb 8 at 18:06













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

                  – David Carlisle
                  Feb 8 at 18:12





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

                  – David Carlisle
                  Feb 8 at 18:12




                  5




                  5





                  @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
                  Feb 8 at 18:49





                  @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
                  Feb 8 at 18:49




                  2




                  2





                  No zzz? :'-(

                  – Henri Menke
                  Feb 9 at 6:02





                  No zzz? :'-(

                  – Henri Menke
                  Feb 9 at 6:02











                  6














                  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 and where 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 pair of matching curly 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 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}
                  %%
                  %% !!! The argument of UD@ExtractFirstArg must not be empty. !!!
                  %% You can check for emptiness via UD@CheckWhetherNull before applying
                  %% UD@ExtractFirstArg.
                  %%.............................................................................
                  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@RemoveSpacesAndOneLevelOfBraces{<argument>} removes leading and
                  %% trailing spaces from <argument>.
                  %% If after that the <argument> is something that is entirely nested
                  %% between at least one pair of matching curly braces, the outermost
                  %% pair of these braces will be removed.
                  %%
                  %% !!!! <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}{%
                  expandaftermycommand@oneargumentexpandafter{%
                  romannumeral0UD@exchange{ }{expandafterexpandafterexpandafter}%
                  UD@RemoveSpacesAndOneLevelOfBraces{#1}%
                  }%
                  }{%
                  expandafterUD@exchangeexpandafter{expandafter
                  {UD@GobbleToComma#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}%
                  }%
                  }{%
                  expandaftermycommand@twoargumentsexpandafter{%
                  romannumeral0%
                  UD@exchange{ }{expandafterexpandafterexpandafter}%
                  UD@RemoveSpacesAndOneLevelOfBraces{#1}%
                  }%
                  }%
                  }{%
                  expandafterUD@exchangeexpandafter{expandafter%
                  {UD@GobbleToDash#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}%
                  }%
                  }{%
                  expandaftermycommand@threeargumentsexpandafter{%
                  romannumeral0%
                  UD@exchange{ }{expandafterexpandafterexpandafter}%
                  UD@RemoveSpacesAndOneLevelOfBraces{#3}%
                  }%
                  }%
                  }%
                  }%
                  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
                  pagestyle{empty}%


                  begin{document}
                  vspace*{-3.5cm}%
                  enlargethispage{7cm}%

                  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}} }\
                  (Be aware that (only) the outermost braces get removed from
                  an argument if surrounding the entire argument after removal
                  of surrounding spaces.)\
                  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






























                    6














                    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 and where 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 pair of matching curly 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 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}
                    %%
                    %% !!! The argument of UD@ExtractFirstArg must not be empty. !!!
                    %% You can check for emptiness via UD@CheckWhetherNull before applying
                    %% UD@ExtractFirstArg.
                    %%.............................................................................
                    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@RemoveSpacesAndOneLevelOfBraces{<argument>} removes leading and
                    %% trailing spaces from <argument>.
                    %% If after that the <argument> is something that is entirely nested
                    %% between at least one pair of matching curly braces, the outermost
                    %% pair of these braces will be removed.
                    %%
                    %% !!!! <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}{%
                    expandaftermycommand@oneargumentexpandafter{%
                    romannumeral0UD@exchange{ }{expandafterexpandafterexpandafter}%
                    UD@RemoveSpacesAndOneLevelOfBraces{#1}%
                    }%
                    }{%
                    expandafterUD@exchangeexpandafter{expandafter
                    {UD@GobbleToComma#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}%
                    }%
                    }{%
                    expandaftermycommand@twoargumentsexpandafter{%
                    romannumeral0%
                    UD@exchange{ }{expandafterexpandafterexpandafter}%
                    UD@RemoveSpacesAndOneLevelOfBraces{#1}%
                    }%
                    }%
                    }{%
                    expandafterUD@exchangeexpandafter{expandafter%
                    {UD@GobbleToDash#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}%
                    }%
                    }{%
                    expandaftermycommand@threeargumentsexpandafter{%
                    romannumeral0%
                    UD@exchange{ }{expandafterexpandafterexpandafter}%
                    UD@RemoveSpacesAndOneLevelOfBraces{#3}%
                    }%
                    }%
                    }%
                    }%
                    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
                    pagestyle{empty}%


                    begin{document}
                    vspace*{-3.5cm}%
                    enlargethispage{7cm}%

                    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}} }\
                    (Be aware that (only) the outermost braces get removed from
                    an argument if surrounding the entire argument after removal
                    of surrounding spaces.)\
                    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




























                      6












                      6








                      6







                      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 and where 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 pair of matching curly 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 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}
                      %%
                      %% !!! The argument of UD@ExtractFirstArg must not be empty. !!!
                      %% You can check for emptiness via UD@CheckWhetherNull before applying
                      %% UD@ExtractFirstArg.
                      %%.............................................................................
                      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@RemoveSpacesAndOneLevelOfBraces{<argument>} removes leading and
                      %% trailing spaces from <argument>.
                      %% If after that the <argument> is something that is entirely nested
                      %% between at least one pair of matching curly braces, the outermost
                      %% pair of these braces will be removed.
                      %%
                      %% !!!! <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}{%
                      expandaftermycommand@oneargumentexpandafter{%
                      romannumeral0UD@exchange{ }{expandafterexpandafterexpandafter}%
                      UD@RemoveSpacesAndOneLevelOfBraces{#1}%
                      }%
                      }{%
                      expandafterUD@exchangeexpandafter{expandafter
                      {UD@GobbleToComma#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}%
                      }%
                      }{%
                      expandaftermycommand@twoargumentsexpandafter{%
                      romannumeral0%
                      UD@exchange{ }{expandafterexpandafterexpandafter}%
                      UD@RemoveSpacesAndOneLevelOfBraces{#1}%
                      }%
                      }%
                      }{%
                      expandafterUD@exchangeexpandafter{expandafter%
                      {UD@GobbleToDash#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}%
                      }%
                      }{%
                      expandaftermycommand@threeargumentsexpandafter{%
                      romannumeral0%
                      UD@exchange{ }{expandafterexpandafterexpandafter}%
                      UD@RemoveSpacesAndOneLevelOfBraces{#3}%
                      }%
                      }%
                      }%
                      }%
                      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
                      pagestyle{empty}%


                      begin{document}
                      vspace*{-3.5cm}%
                      enlargethispage{7cm}%

                      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}} }\
                      (Be aware that (only) the outermost braces get removed from
                      an argument if surrounding the entire argument after removal
                      of surrounding spaces.)\
                      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 and where 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 pair of matching curly 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 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}
                      %%
                      %% !!! The argument of UD@ExtractFirstArg must not be empty. !!!
                      %% You can check for emptiness via UD@CheckWhetherNull before applying
                      %% UD@ExtractFirstArg.
                      %%.............................................................................
                      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@RemoveSpacesAndOneLevelOfBraces{<argument>} removes leading and
                      %% trailing spaces from <argument>.
                      %% If after that the <argument> is something that is entirely nested
                      %% between at least one pair of matching curly braces, the outermost
                      %% pair of these braces will be removed.
                      %%
                      %% !!!! <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}{%
                      expandaftermycommand@oneargumentexpandafter{%
                      romannumeral0UD@exchange{ }{expandafterexpandafterexpandafter}%
                      UD@RemoveSpacesAndOneLevelOfBraces{#1}%
                      }%
                      }{%
                      expandafterUD@exchangeexpandafter{expandafter
                      {UD@GobbleToComma#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}%
                      }%
                      }{%
                      expandaftermycommand@twoargumentsexpandafter{%
                      romannumeral0%
                      UD@exchange{ }{expandafterexpandafterexpandafter}%
                      UD@RemoveSpacesAndOneLevelOfBraces{#1}%
                      }%
                      }%
                      }{%
                      expandafterUD@exchangeexpandafter{expandafter%
                      {UD@GobbleToDash#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}%
                      }%
                      }{%
                      expandaftermycommand@threeargumentsexpandafter{%
                      romannumeral0%
                      UD@exchange{ }{expandafterexpandafterexpandafter}%
                      UD@RemoveSpacesAndOneLevelOfBraces{#3}%
                      }%
                      }%
                      }%
                      }%
                      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
                      pagestyle{empty}%


                      begin{document}
                      vspace*{-3.5cm}%
                      enlargethispage{7cm}%

                      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}} }\
                      (Be aware that (only) the outermost braces get removed from
                      an argument if surrounding the entire argument after removal
                      of surrounding spaces.)\
                      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 Feb 9 at 13:34

























                      answered Feb 8 at 22:53









                      Ulrich DiezUlrich Diez

                      4,830618




                      4,830618























                          4














                          A listofitems approach.



                          By setting a nested parsing with setsepchar{,/-} prior to reading the list into myargs, everything to the left of the 1st comma is read into myargs[1], everything to the right of the comma (and before the next comma) is read into myargs[2].



                          Within myargs[2], everything to the left of the first dash is assigned to myargs[2,1], and everything after the dash (and before the next dash) is assigned to myargs[2,2].



                          The number of sub-elements within myargs[2] is available through listlenmyargs[2].



                          All these elements and list length variables are fully expandable.



                          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






























                            4














                            A listofitems approach.



                            By setting a nested parsing with setsepchar{,/-} prior to reading the list into myargs, everything to the left of the 1st comma is read into myargs[1], everything to the right of the comma (and before the next comma) is read into myargs[2].



                            Within myargs[2], everything to the left of the first dash is assigned to myargs[2,1], and everything after the dash (and before the next dash) is assigned to myargs[2,2].



                            The number of sub-elements within myargs[2] is available through listlenmyargs[2].



                            All these elements and list length variables are fully expandable.



                            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




























                              4












                              4








                              4







                              A listofitems approach.



                              By setting a nested parsing with setsepchar{,/-} prior to reading the list into myargs, everything to the left of the 1st comma is read into myargs[1], everything to the right of the comma (and before the next comma) is read into myargs[2].



                              Within myargs[2], everything to the left of the first dash is assigned to myargs[2,1], and everything after the dash (and before the next dash) is assigned to myargs[2,2].



                              The number of sub-elements within myargs[2] is available through listlenmyargs[2].



                              All these elements and list length variables are fully expandable.



                              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.



                              By setting a nested parsing with setsepchar{,/-} prior to reading the list into myargs, everything to the left of the 1st comma is read into myargs[1], everything to the right of the comma (and before the next comma) is read into myargs[2].



                              Within myargs[2], everything to the left of the first dash is assigned to myargs[2,1], and everything after the dash (and before the next dash) is assigned to myargs[2,2].



                              The number of sub-elements within myargs[2] is available through listlenmyargs[2].



                              All these elements and list length variables are fully expandable.



                              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








                              edited Feb 9 at 14:15

























                              answered Feb 8 at 18:54









                              Steven B. SegletesSteven B. Segletes

                              155k9199409




                              155k9199409























                                  1














                                  One more:



                                  documentclass{article}
                                  usepackage{xstring}
                                  defmycommand#1,#2 {IfSubStr{#2}{-}{[[#1],
                                  [StrBefore{#2}{-}]-[StrBehind{#2}{-}]] }{[[#1],[#2]]}}
                                  begin{document}
                                  mycommand aaa,bbb-ccc
                                  mycommand aaa,bbb
                                  end{document}


                                  mwe






                                  share|improve this answer




























                                    1














                                    One more:



                                    documentclass{article}
                                    usepackage{xstring}
                                    defmycommand#1,#2 {IfSubStr{#2}{-}{[[#1],
                                    [StrBefore{#2}{-}]-[StrBehind{#2}{-}]] }{[[#1],[#2]]}}
                                    begin{document}
                                    mycommand aaa,bbb-ccc
                                    mycommand aaa,bbb
                                    end{document}


                                    mwe






                                    share|improve this answer


























                                      1












                                      1








                                      1







                                      One more:



                                      documentclass{article}
                                      usepackage{xstring}
                                      defmycommand#1,#2 {IfSubStr{#2}{-}{[[#1],
                                      [StrBefore{#2}{-}]-[StrBehind{#2}{-}]] }{[[#1],[#2]]}}
                                      begin{document}
                                      mycommand aaa,bbb-ccc
                                      mycommand aaa,bbb
                                      end{document}


                                      mwe






                                      share|improve this answer













                                      One more:



                                      documentclass{article}
                                      usepackage{xstring}
                                      defmycommand#1,#2 {IfSubStr{#2}{-}{[[#1],
                                      [StrBefore{#2}{-}]-[StrBehind{#2}{-}]] }{[[#1],[#2]]}}
                                      begin{document}
                                      mycommand aaa,bbb-ccc
                                      mycommand aaa,bbb
                                      end{document}


                                      mwe







                                      share|improve this answer












                                      share|improve this answer



                                      share|improve this answer










                                      answered Feb 9 at 18:13









                                      FranFran

                                      52.5k6117178




                                      52.5k6117178






























                                          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

                                          Biblatex bibliography style without URLs when DOI exists (in Overleaf with Zotero bibliography)

                                          ComboBox Display Member on multiple fields

                                          Is it possible to collect Nectar points via Trainline?