A command challenge

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP












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



mycommandarg_1, arg_2


and



mycommandarg_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 autocitesugfridsson,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



mycommandarg_1, arg_2


and



mycommandarg_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 autocitesugfridsson,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



mycommandarg_1, arg_2


and



mycommandarg_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



mycommandarg_1, arg_2


and



mycommandarg_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

435113




435113







  • 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 autocitesugfridsson,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 autocitesugfridsson,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 autocitesugfridsson,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 autocitesugfridsson,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:



documentclassarticle
usepackagexparse

% split at the comma
NewDocumentCommandmycommand >SplitArgument1,m %
mycommandA#1%

% do something with #1 and split the second part at the hyphen
NewDocumentCommandmycommandA m >SplitArgument1-m %
Main is #1%
IfNoValueTF#2.; mycommandB#2%

% do something with the second part
NewDocumentCommandmycommandBmm%
Secondary is #1IfValueT#2 plus #2.%


begindocument

mycommandarg1

mycommandarg1, arg2

mycommandarg1, arg2-arg3

enddocument


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



    documentclassarticle

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


    begindocument

    $mycommandarg_1, arg_2$

    $mycommandarg_1, arg_2-arg3$

    enddocument





    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 mycommandarg_1a, arg_2 the braces surrounding arg_1 should probably be preserved while with things like mycommandarg_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 mycommandarg 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.



    documentclassarticle

    makeatletter
    %%-----------------------------------------------------------------------------
    %% Paraphernalia ;-) :
    %%.............................................................................
    newcommandUD@firstoftwo[2]#1%
    newcommandUD@secondoftwo[2]#2%
    newcommandUD@exchange[2]#2#1%
    newcommandUD@removespaceUD@firstoftwodefUD@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@secondoftwostringexpandafter
    UD@secondoftwoexpandafterexpandafterstring#1expandafter
    UD@secondoftwostringexpandafterUD@firstoftwoexpandafterexpandafter
    UD@secondoftwostringexpandafterexpandafterUD@firstoftwo %
    UD@secondoftwoexpandafterexpandafterUD@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@secondoftwostringUD@CheckWhetherLeadingSpaceB.#1 %
    %
    newcommandUD@CheckWhetherLeadingSpaceB%
    longdefUD@CheckWhetherLeadingSpaceB#1 %
    expandafterUD@CheckWhetherNullexpandafterUD@secondoftwo#1%
    UD@exchangeUD@firstoftwoUD@exchangeUD@secondoftwo%
    UD@exchange expandafterexpandafterexpandafterexpandafter
    expandafterexpandafterexpandafterexpandafterexpandafter
    expandafterexpandafterUD@secondoftwoexpandafterstring%
    %
    %%-----------------------------------------------------------------------------
    %% Extract first inner undelimited argument:
    %%.............................................................................
    %% UD@ExtractFirstArgABCDE yields A
    %%
    %% UD@ExtractFirstArgABCDE 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@CheckWhetherNullexpandafterUD@firstoftwo#1%
    #1%
    expandafterUD@ExtractFirstArgLoopexpandafterUD@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@trimleadspaceloopexpandafterUD@removespace#1%
    %
    UD@CheckWhetherNull#1 %
    expandafterUD@CheckWhetherNullexpandafterUD@firstoftwo#1%
    UD@exchange expandafterUD@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@GobbleToCommalongdefUD@GobbleToComma#1,%
    newcommandUD@CheckWhetherNoComma[1]%
    expandafterUD@CheckWhetherNullexpandafterUD@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@GobbleToDashlongdefUD@GobbleToDash#1-%
    newcommandUD@CheckWhetherNoDash[1]%
    expandafterUD@CheckWhetherNullexpandafterUD@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 expandafterexpandafterUD@removespace#1%
    %
    newcommandUD@SplitDashArg%
    longdefUD@SplitDashArg#1-%
    romannumeral0UD@exchange expandafterexpandafterUD@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@exchangeexpandafterexpandafter
    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@exchangeexpandafterexpandafter
    %
    romannumeral0%
    UD@exchange expandafterexpandafterexpandafter%
    UD@RemoveSpacesAndOneLevelOfBraces#2%
    %
    %
    expandaftermycommand@twoargumentsexpandafter%
    romannumeral0%
    UD@exchange expandafterexpandafterexpandafter%
    UD@RemoveSpacesAndOneLevelOfBraces#1%
    %
    %
    %
    expandafterUD@exchangeexpandafterexpandafter%
    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%
    fboxtextttexpandafterstrip@prefixmeaningUD@tempa%
    %
    makeatother

    parindent=0ex
    parskip=smallskipamount
    pagestyleempty%


    begindocument
    vspace*-3.5cm%
    enlargethispage7cm%

    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

    enddocument


    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.



      documentclassarticle
      usepackagelistofitems
      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%

      begindocument

      mycommandarg1, arg2

      and

      mycommandarg1, arg2-arg3

      enddocument


      enter image description here






      share|improve this answer
































        1














        One more:



        documentclassarticle
        usepackagexstring
        defmycommand#1,#2 IfSubStr#2-[[#1],
        [StrBefore#2-]-[StrBehind#2-]] [[#1],[#2]]
        begindocument
        mycommand aaa,bbb-ccc
        mycommand aaa,bbb
        enddocument


        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:



          documentclassarticle
          usepackagexparse

          % split at the comma
          NewDocumentCommandmycommand >SplitArgument1,m %
          mycommandA#1%

          % do something with #1 and split the second part at the hyphen
          NewDocumentCommandmycommandA m >SplitArgument1-m %
          Main is #1%
          IfNoValueTF#2.; mycommandB#2%

          % do something with the second part
          NewDocumentCommandmycommandBmm%
          Secondary is #1IfValueT#2 plus #2.%


          begindocument

          mycommandarg1

          mycommandarg1, arg2

          mycommandarg1, arg2-arg3

          enddocument


          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:



            documentclassarticle
            usepackagexparse

            % split at the comma
            NewDocumentCommandmycommand >SplitArgument1,m %
            mycommandA#1%

            % do something with #1 and split the second part at the hyphen
            NewDocumentCommandmycommandA m >SplitArgument1-m %
            Main is #1%
            IfNoValueTF#2.; mycommandB#2%

            % do something with the second part
            NewDocumentCommandmycommandBmm%
            Secondary is #1IfValueT#2 plus #2.%


            begindocument

            mycommandarg1

            mycommandarg1, arg2

            mycommandarg1, arg2-arg3

            enddocument


            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:



              documentclassarticle
              usepackagexparse

              % split at the comma
              NewDocumentCommandmycommand >SplitArgument1,m %
              mycommandA#1%

              % do something with #1 and split the second part at the hyphen
              NewDocumentCommandmycommandA m >SplitArgument1-m %
              Main is #1%
              IfNoValueTF#2.; mycommandB#2%

              % do something with the second part
              NewDocumentCommandmycommandBmm%
              Secondary is #1IfValueT#2 plus #2.%


              begindocument

              mycommandarg1

              mycommandarg1, arg2

              mycommandarg1, arg2-arg3

              enddocument


              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:



              documentclassarticle
              usepackagexparse

              % split at the comma
              NewDocumentCommandmycommand >SplitArgument1,m %
              mycommandA#1%

              % do something with #1 and split the second part at the hyphen
              NewDocumentCommandmycommandA m >SplitArgument1-m %
              Main is #1%
              IfNoValueTF#2.; mycommandB#2%

              % do something with the second part
              NewDocumentCommandmycommandBmm%
              Secondary is #1IfValueT#2 plus #2.%


              begindocument

              mycommandarg1

              mycommandarg1, arg2

              mycommandarg1, arg2-arg3

              enddocument


              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

              724k8819173221




              724k8819173221





















                  18














                  enter image description here



                  documentclassarticle

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


                  begindocument

                  $mycommandarg_1, arg_2$

                  $mycommandarg_1, arg_2-arg3$

                  enddocument





                  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



                  documentclassarticle

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


                  begindocument

                  $mycommandarg_1, arg_2$

                  $mycommandarg_1, arg_2-arg3$

                  enddocument





                  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



                  documentclassarticle

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


                  begindocument

                  $mycommandarg_1, arg_2$

                  $mycommandarg_1, arg_2-arg3$

                  enddocument





                  share|improve this answer













                  enter image description here



                  documentclassarticle

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


                  begindocument

                  $mycommandarg_1, arg_2$

                  $mycommandarg_1, arg_2-arg3$

                  enddocument






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Feb 8 at 17:48









                  David CarlisleDavid Carlisle

                  493k4111371885




                  493k4111371885







                  • 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 mycommandarg_1a, arg_2 the braces surrounding arg_1 should probably be preserved while with things like mycommandarg_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 mycommandarg 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.



                  documentclassarticle

                  makeatletter
                  %%-----------------------------------------------------------------------------
                  %% Paraphernalia ;-) :
                  %%.............................................................................
                  newcommandUD@firstoftwo[2]#1%
                  newcommandUD@secondoftwo[2]#2%
                  newcommandUD@exchange[2]#2#1%
                  newcommandUD@removespaceUD@firstoftwodefUD@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@secondoftwostringexpandafter
                  UD@secondoftwoexpandafterexpandafterstring#1expandafter
                  UD@secondoftwostringexpandafterUD@firstoftwoexpandafterexpandafter
                  UD@secondoftwostringexpandafterexpandafterUD@firstoftwo %
                  UD@secondoftwoexpandafterexpandafterUD@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@secondoftwostringUD@CheckWhetherLeadingSpaceB.#1 %
                  %
                  newcommandUD@CheckWhetherLeadingSpaceB%
                  longdefUD@CheckWhetherLeadingSpaceB#1 %
                  expandafterUD@CheckWhetherNullexpandafterUD@secondoftwo#1%
                  UD@exchangeUD@firstoftwoUD@exchangeUD@secondoftwo%
                  UD@exchange expandafterexpandafterexpandafterexpandafter
                  expandafterexpandafterexpandafterexpandafterexpandafter
                  expandafterexpandafterUD@secondoftwoexpandafterstring%
                  %
                  %%-----------------------------------------------------------------------------
                  %% Extract first inner undelimited argument:
                  %%.............................................................................
                  %% UD@ExtractFirstArgABCDE yields A
                  %%
                  %% UD@ExtractFirstArgABCDE 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@CheckWhetherNullexpandafterUD@firstoftwo#1%
                  #1%
                  expandafterUD@ExtractFirstArgLoopexpandafterUD@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@trimleadspaceloopexpandafterUD@removespace#1%
                  %
                  UD@CheckWhetherNull#1 %
                  expandafterUD@CheckWhetherNullexpandafterUD@firstoftwo#1%
                  UD@exchange expandafterUD@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@GobbleToCommalongdefUD@GobbleToComma#1,%
                  newcommandUD@CheckWhetherNoComma[1]%
                  expandafterUD@CheckWhetherNullexpandafterUD@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@GobbleToDashlongdefUD@GobbleToDash#1-%
                  newcommandUD@CheckWhetherNoDash[1]%
                  expandafterUD@CheckWhetherNullexpandafterUD@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 expandafterexpandafterUD@removespace#1%
                  %
                  newcommandUD@SplitDashArg%
                  longdefUD@SplitDashArg#1-%
                  romannumeral0UD@exchange expandafterexpandafterUD@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@exchangeexpandafterexpandafter
                  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@exchangeexpandafterexpandafter
                  %
                  romannumeral0%
                  UD@exchange expandafterexpandafterexpandafter%
                  UD@RemoveSpacesAndOneLevelOfBraces#2%
                  %
                  %
                  expandaftermycommand@twoargumentsexpandafter%
                  romannumeral0%
                  UD@exchange expandafterexpandafterexpandafter%
                  UD@RemoveSpacesAndOneLevelOfBraces#1%
                  %
                  %
                  %
                  expandafterUD@exchangeexpandafterexpandafter%
                  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%
                  fboxtextttexpandafterstrip@prefixmeaningUD@tempa%
                  %
                  makeatother

                  parindent=0ex
                  parskip=smallskipamount
                  pagestyleempty%


                  begindocument
                  vspace*-3.5cm%
                  enlargethispage7cm%

                  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

                  enddocument


                  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 mycommandarg_1a, arg_2 the braces surrounding arg_1 should probably be preserved while with things like mycommandarg_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 mycommandarg 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.



                    documentclassarticle

                    makeatletter
                    %%-----------------------------------------------------------------------------
                    %% Paraphernalia ;-) :
                    %%.............................................................................
                    newcommandUD@firstoftwo[2]#1%
                    newcommandUD@secondoftwo[2]#2%
                    newcommandUD@exchange[2]#2#1%
                    newcommandUD@removespaceUD@firstoftwodefUD@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@secondoftwostringexpandafter
                    UD@secondoftwoexpandafterexpandafterstring#1expandafter
                    UD@secondoftwostringexpandafterUD@firstoftwoexpandafterexpandafter
                    UD@secondoftwostringexpandafterexpandafterUD@firstoftwo %
                    UD@secondoftwoexpandafterexpandafterUD@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@secondoftwostringUD@CheckWhetherLeadingSpaceB.#1 %
                    %
                    newcommandUD@CheckWhetherLeadingSpaceB%
                    longdefUD@CheckWhetherLeadingSpaceB#1 %
                    expandafterUD@CheckWhetherNullexpandafterUD@secondoftwo#1%
                    UD@exchangeUD@firstoftwoUD@exchangeUD@secondoftwo%
                    UD@exchange expandafterexpandafterexpandafterexpandafter
                    expandafterexpandafterexpandafterexpandafterexpandafter
                    expandafterexpandafterUD@secondoftwoexpandafterstring%
                    %
                    %%-----------------------------------------------------------------------------
                    %% Extract first inner undelimited argument:
                    %%.............................................................................
                    %% UD@ExtractFirstArgABCDE yields A
                    %%
                    %% UD@ExtractFirstArgABCDE 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@CheckWhetherNullexpandafterUD@firstoftwo#1%
                    #1%
                    expandafterUD@ExtractFirstArgLoopexpandafterUD@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@trimleadspaceloopexpandafterUD@removespace#1%
                    %
                    UD@CheckWhetherNull#1 %
                    expandafterUD@CheckWhetherNullexpandafterUD@firstoftwo#1%
                    UD@exchange expandafterUD@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@GobbleToCommalongdefUD@GobbleToComma#1,%
                    newcommandUD@CheckWhetherNoComma[1]%
                    expandafterUD@CheckWhetherNullexpandafterUD@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@GobbleToDashlongdefUD@GobbleToDash#1-%
                    newcommandUD@CheckWhetherNoDash[1]%
                    expandafterUD@CheckWhetherNullexpandafterUD@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 expandafterexpandafterUD@removespace#1%
                    %
                    newcommandUD@SplitDashArg%
                    longdefUD@SplitDashArg#1-%
                    romannumeral0UD@exchange expandafterexpandafterUD@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@exchangeexpandafterexpandafter
                    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@exchangeexpandafterexpandafter
                    %
                    romannumeral0%
                    UD@exchange expandafterexpandafterexpandafter%
                    UD@RemoveSpacesAndOneLevelOfBraces#2%
                    %
                    %
                    expandaftermycommand@twoargumentsexpandafter%
                    romannumeral0%
                    UD@exchange expandafterexpandafterexpandafter%
                    UD@RemoveSpacesAndOneLevelOfBraces#1%
                    %
                    %
                    %
                    expandafterUD@exchangeexpandafterexpandafter%
                    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%
                    fboxtextttexpandafterstrip@prefixmeaningUD@tempa%
                    %
                    makeatother

                    parindent=0ex
                    parskip=smallskipamount
                    pagestyleempty%


                    begindocument
                    vspace*-3.5cm%
                    enlargethispage7cm%

                    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

                    enddocument


                    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 mycommandarg_1a, arg_2 the braces surrounding arg_1 should probably be preserved while with things like mycommandarg_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 mycommandarg 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.



                      documentclassarticle

                      makeatletter
                      %%-----------------------------------------------------------------------------
                      %% Paraphernalia ;-) :
                      %%.............................................................................
                      newcommandUD@firstoftwo[2]#1%
                      newcommandUD@secondoftwo[2]#2%
                      newcommandUD@exchange[2]#2#1%
                      newcommandUD@removespaceUD@firstoftwodefUD@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@secondoftwostringexpandafter
                      UD@secondoftwoexpandafterexpandafterstring#1expandafter
                      UD@secondoftwostringexpandafterUD@firstoftwoexpandafterexpandafter
                      UD@secondoftwostringexpandafterexpandafterUD@firstoftwo %
                      UD@secondoftwoexpandafterexpandafterUD@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@secondoftwostringUD@CheckWhetherLeadingSpaceB.#1 %
                      %
                      newcommandUD@CheckWhetherLeadingSpaceB%
                      longdefUD@CheckWhetherLeadingSpaceB#1 %
                      expandafterUD@CheckWhetherNullexpandafterUD@secondoftwo#1%
                      UD@exchangeUD@firstoftwoUD@exchangeUD@secondoftwo%
                      UD@exchange expandafterexpandafterexpandafterexpandafter
                      expandafterexpandafterexpandafterexpandafterexpandafter
                      expandafterexpandafterUD@secondoftwoexpandafterstring%
                      %
                      %%-----------------------------------------------------------------------------
                      %% Extract first inner undelimited argument:
                      %%.............................................................................
                      %% UD@ExtractFirstArgABCDE yields A
                      %%
                      %% UD@ExtractFirstArgABCDE 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@CheckWhetherNullexpandafterUD@firstoftwo#1%
                      #1%
                      expandafterUD@ExtractFirstArgLoopexpandafterUD@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@trimleadspaceloopexpandafterUD@removespace#1%
                      %
                      UD@CheckWhetherNull#1 %
                      expandafterUD@CheckWhetherNullexpandafterUD@firstoftwo#1%
                      UD@exchange expandafterUD@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@GobbleToCommalongdefUD@GobbleToComma#1,%
                      newcommandUD@CheckWhetherNoComma[1]%
                      expandafterUD@CheckWhetherNullexpandafterUD@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@GobbleToDashlongdefUD@GobbleToDash#1-%
                      newcommandUD@CheckWhetherNoDash[1]%
                      expandafterUD@CheckWhetherNullexpandafterUD@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 expandafterexpandafterUD@removespace#1%
                      %
                      newcommandUD@SplitDashArg%
                      longdefUD@SplitDashArg#1-%
                      romannumeral0UD@exchange expandafterexpandafterUD@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@exchangeexpandafterexpandafter
                      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@exchangeexpandafterexpandafter
                      %
                      romannumeral0%
                      UD@exchange expandafterexpandafterexpandafter%
                      UD@RemoveSpacesAndOneLevelOfBraces#2%
                      %
                      %
                      expandaftermycommand@twoargumentsexpandafter%
                      romannumeral0%
                      UD@exchange expandafterexpandafterexpandafter%
                      UD@RemoveSpacesAndOneLevelOfBraces#1%
                      %
                      %
                      %
                      expandafterUD@exchangeexpandafterexpandafter%
                      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%
                      fboxtextttexpandafterstrip@prefixmeaningUD@tempa%
                      %
                      makeatother

                      parindent=0ex
                      parskip=smallskipamount
                      pagestyleempty%


                      begindocument
                      vspace*-3.5cm%
                      enlargethispage7cm%

                      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

                      enddocument


                      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 mycommandarg_1a, arg_2 the braces surrounding arg_1 should probably be preserved while with things like mycommandarg_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 mycommandarg 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.



                      documentclassarticle

                      makeatletter
                      %%-----------------------------------------------------------------------------
                      %% Paraphernalia ;-) :
                      %%.............................................................................
                      newcommandUD@firstoftwo[2]#1%
                      newcommandUD@secondoftwo[2]#2%
                      newcommandUD@exchange[2]#2#1%
                      newcommandUD@removespaceUD@firstoftwodefUD@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@secondoftwostringexpandafter
                      UD@secondoftwoexpandafterexpandafterstring#1expandafter
                      UD@secondoftwostringexpandafterUD@firstoftwoexpandafterexpandafter
                      UD@secondoftwostringexpandafterexpandafterUD@firstoftwo %
                      UD@secondoftwoexpandafterexpandafterUD@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@secondoftwostringUD@CheckWhetherLeadingSpaceB.#1 %
                      %
                      newcommandUD@CheckWhetherLeadingSpaceB%
                      longdefUD@CheckWhetherLeadingSpaceB#1 %
                      expandafterUD@CheckWhetherNullexpandafterUD@secondoftwo#1%
                      UD@exchangeUD@firstoftwoUD@exchangeUD@secondoftwo%
                      UD@exchange expandafterexpandafterexpandafterexpandafter
                      expandafterexpandafterexpandafterexpandafterexpandafter
                      expandafterexpandafterUD@secondoftwoexpandafterstring%
                      %
                      %%-----------------------------------------------------------------------------
                      %% Extract first inner undelimited argument:
                      %%.............................................................................
                      %% UD@ExtractFirstArgABCDE yields A
                      %%
                      %% UD@ExtractFirstArgABCDE 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@CheckWhetherNullexpandafterUD@firstoftwo#1%
                      #1%
                      expandafterUD@ExtractFirstArgLoopexpandafterUD@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@trimleadspaceloopexpandafterUD@removespace#1%
                      %
                      UD@CheckWhetherNull#1 %
                      expandafterUD@CheckWhetherNullexpandafterUD@firstoftwo#1%
                      UD@exchange expandafterUD@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@GobbleToCommalongdefUD@GobbleToComma#1,%
                      newcommandUD@CheckWhetherNoComma[1]%
                      expandafterUD@CheckWhetherNullexpandafterUD@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@GobbleToDashlongdefUD@GobbleToDash#1-%
                      newcommandUD@CheckWhetherNoDash[1]%
                      expandafterUD@CheckWhetherNullexpandafterUD@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 expandafterexpandafterUD@removespace#1%
                      %
                      newcommandUD@SplitDashArg%
                      longdefUD@SplitDashArg#1-%
                      romannumeral0UD@exchange expandafterexpandafterUD@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@exchangeexpandafterexpandafter
                      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@exchangeexpandafterexpandafter
                      %
                      romannumeral0%
                      UD@exchange expandafterexpandafterexpandafter%
                      UD@RemoveSpacesAndOneLevelOfBraces#2%
                      %
                      %
                      expandaftermycommand@twoargumentsexpandafter%
                      romannumeral0%
                      UD@exchange expandafterexpandafterexpandafter%
                      UD@RemoveSpacesAndOneLevelOfBraces#1%
                      %
                      %
                      %
                      expandafterUD@exchangeexpandafterexpandafter%
                      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%
                      fboxtextttexpandafterstrip@prefixmeaningUD@tempa%
                      %
                      makeatother

                      parindent=0ex
                      parskip=smallskipamount
                      pagestyleempty%


                      begindocument
                      vspace*-3.5cm%
                      enlargethispage7cm%

                      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

                      enddocument


                      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

                      5,105618




                      5,105618





















                          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.



                          documentclassarticle
                          usepackagelistofitems
                          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%

                          begindocument

                          mycommandarg1, arg2

                          and

                          mycommandarg1, arg2-arg3

                          enddocument


                          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.



                            documentclassarticle
                            usepackagelistofitems
                            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%

                            begindocument

                            mycommandarg1, arg2

                            and

                            mycommandarg1, arg2-arg3

                            enddocument


                            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.



                              documentclassarticle
                              usepackagelistofitems
                              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%

                              begindocument

                              mycommandarg1, arg2

                              and

                              mycommandarg1, arg2-arg3

                              enddocument


                              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.



                              documentclassarticle
                              usepackagelistofitems
                              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%

                              begindocument

                              mycommandarg1, arg2

                              and

                              mycommandarg1, arg2-arg3

                              enddocument


                              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

                              157k9202411




                              157k9202411





















                                  1














                                  One more:



                                  documentclassarticle
                                  usepackagexstring
                                  defmycommand#1,#2 IfSubStr#2-[[#1],
                                  [StrBefore#2-]-[StrBehind#2-]] [[#1],[#2]]
                                  begindocument
                                  mycommand aaa,bbb-ccc
                                  mycommand aaa,bbb
                                  enddocument


                                  mwe






                                  share|improve this answer



























                                    1














                                    One more:



                                    documentclassarticle
                                    usepackagexstring
                                    defmycommand#1,#2 IfSubStr#2-[[#1],
                                    [StrBefore#2-]-[StrBehind#2-]] [[#1],[#2]]
                                    begindocument
                                    mycommand aaa,bbb-ccc
                                    mycommand aaa,bbb
                                    enddocument


                                    mwe






                                    share|improve this answer

























                                      1












                                      1








                                      1







                                      One more:



                                      documentclassarticle
                                      usepackagexstring
                                      defmycommand#1,#2 IfSubStr#2-[[#1],
                                      [StrBefore#2-]-[StrBehind#2-]] [[#1],[#2]]
                                      begindocument
                                      mycommand aaa,bbb-ccc
                                      mycommand aaa,bbb
                                      enddocument


                                      mwe






                                      share|improve this answer













                                      One more:



                                      documentclassarticle
                                      usepackagexstring
                                      defmycommand#1,#2 IfSubStr#2-[[#1],
                                      [StrBefore#2-]-[StrBehind#2-]] [[#1],[#2]]
                                      begindocument
                                      mycommand aaa,bbb-ccc
                                      mycommand aaa,bbb
                                      enddocument


                                      mwe







                                      share|improve this answer












                                      share|improve this answer



                                      share|improve this answer










                                      answered Feb 9 at 18:13









                                      FranFran

                                      52.8k6118182




                                      52.8k6118182



























                                          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

                                          How to check contact read email or not when send email to Individual?

                                          Bahrain

                                          Postfix configuration issue with fips on centos 7; mailgun relay