Pulling numbers out of a file name












6














A long time ago, I wanted to solve the problem where I would typeset my homework assignments, but copy the file "hw1.tex" to make "hw2.tex", and forget to change the title "Homework 1" at the top of the page.



So I wrote a function (that now I no longer 100% remember how it works, or maybe I got parts of it from a place like StackExchange and never did fully understand it):



usepackage{substr}
newcommand{hwnum}{BehindSubString{hw}{scantokensexpandafter{jobnamenoexpand}}}


Now I can make Homework hwnum the title. When I compile "hw1.tex", the title is "Homework 1", and when I compile "hw2.tex", the title becomes "Homework 2".



Minimal working example (assuming you first save it as a file with the appropriate name):



documentclass{article}

usepackage{substr}
newcommand{hwnum}{BehindSubString{hw}{scantokensexpandafter{jobnamenoexpand}}}

begin{document}

This is Homework hwnum.

end{document}


These days, I have to typeset more than just homework assignments, so I'd like to have this be a bit more flexible.




  1. It would be nicer, though not very important, if I didn't have to change the prefix "hw" in the command if I want to deal with filenames such as "day1.tex", "day2.tex", and so on.

  2. What I really want is to extract more than one number: for example, "Lecture 7" and "Chapter 3" (or whatever) from a filename such as "ch3lec7.tex".

  3. Putting these together, an ideal function would just be able to locate all the numbers in the filename, no matter which non-numbers they're separated by. The same function could pull out 3 and 7 whether it's given the filename "ch3lec7.tex" or "week3day7.tex".


What is a way for me to do at least #2, but also if possible #1 or #3?










share|improve this question





























    6














    A long time ago, I wanted to solve the problem where I would typeset my homework assignments, but copy the file "hw1.tex" to make "hw2.tex", and forget to change the title "Homework 1" at the top of the page.



    So I wrote a function (that now I no longer 100% remember how it works, or maybe I got parts of it from a place like StackExchange and never did fully understand it):



    usepackage{substr}
    newcommand{hwnum}{BehindSubString{hw}{scantokensexpandafter{jobnamenoexpand}}}


    Now I can make Homework hwnum the title. When I compile "hw1.tex", the title is "Homework 1", and when I compile "hw2.tex", the title becomes "Homework 2".



    Minimal working example (assuming you first save it as a file with the appropriate name):



    documentclass{article}

    usepackage{substr}
    newcommand{hwnum}{BehindSubString{hw}{scantokensexpandafter{jobnamenoexpand}}}

    begin{document}

    This is Homework hwnum.

    end{document}


    These days, I have to typeset more than just homework assignments, so I'd like to have this be a bit more flexible.




    1. It would be nicer, though not very important, if I didn't have to change the prefix "hw" in the command if I want to deal with filenames such as "day1.tex", "day2.tex", and so on.

    2. What I really want is to extract more than one number: for example, "Lecture 7" and "Chapter 3" (or whatever) from a filename such as "ch3lec7.tex".

    3. Putting these together, an ideal function would just be able to locate all the numbers in the filename, no matter which non-numbers they're separated by. The same function could pull out 3 and 7 whether it's given the filename "ch3lec7.tex" or "week3day7.tex".


    What is a way for me to do at least #2, but also if possible #1 or #3?










    share|improve this question



























      6












      6








      6







      A long time ago, I wanted to solve the problem where I would typeset my homework assignments, but copy the file "hw1.tex" to make "hw2.tex", and forget to change the title "Homework 1" at the top of the page.



      So I wrote a function (that now I no longer 100% remember how it works, or maybe I got parts of it from a place like StackExchange and never did fully understand it):



      usepackage{substr}
      newcommand{hwnum}{BehindSubString{hw}{scantokensexpandafter{jobnamenoexpand}}}


      Now I can make Homework hwnum the title. When I compile "hw1.tex", the title is "Homework 1", and when I compile "hw2.tex", the title becomes "Homework 2".



      Minimal working example (assuming you first save it as a file with the appropriate name):



      documentclass{article}

      usepackage{substr}
      newcommand{hwnum}{BehindSubString{hw}{scantokensexpandafter{jobnamenoexpand}}}

      begin{document}

      This is Homework hwnum.

      end{document}


      These days, I have to typeset more than just homework assignments, so I'd like to have this be a bit more flexible.




      1. It would be nicer, though not very important, if I didn't have to change the prefix "hw" in the command if I want to deal with filenames such as "day1.tex", "day2.tex", and so on.

      2. What I really want is to extract more than one number: for example, "Lecture 7" and "Chapter 3" (or whatever) from a filename such as "ch3lec7.tex".

      3. Putting these together, an ideal function would just be able to locate all the numbers in the filename, no matter which non-numbers they're separated by. The same function could pull out 3 and 7 whether it's given the filename "ch3lec7.tex" or "week3day7.tex".


      What is a way for me to do at least #2, but also if possible #1 or #3?










      share|improve this question















      A long time ago, I wanted to solve the problem where I would typeset my homework assignments, but copy the file "hw1.tex" to make "hw2.tex", and forget to change the title "Homework 1" at the top of the page.



      So I wrote a function (that now I no longer 100% remember how it works, or maybe I got parts of it from a place like StackExchange and never did fully understand it):



      usepackage{substr}
      newcommand{hwnum}{BehindSubString{hw}{scantokensexpandafter{jobnamenoexpand}}}


      Now I can make Homework hwnum the title. When I compile "hw1.tex", the title is "Homework 1", and when I compile "hw2.tex", the title becomes "Homework 2".



      Minimal working example (assuming you first save it as a file with the appropriate name):



      documentclass{article}

      usepackage{substr}
      newcommand{hwnum}{BehindSubString{hw}{scantokensexpandafter{jobnamenoexpand}}}

      begin{document}

      This is Homework hwnum.

      end{document}


      These days, I have to typeset more than just homework assignments, so I'd like to have this be a bit more flexible.




      1. It would be nicer, though not very important, if I didn't have to change the prefix "hw" in the command if I want to deal with filenames such as "day1.tex", "day2.tex", and so on.

      2. What I really want is to extract more than one number: for example, "Lecture 7" and "Chapter 3" (or whatever) from a filename such as "ch3lec7.tex".

      3. Putting these together, an ideal function would just be able to locate all the numbers in the filename, no matter which non-numbers they're separated by. The same function could pull out 3 and 7 whether it's given the filename "ch3lec7.tex" or "week3day7.tex".


      What is a way for me to do at least #2, but also if possible #1 or #3?







      strings jobname






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Dec 10 at 0:05

























      asked Dec 9 at 21:06









      Misha Lavrov

      1336




      1336






















          2 Answers
          2






          active

          oldest

          votes


















          6














          The code below uses regular expressions from LaTeX3 to extract all of the numbers in the filename and then makes them available as misha{1}, misha{2}, .... There is no error checking so, for example, if you have misha{100} in your document then this command will fail silently, doing nothing.



          If you save the code below as the file ch3lec7.tex then run it you will get the output:



          enter image description here



          Here is the code:



          documentclass{article}

          usepackage{expl3}
          ExplSyntaxOn
          cs_generate_variant:Nn regex_extract_all:nnN {nVN}
          seq_new:N l_misha_seq
          regex_extract_all:nVN {d+} c_sys_jobname_str l_misha_seq
          newcommandmisha[1]{seq_item:Nn l_misha_seq {#1}}
          ExplSyntaxOff

          begin{document}

          Chapter misha{1}, lecture misha{2}.

          end{document}


          The work is all done by the command regex_extract_all:nVN, which puts all of the numbers in jobname into an internal LaTeX3 sequence. (As egreg pointed out, LaTeX3 stores the filename in the string constant c_sys_jobname_str.) The command misha{k} prints the kth element of this sequence.






          share|improve this answer























          • When I try to compile this, I get the error Control sequence regex_extract_all:nnN undefined.
            – Misha Lavrov
            Dec 10 at 3:37






          • 2




            @MishaLavrov I suspect that you need to update your latex distribution. I think that the regular expression machinery was added to LaTeX in mid 2017. The code above compiles fine for me. I am using TeX Live 2018.
            – Andrew
            Dec 10 at 4:01












          • Updating my LaTeX distribution was something of an adventure, but I got there in the end and now everything works. Thanks for the quick answer that does everything I hoped for!
            – Misha Lavrov
            Dec 10 at 5:33



















          1














          Off the cuff I can offer four macros:





          1. UD@ExtractDigitSequences{<arbitrary token sequence>}

            This macro extracts all catcode-12-digit-sequences from <arbitrary token sequence>, nests each catcode-12-digit-sequence into curly braces.


          2. UD@ExtractKthDigitSequence{<number K>}{<arbitrary token sequence>}

            This macro extracts the K-th catcode-12-digit-sequence from <arbitrary token sequence>.


          3. UD@ExtractDigitSequencesFromJobname

            This macro extracts all catcode-12-digit-sequences from the expansion of jobname, nests each catcode-12-digit-sequence into curly braces.


          4. UD@ExtractKthDigitSequenceFromJobname{<number K>}

            This macro extracts the K-th catcode-12-digit-sequence from the expansion of jobname.


          Basically UD@ExtractDigitSequences{<arbitrary token sequence>} and UD@ExtractDigitSequencesFromJobname are wrappers for a recursive loop formed by the macro UD@extractDigitSequencesLoop.



          The gist of that recursive loop is:



          UD@extractDigitSequencesLoop processes three arguments:



          The first argument denotes the (remaining) <arbitrary token-sequence>.

          The second argument denotes the collection of brace-nested digit-sequences collected so far.

          The third argument denotes the collection of digits collected so far for the current digit-sequence.



          First the loop checks whether the (remaining) <arbitrary token-sequence> is empty.



          If so, you are done and the second argument will be delivered and in case the third argument is not empty, it will also be delivered, nested in braces.



          If not so, the loop will look at the first token of the (remaining) <arbitrary token-sequence>, hereby taking into account braces and spaces as cases that need special treatment.



          In case of the first token of the (remaining) <arbitrary token-sequence> being both a non-brace-token and a non-digit-token, the current digit sequence in argument 3 is finished and, if not empty, can be nested in braces and attached to argument 2 before calling the loop again with that token removed from the (remaining) <arbitrary token-sequence>.



          In case of the first token of the (remaining) <arbitrary token-sequence> being an opening-brace, the current digit sequence in argument 3 is finished and, if not empty, can be nested in braces and attached to argument 2. In this case we also need to attach to argument 2 the result of applying the entire routine on the brace-nested first component/on the leading undelimited argument of the (remaining) <arbitrary token-sequence> before calling the loop again with that undelimited argument removed from the (remaining) <arbitrary token-sequence>.



          (This case is important only as long as it is about extracting from arbitrary token sequences: The expansion of the jobname-primitive in any case does contain neither curly opening braces of category-code 1 nor closing braces of category code 2 but a collection of explicit character tokens that may contain explicit character tokens of category code 12(other but not with character code 32(space) and explicit character tokens of category code 10(space) and character code 32(space)=explicit non-funny space-tokens.)



          In case of the first token of the (remaining) <arbitrary token-sequence> being a digit-token, it needs to be attached to the current digit sequence in argument 3 before calling the loop again with that token removed from the (remaining) <arbitrary token-sequence>.



          Of course you also need routines for checking




          • whether an argument is empty.

          • whether an argument's first token is an opening brace.

          • whether an argument's first token is a space token.

          • whether an argument's first token is a digit-token.


          UD@ExtractKthDigitSequence{<number K>}{<arbitrary token sequence>} and UD@ExtractKthDigitSequenceFromJobname{<number K>} "feed" the result of carrying out that loop to another macro which is called UD@ExtractKthArg{<integer K>}{<list of undelimited args>} which in turn is a routine for delivering the K-th undelimited argument from a list of undelimited/brace-nested arguments.



          Everything is implemented so that it will also work in expansion-contexts like csname..endcsname.



          Neither do you need extensions like eTeX or LuaTeX, nor do you need any additional LaTeX2e packages like expl3 or substr or the like.



          documentclass{article}
          makeatletter
          %%=============================================================================
          %% Paraphernalia
          %%.............................................................................
          newcommandUD@firstoftwo[2]{#1}%
          newcommandUD@secondoftwo[2]{#2}%
          newcommandUD@Exchange[2]{#2#1}%
          newcommandUD@gobblespace{}UD@firstoftwo{defUD@gobblespace}{} {}%
          %%=============================================================================
          %% 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>}%
          %%
          %% Due to romannumeral-expansion the result is delivered after two
          %% expansion-steps.
          %%
          %% The gist of this macro comes from Robert R. Schneck's ifempty-macro:
          %% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
          %%
          %% Crank out the cases of string "hitting"
          %% - an opening-brace -> argument is not empty
          %% - a non-brace-token -> argument is not empty
          %% - a closing-brace -> argument is empty
          %%.............................................................................
          newcommandUD@CheckWhetherNull[1]{%
          romannumeral0expandafterUD@secondoftwostring{expandafter
          UD@secondoftwoexpandafter{expandafter{string#1}expandafter
          UD@secondoftwostring}expandafterUD@firstoftwoexpandafter{expandafter
          UD@secondoftwostring}expandafterexpandafterUD@firstoftwo{ }{}%
          UD@secondoftwo}{expandafterexpandafterUD@firstoftwo{ }{}UD@firstoftwo}%
          }%
          %%=============================================================================
          %% Check whether argument's first token is a catcode-1-character
          %%-----------------------------------------------------------------------------
          %% UD@CheckWhetherBrace{<Argument which is to be checked>}%
          %% {<Tokens to be delivered in case that argument
          %% which is to be checked has leading
          %% catcode-1-token>}%
          %% {<Tokens to be delivered in case that argument
          %% which is to be checked has no leading
          %% catcode-1-token>}%
          %%
          %% Due to romannumeral-expansion the result is delivered after two
          %% expansion-steps.
          %%
          %% Basically this is a variation of UD@CheckWhetherNull where non-emptiness
          %% is ensured so that you need to only crank out the cases of string "hitting"
          %% an opening-brace or a non-brace-token.
          %%.............................................................................
          newcommandUD@CheckWhetherBrace[1]{%
          romannumeral0expandafterUD@secondoftwoexpandafter{expandafter{%
          string#1.}expandafterUD@firstoftwoexpandafter{expandafter
          UD@secondoftwostring}expandafterexpandafterUD@firstoftwo{ }{}%
          UD@firstoftwo}{expandafterexpandafterUD@firstoftwo{ }{}UD@secondoftwo}%
          }%
          %%=============================================================================
          %% Check whether brace-balanced argument starts with a space-token
          %%-----------------------------------------------------------------------------
          %% UD@CheckWhetherLeadingSpace{<Argument which is to be checked>}%
          %% {<Tokens to be delivered in case <argument
          %% which is to be checked>'s 1st token is a
          %% space-token>}%
          %% {<Tokens to be delivered in case <argument
          %% which is to be checked>'s 1st token is not
          %% a space-token>}%
          %%
          %% Due to romannumeral-expansion the result is delivered after two
          %% expansion-steps.
          %%.............................................................................
          newcommandUD@CheckWhetherLeadingSpace[1]{%
          romannumeral0UD@CheckWhetherNull{#1}%
          {expandafterexpandafterUD@firstoftwo{ }{}UD@secondoftwo}%
          {expandafterUD@secondoftwostring{UD@CheckWhetherLeadingSpaceB.#1 }{}}%
          }%
          newcommandUD@CheckWhetherLeadingSpaceB{}%
          longdefUD@CheckWhetherLeadingSpaceB#1 {%
          expandafterUD@CheckWhetherNullexpandafter{UD@secondoftwo#1{}}%
          {UD@Exchange{UD@firstoftwo}}{UD@Exchange{UD@secondoftwo}}%
          {UD@Exchange{ }{expandafterexpandafterexpandafterexpandafter
          expandafterexpandafterexpandafter}expandafterexpandafter
          expandafter}expandafterUD@secondoftwoexpandafter{string}%
          }%
          %%=============================================================================
          %% Check whether argument does not contain "!" (unless nested in braces):
          %%-----------------------------------------------------------------------------
          %% UD@CheckWhetherNoExclam{<Argument which is to be checked>}%
          %% {<Tokens to be delivered in case <argument which is
          %% to be checked> does not contain !>}%
          %% {<Tokens to be delivered in case <argument which is
          %% to be checked> does contain !>
          %%.............................................................................
          newcommandUD@GobbleToExclam{}%
          longdefUD@GobbleToExclam#1!{}%
          newcommandUD@CheckWhetherNoExclam[1]{%
          expandafterUD@CheckWhetherNullexpandafter{UD@GobbleToExclam#1!}%
          }%
          %%=============================================================================
          %% Check whether argument is a single explicit character-token of
          %% category code 12 (other) that denotes digit:
          %%-----------------------------------------------------------------------------
          %% UD@CheckWhetherdigit{<Argument which is to be checked>}%
          %% {<Tokens to be delivered in case <argument which is
          %% to be checked> is a single catcode-12-digit>}%
          %% {<Tokens to be delivered in case <argument which is
          %% to be checked> is not a single catcode-12-digit>
          %%
          %% Due to romannumeral-expansion the result is delivered after two
          %% expansion-steps.
          %%.............................................................................
          newcommandUD@CheckWhetherdigitfork{}%
          longdefUD@CheckWhetherdigitfork#1!0!1!2!3!4!5!6!7!8!9!#2#3!!!!{#2}%
          newcommandUD@CheckWhetherdigit[1]{%
          romannumeral0%
          UD@CheckWhetherNoExclam{#1}{%
          UD@CheckWhetherdigitfork
          !#1!1!2!3!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
          !0!#1!2!3!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
          !0!1!#1!3!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
          !0!1!2!#1!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
          !0!1!2!3!#1!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
          !0!1!2!3!4!#1!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
          !0!1!2!3!4!5!#1!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
          !0!1!2!3!4!5!6!#1!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
          !0!1!2!3!4!5!6!7!#1!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
          !0!1!2!3!4!5!6!7!8!#1!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
          !0!1!2!3!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@secondoftwo}%
          !!!!%
          }{UD@firstoftwoexpandafter{} UD@secondoftwo}%
          }%
          %%=============================================================================
          %% Extract K-th inner undelimited argument:
          %%-----------------------------------------------------------------------------
          %% UD@ExtractKthArg{<integer K>}{<list of undelimited args>}
          %%
          %% In case there is no K-th argument in <list of indelimited args> :
          %% Does not deliver any token.
          %% In case there is a K-th argument in <list of indelimited args> :
          %% Does deliver that K-th argument with one level of braces removed.
          %%
          %% Examples:
          %%
          %% UD@ExtractKthArg{0}{ABCDE} yields: <nothing>
          %%
          %% UD@ExtractKthArg{3}{ABCDE} yields: C
          %%
          %% UD@ExtractKthArg{3}{AB{CD}E} yields: CD
          %%
          %% UD@ExtractKthArg{4}{{001}{002}{003}{004}{005}} yields: 004
          %%
          %% UD@ExtractKthArg{6}{{001}{002}{003}} yields: <nothing>
          %%
          %%
          %% Due to romannumeral-expansion the result is delivered after two
          %% expansion-steps.
          %%.............................................................................
          newcommandUD@ExtractKthArg[1]{%
          romannumeral0%
          % #1: <integer number K>
          expandafterUD@ExtractKthArgCheck
          expandafter{romannumeralnumbernumber#1 000}%
          }%
          newcommandUD@ExtractKthArgCheck[2]{%
          UD@CheckWhetherNull{#1}{ }{%
          expandafterUD@ExtractKthArgLoopexpandafter{UD@firstoftwo{}#1}{#2}%
          }%
          }%
          newcommandUD@ExtractKthArgLoop[2]{%
          UD@CheckWhetherNull{#2}{ }{%
          UD@CheckWhetherNull{#1}{%
          UD@ExtractFirstArgLoop{#2UD@SelDOm}%
          }{%
          expandafterUD@Exchangeexpandafter{expandafter{UD@firstoftwo{}#2}}%
          {expandafterUD@ExtractKthArgLoopexpandafter{UD@firstoftwo{}#1}}%
          }%
          }%
          }%
          newcommandUD@RemoveTillUD@SelDOm{}%
          longdefUD@RemoveTillUD@SelDOm#1#2UD@SelDOm{{#1}}%
          newcommandUD@ExtractFirstArgLoop[1]{%
          expandafterUD@CheckWhetherNullexpandafter{UD@firstoftwo{}#1}%
          {UD@firstoftwo{expandafter}{} UD@secondoftwo{}#1}%
          {expandafterUD@ExtractFirstArgLoopexpandafter{UD@RemoveTillUD@SelDOm#1}}%
          }%
          %%=============================================================================
          %% UD@ExtractDigitSequences{<token sequence>}
          %%-----------------------------------------------------------------------------
          %% Extracts sequences of explicit character tokens of category code 12
          %% that denote digits from <token sequence>, nests each such sequence
          %% into curly braces:
          %%
          %% E.g., UD@ExtractDigitSequences{00foo78Bar66}
          %% yields: {00}{78}{66}%
          %%
          %% E.g., UD@ExtractDigitSequences{00foo78Bar66Baz543BaT954}
          %% yields: {00}{78}{66}{543}{954}%
          %%
          %% Does not deliver any token in case <token sequence> does not contain
          %% explicit character-tokens of category code 12(other) that denote
          %% digits.
          %%
          %% Due to romannumeral-expansion the result is delivered after two
          %% expansion-steps.
          %%.............................................................................
          newcommandUD@ExtractDigitSequences[1]{%
          romannumeral0UD@extractDigitSequencesLoop{#1}{}{}%
          }%
          newcommandUD@extractDigitSequencesLoop[3]{%
          UD@CheckWhetherNull{#1}{%
          UD@CheckWhetherNull{#3}{ #2}{ #2{#3}}%
          }{%
          UD@CheckWhetherBrace{#1}{%
          expandafterUD@Exchangeexpandafter{%
          expandafter{romannumeral0%
          UD@CheckWhetherNull{#3}{UD@Exchange{{#2}}}{UD@Exchange{{#2{#3}}}}%
          {expandafterUD@extractDigitSequencesLoop
          expandafter{romannumeral0UD@ExtractKthArgCheck{m}{#1}}%
          }{}%
          }%
          }%
          {expandafterUD@extractDigitSequencesLoopexpandafter{UD@firstoftwo{}#1}}%
          {}%
          }{%
          UD@CheckWhetherLeadingSpace{#1}{%
          UD@CheckWhetherNull{#3}{UD@Exchange{{#2}}}{UD@Exchange{{#2{#3}}}}%
          {expandafterUD@extractDigitSequencesLoopexpandafter{UD@gobblespace#1}}%
          {}%
          }{%
          expandafterUD@CheckWhetherdigit
          expandafter{romannumeral0UD@ExtractKthArgCheck{m}{#1}}{%
          expandafterexpandafterexpandafterUD@Exchange
          expandafterexpandafterexpandafter{%
          expandafterexpandafterexpandafter{%
          expandafterUD@Exchange
          expandafter{romannumeral0UD@ExtractKthArgCheck{m}{#1}}{#3}%
          }%
          }%
          {expandafterUD@extractDigitSequencesLoopexpandafter{UD@firstoftwo{}#1}{#2}}%
          }{%
          UD@CheckWhetherNull{#3}{UD@Exchange{{#2}}}{UD@Exchange{{#2{#3}}}}%
          {expandafterUD@extractDigitSequencesLoopexpandafter{UD@firstoftwo{}#1}}%
          {}%
          }%
          }%
          }%
          }%
          }%
          %%=============================================================================
          %% UD@ExtractKthDigitSequence{<integer K>}{<token sequence>}
          %%-----------------------------------------------------------------------------
          %% Extracts the K-th sequence of explicit character-tokens of category
          %% code 12 (other) that denote digits from <token sequence> if existent.
          %% Otherwise doesn't deliver any token.
          %%
          %% Due to romannumeral-expansion the result is delivered after two
          %% expansion-steps.
          %%.............................................................................
          newcommandUD@ExtractKthDigitSequence[2]{%
          romannumeral0%
          expandafterUD@Exchangeexpandafter{%
          expandafter{romannumeral0UD@extractDigitSequencesLoop{#2}{}{}}%
          }{%
          expandafterUD@ExtractKthArgCheck
          expandafter{romannumeralnumbernumber#1 000}%
          }%
          }%
          %%=============================================================================
          %% UD@ExtractDigitSequencesFromJobname
          %%-----------------------------------------------------------------------------
          %% Extracts sequences of explicit character tokens of category code 12
          %% that denote digits from the top-level-expansion of the control-word-
          %% token jobname, nests each such sequence into curly braces:
          %%
          %% E.g., if jobname = 00foo78Bar66, then
          %%
          %% UD@ExtractDigitSequencesFromJobname
          %%
          %% yields: {00}{78}{66}%
          %%
          %% E.g., if jobname = 00foo78Bar66Baz543BaT954, then
          %%
          %% UD@ExtractDigitSequencesFromJobname
          %%
          %% yields: {00}{78}{66}{543}{954}%
          %%
          %% Does not deliver any token in case <token sequence> does not contain
          %% explicit character-tokens of category code 12(other) that denote
          %% digits.
          %%
          %% Due to romannumeral-expansion the result is delivered after two
          %% expansion-steps.
          %%.............................................................................
          newcommandUD@ExtractDigitSequencesFromJobname{%
          romannumeral0%
          expandafterUD@extractDigitSequencesLoopexpandafter{jobname}{}{}%
          }%
          %%=============================================================================
          %% UD@ExtractKthDigitSequenceFromJobname{<integer K>}
          %%-----------------------------------------------------------------------------
          %% Extracts the K-th sequence of explicit character-tokens of category
          %% code 12 (other) that denote digits from the top-level-expansion of the
          %% control-word-token jobname if existent.
          %% Otherwise doesn't deliver any token.
          %%
          %% Due to romannumeral-expansion the result is delivered after two
          %% expansion-steps.
          %%.............................................................................
          newcommandUD@ExtractKthDigitSequenceFromJobname[1]{%
          romannumeral
          expandafterUD@Exchangeexpandafter{expandafter{jobname}}%
          {expandafterUD@secondoftwoUD@ExtractKthDigitSequence{#1}}%
          }%
          makeatother

          begin{document}

          makeatletter

          defbraceshowloop#1{%
          ifxrelax#1expandafterUD@firstoftwoelseexpandafterUD@secondoftwofi
          {}{{#1}braceshowloop}%
          }%

          noindent
          verb|UD@ExtractDigitSequences{{{32}54{}t 65zk_+} 8}|:
          expandafterexpandafterexpandafterbraceshowloop
          UD@ExtractDigitSequences{{{32}54{}t 65zk_+} 8}relax\
          verb|UD@ExtractKthDigitSequence{-1}{{{32}54{}t 65zk_+} 8}|:
          UD@ExtractKthDigitSequence{-1}{{{32}54{}t 65zk_+} 8}\
          verb|UD@ExtractKthDigitSequence{0}{{{32}54{}t 65zk_+} 8}|:
          UD@ExtractKthDigitSequence{0}{{{32}54{}t 65zk_+} 8}\
          verb|UD@ExtractKthDigitSequence{1}{{{32}54{}t 65zk_+} 8}|:
          UD@ExtractKthDigitSequence{1}{{{32}54{}t 65zk_+} 8}\
          verb|UD@ExtractKthDigitSequence{2}{{{32}54{}t 65zk_+} 8}|:
          UD@ExtractKthDigitSequence{2}{{{32}54{}t 65zk_+} 8}\
          verb|UD@ExtractKthDigitSequence{3}{{{32}54{}t 65zk_+} 8}|:
          UD@ExtractKthDigitSequence{3}{{{32}54{}t 65zk_+} 8}\
          verb|UD@ExtractKthDigitSequence{4}{{{32}54{}t 65zk_+} 8}|:
          UD@ExtractKthDigitSequence{4}{{{32}54{}t 65zk_+} 8}\
          verb|UD@ExtractKthDigitSequence{5}{{{32}54{}t 65zk_+} 8}|:
          UD@ExtractKthDigitSequence{5}{{{32}54{}t 65zk_+} 8}\
          verb|jobname|:
          jobname\
          verb|UD@ExtractDigitSequencesFromJobname|:
          expandafterexpandafterexpandafterbraceshowloop
          UD@ExtractDigitSequencesFromJobnamerelax\
          verb|UD@ExtractKthDigitSequenceFromJobname{-1}|:
          UD@ExtractKthDigitSequenceFromJobname{-1}\
          verb|UD@ExtractKthDigitSequenceFromJobname{0}|:
          UD@ExtractKthDigitSequenceFromJobname{0}\
          verb|UD@ExtractKthDigitSequenceFromJobname{1}|:
          UD@ExtractKthDigitSequenceFromJobname{1}\
          verb|UD@ExtractKthDigitSequenceFromJobname{2}|:
          UD@ExtractKthDigitSequenceFromJobname{2}\
          verb|UD@ExtractKthDigitSequenceFromJobname{3}|:
          UD@ExtractKthDigitSequenceFromJobname{3}\
          verb|UD@ExtractKthDigitSequenceFromJobname{4}|:
          UD@ExtractKthDigitSequenceFromJobname{4}\
          verb|UD@ExtractKthDigitSequenceFromJobname{5}|:
          UD@ExtractKthDigitSequenceFromJobname{5}\
          verb|UD@ExtractKthDigitSequenceFromJobname{6}|:
          UD@ExtractKthDigitSequenceFromJobname{6}\

          end{document}


          enter image description here






          share|improve this answer























            Your Answer








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

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

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


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f464025%2fpulling-numbers-out-of-a-file-name%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            6














            The code below uses regular expressions from LaTeX3 to extract all of the numbers in the filename and then makes them available as misha{1}, misha{2}, .... There is no error checking so, for example, if you have misha{100} in your document then this command will fail silently, doing nothing.



            If you save the code below as the file ch3lec7.tex then run it you will get the output:



            enter image description here



            Here is the code:



            documentclass{article}

            usepackage{expl3}
            ExplSyntaxOn
            cs_generate_variant:Nn regex_extract_all:nnN {nVN}
            seq_new:N l_misha_seq
            regex_extract_all:nVN {d+} c_sys_jobname_str l_misha_seq
            newcommandmisha[1]{seq_item:Nn l_misha_seq {#1}}
            ExplSyntaxOff

            begin{document}

            Chapter misha{1}, lecture misha{2}.

            end{document}


            The work is all done by the command regex_extract_all:nVN, which puts all of the numbers in jobname into an internal LaTeX3 sequence. (As egreg pointed out, LaTeX3 stores the filename in the string constant c_sys_jobname_str.) The command misha{k} prints the kth element of this sequence.






            share|improve this answer























            • When I try to compile this, I get the error Control sequence regex_extract_all:nnN undefined.
              – Misha Lavrov
              Dec 10 at 3:37






            • 2




              @MishaLavrov I suspect that you need to update your latex distribution. I think that the regular expression machinery was added to LaTeX in mid 2017. The code above compiles fine for me. I am using TeX Live 2018.
              – Andrew
              Dec 10 at 4:01












            • Updating my LaTeX distribution was something of an adventure, but I got there in the end and now everything works. Thanks for the quick answer that does everything I hoped for!
              – Misha Lavrov
              Dec 10 at 5:33
















            6














            The code below uses regular expressions from LaTeX3 to extract all of the numbers in the filename and then makes them available as misha{1}, misha{2}, .... There is no error checking so, for example, if you have misha{100} in your document then this command will fail silently, doing nothing.



            If you save the code below as the file ch3lec7.tex then run it you will get the output:



            enter image description here



            Here is the code:



            documentclass{article}

            usepackage{expl3}
            ExplSyntaxOn
            cs_generate_variant:Nn regex_extract_all:nnN {nVN}
            seq_new:N l_misha_seq
            regex_extract_all:nVN {d+} c_sys_jobname_str l_misha_seq
            newcommandmisha[1]{seq_item:Nn l_misha_seq {#1}}
            ExplSyntaxOff

            begin{document}

            Chapter misha{1}, lecture misha{2}.

            end{document}


            The work is all done by the command regex_extract_all:nVN, which puts all of the numbers in jobname into an internal LaTeX3 sequence. (As egreg pointed out, LaTeX3 stores the filename in the string constant c_sys_jobname_str.) The command misha{k} prints the kth element of this sequence.






            share|improve this answer























            • When I try to compile this, I get the error Control sequence regex_extract_all:nnN undefined.
              – Misha Lavrov
              Dec 10 at 3:37






            • 2




              @MishaLavrov I suspect that you need to update your latex distribution. I think that the regular expression machinery was added to LaTeX in mid 2017. The code above compiles fine for me. I am using TeX Live 2018.
              – Andrew
              Dec 10 at 4:01












            • Updating my LaTeX distribution was something of an adventure, but I got there in the end and now everything works. Thanks for the quick answer that does everything I hoped for!
              – Misha Lavrov
              Dec 10 at 5:33














            6












            6








            6






            The code below uses regular expressions from LaTeX3 to extract all of the numbers in the filename and then makes them available as misha{1}, misha{2}, .... There is no error checking so, for example, if you have misha{100} in your document then this command will fail silently, doing nothing.



            If you save the code below as the file ch3lec7.tex then run it you will get the output:



            enter image description here



            Here is the code:



            documentclass{article}

            usepackage{expl3}
            ExplSyntaxOn
            cs_generate_variant:Nn regex_extract_all:nnN {nVN}
            seq_new:N l_misha_seq
            regex_extract_all:nVN {d+} c_sys_jobname_str l_misha_seq
            newcommandmisha[1]{seq_item:Nn l_misha_seq {#1}}
            ExplSyntaxOff

            begin{document}

            Chapter misha{1}, lecture misha{2}.

            end{document}


            The work is all done by the command regex_extract_all:nVN, which puts all of the numbers in jobname into an internal LaTeX3 sequence. (As egreg pointed out, LaTeX3 stores the filename in the string constant c_sys_jobname_str.) The command misha{k} prints the kth element of this sequence.






            share|improve this answer














            The code below uses regular expressions from LaTeX3 to extract all of the numbers in the filename and then makes them available as misha{1}, misha{2}, .... There is no error checking so, for example, if you have misha{100} in your document then this command will fail silently, doing nothing.



            If you save the code below as the file ch3lec7.tex then run it you will get the output:



            enter image description here



            Here is the code:



            documentclass{article}

            usepackage{expl3}
            ExplSyntaxOn
            cs_generate_variant:Nn regex_extract_all:nnN {nVN}
            seq_new:N l_misha_seq
            regex_extract_all:nVN {d+} c_sys_jobname_str l_misha_seq
            newcommandmisha[1]{seq_item:Nn l_misha_seq {#1}}
            ExplSyntaxOff

            begin{document}

            Chapter misha{1}, lecture misha{2}.

            end{document}


            The work is all done by the command regex_extract_all:nVN, which puts all of the numbers in jobname into an internal LaTeX3 sequence. (As egreg pointed out, LaTeX3 stores the filename in the string constant c_sys_jobname_str.) The command misha{k} prints the kth element of this sequence.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Dec 10 at 1:17

























            answered Dec 10 at 0:03









            Andrew

            30.4k34380




            30.4k34380












            • When I try to compile this, I get the error Control sequence regex_extract_all:nnN undefined.
              – Misha Lavrov
              Dec 10 at 3:37






            • 2




              @MishaLavrov I suspect that you need to update your latex distribution. I think that the regular expression machinery was added to LaTeX in mid 2017. The code above compiles fine for me. I am using TeX Live 2018.
              – Andrew
              Dec 10 at 4:01












            • Updating my LaTeX distribution was something of an adventure, but I got there in the end and now everything works. Thanks for the quick answer that does everything I hoped for!
              – Misha Lavrov
              Dec 10 at 5:33


















            • When I try to compile this, I get the error Control sequence regex_extract_all:nnN undefined.
              – Misha Lavrov
              Dec 10 at 3:37






            • 2




              @MishaLavrov I suspect that you need to update your latex distribution. I think that the regular expression machinery was added to LaTeX in mid 2017. The code above compiles fine for me. I am using TeX Live 2018.
              – Andrew
              Dec 10 at 4:01












            • Updating my LaTeX distribution was something of an adventure, but I got there in the end and now everything works. Thanks for the quick answer that does everything I hoped for!
              – Misha Lavrov
              Dec 10 at 5:33
















            When I try to compile this, I get the error Control sequence regex_extract_all:nnN undefined.
            – Misha Lavrov
            Dec 10 at 3:37




            When I try to compile this, I get the error Control sequence regex_extract_all:nnN undefined.
            – Misha Lavrov
            Dec 10 at 3:37




            2




            2




            @MishaLavrov I suspect that you need to update your latex distribution. I think that the regular expression machinery was added to LaTeX in mid 2017. The code above compiles fine for me. I am using TeX Live 2018.
            – Andrew
            Dec 10 at 4:01






            @MishaLavrov I suspect that you need to update your latex distribution. I think that the regular expression machinery was added to LaTeX in mid 2017. The code above compiles fine for me. I am using TeX Live 2018.
            – Andrew
            Dec 10 at 4:01














            Updating my LaTeX distribution was something of an adventure, but I got there in the end and now everything works. Thanks for the quick answer that does everything I hoped for!
            – Misha Lavrov
            Dec 10 at 5:33




            Updating my LaTeX distribution was something of an adventure, but I got there in the end and now everything works. Thanks for the quick answer that does everything I hoped for!
            – Misha Lavrov
            Dec 10 at 5:33











            1














            Off the cuff I can offer four macros:





            1. UD@ExtractDigitSequences{<arbitrary token sequence>}

              This macro extracts all catcode-12-digit-sequences from <arbitrary token sequence>, nests each catcode-12-digit-sequence into curly braces.


            2. UD@ExtractKthDigitSequence{<number K>}{<arbitrary token sequence>}

              This macro extracts the K-th catcode-12-digit-sequence from <arbitrary token sequence>.


            3. UD@ExtractDigitSequencesFromJobname

              This macro extracts all catcode-12-digit-sequences from the expansion of jobname, nests each catcode-12-digit-sequence into curly braces.


            4. UD@ExtractKthDigitSequenceFromJobname{<number K>}

              This macro extracts the K-th catcode-12-digit-sequence from the expansion of jobname.


            Basically UD@ExtractDigitSequences{<arbitrary token sequence>} and UD@ExtractDigitSequencesFromJobname are wrappers for a recursive loop formed by the macro UD@extractDigitSequencesLoop.



            The gist of that recursive loop is:



            UD@extractDigitSequencesLoop processes three arguments:



            The first argument denotes the (remaining) <arbitrary token-sequence>.

            The second argument denotes the collection of brace-nested digit-sequences collected so far.

            The third argument denotes the collection of digits collected so far for the current digit-sequence.



            First the loop checks whether the (remaining) <arbitrary token-sequence> is empty.



            If so, you are done and the second argument will be delivered and in case the third argument is not empty, it will also be delivered, nested in braces.



            If not so, the loop will look at the first token of the (remaining) <arbitrary token-sequence>, hereby taking into account braces and spaces as cases that need special treatment.



            In case of the first token of the (remaining) <arbitrary token-sequence> being both a non-brace-token and a non-digit-token, the current digit sequence in argument 3 is finished and, if not empty, can be nested in braces and attached to argument 2 before calling the loop again with that token removed from the (remaining) <arbitrary token-sequence>.



            In case of the first token of the (remaining) <arbitrary token-sequence> being an opening-brace, the current digit sequence in argument 3 is finished and, if not empty, can be nested in braces and attached to argument 2. In this case we also need to attach to argument 2 the result of applying the entire routine on the brace-nested first component/on the leading undelimited argument of the (remaining) <arbitrary token-sequence> before calling the loop again with that undelimited argument removed from the (remaining) <arbitrary token-sequence>.



            (This case is important only as long as it is about extracting from arbitrary token sequences: The expansion of the jobname-primitive in any case does contain neither curly opening braces of category-code 1 nor closing braces of category code 2 but a collection of explicit character tokens that may contain explicit character tokens of category code 12(other but not with character code 32(space) and explicit character tokens of category code 10(space) and character code 32(space)=explicit non-funny space-tokens.)



            In case of the first token of the (remaining) <arbitrary token-sequence> being a digit-token, it needs to be attached to the current digit sequence in argument 3 before calling the loop again with that token removed from the (remaining) <arbitrary token-sequence>.



            Of course you also need routines for checking




            • whether an argument is empty.

            • whether an argument's first token is an opening brace.

            • whether an argument's first token is a space token.

            • whether an argument's first token is a digit-token.


            UD@ExtractKthDigitSequence{<number K>}{<arbitrary token sequence>} and UD@ExtractKthDigitSequenceFromJobname{<number K>} "feed" the result of carrying out that loop to another macro which is called UD@ExtractKthArg{<integer K>}{<list of undelimited args>} which in turn is a routine for delivering the K-th undelimited argument from a list of undelimited/brace-nested arguments.



            Everything is implemented so that it will also work in expansion-contexts like csname..endcsname.



            Neither do you need extensions like eTeX or LuaTeX, nor do you need any additional LaTeX2e packages like expl3 or substr or the like.



            documentclass{article}
            makeatletter
            %%=============================================================================
            %% Paraphernalia
            %%.............................................................................
            newcommandUD@firstoftwo[2]{#1}%
            newcommandUD@secondoftwo[2]{#2}%
            newcommandUD@Exchange[2]{#2#1}%
            newcommandUD@gobblespace{}UD@firstoftwo{defUD@gobblespace}{} {}%
            %%=============================================================================
            %% 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>}%
            %%
            %% Due to romannumeral-expansion the result is delivered after two
            %% expansion-steps.
            %%
            %% The gist of this macro comes from Robert R. Schneck's ifempty-macro:
            %% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
            %%
            %% Crank out the cases of string "hitting"
            %% - an opening-brace -> argument is not empty
            %% - a non-brace-token -> argument is not empty
            %% - a closing-brace -> argument is empty
            %%.............................................................................
            newcommandUD@CheckWhetherNull[1]{%
            romannumeral0expandafterUD@secondoftwostring{expandafter
            UD@secondoftwoexpandafter{expandafter{string#1}expandafter
            UD@secondoftwostring}expandafterUD@firstoftwoexpandafter{expandafter
            UD@secondoftwostring}expandafterexpandafterUD@firstoftwo{ }{}%
            UD@secondoftwo}{expandafterexpandafterUD@firstoftwo{ }{}UD@firstoftwo}%
            }%
            %%=============================================================================
            %% Check whether argument's first token is a catcode-1-character
            %%-----------------------------------------------------------------------------
            %% UD@CheckWhetherBrace{<Argument which is to be checked>}%
            %% {<Tokens to be delivered in case that argument
            %% which is to be checked has leading
            %% catcode-1-token>}%
            %% {<Tokens to be delivered in case that argument
            %% which is to be checked has no leading
            %% catcode-1-token>}%
            %%
            %% Due to romannumeral-expansion the result is delivered after two
            %% expansion-steps.
            %%
            %% Basically this is a variation of UD@CheckWhetherNull where non-emptiness
            %% is ensured so that you need to only crank out the cases of string "hitting"
            %% an opening-brace or a non-brace-token.
            %%.............................................................................
            newcommandUD@CheckWhetherBrace[1]{%
            romannumeral0expandafterUD@secondoftwoexpandafter{expandafter{%
            string#1.}expandafterUD@firstoftwoexpandafter{expandafter
            UD@secondoftwostring}expandafterexpandafterUD@firstoftwo{ }{}%
            UD@firstoftwo}{expandafterexpandafterUD@firstoftwo{ }{}UD@secondoftwo}%
            }%
            %%=============================================================================
            %% Check whether brace-balanced argument starts with a space-token
            %%-----------------------------------------------------------------------------
            %% UD@CheckWhetherLeadingSpace{<Argument which is to be checked>}%
            %% {<Tokens to be delivered in case <argument
            %% which is to be checked>'s 1st token is a
            %% space-token>}%
            %% {<Tokens to be delivered in case <argument
            %% which is to be checked>'s 1st token is not
            %% a space-token>}%
            %%
            %% Due to romannumeral-expansion the result is delivered after two
            %% expansion-steps.
            %%.............................................................................
            newcommandUD@CheckWhetherLeadingSpace[1]{%
            romannumeral0UD@CheckWhetherNull{#1}%
            {expandafterexpandafterUD@firstoftwo{ }{}UD@secondoftwo}%
            {expandafterUD@secondoftwostring{UD@CheckWhetherLeadingSpaceB.#1 }{}}%
            }%
            newcommandUD@CheckWhetherLeadingSpaceB{}%
            longdefUD@CheckWhetherLeadingSpaceB#1 {%
            expandafterUD@CheckWhetherNullexpandafter{UD@secondoftwo#1{}}%
            {UD@Exchange{UD@firstoftwo}}{UD@Exchange{UD@secondoftwo}}%
            {UD@Exchange{ }{expandafterexpandafterexpandafterexpandafter
            expandafterexpandafterexpandafter}expandafterexpandafter
            expandafter}expandafterUD@secondoftwoexpandafter{string}%
            }%
            %%=============================================================================
            %% Check whether argument does not contain "!" (unless nested in braces):
            %%-----------------------------------------------------------------------------
            %% UD@CheckWhetherNoExclam{<Argument which is to be checked>}%
            %% {<Tokens to be delivered in case <argument which is
            %% to be checked> does not contain !>}%
            %% {<Tokens to be delivered in case <argument which is
            %% to be checked> does contain !>
            %%.............................................................................
            newcommandUD@GobbleToExclam{}%
            longdefUD@GobbleToExclam#1!{}%
            newcommandUD@CheckWhetherNoExclam[1]{%
            expandafterUD@CheckWhetherNullexpandafter{UD@GobbleToExclam#1!}%
            }%
            %%=============================================================================
            %% Check whether argument is a single explicit character-token of
            %% category code 12 (other) that denotes digit:
            %%-----------------------------------------------------------------------------
            %% UD@CheckWhetherdigit{<Argument which is to be checked>}%
            %% {<Tokens to be delivered in case <argument which is
            %% to be checked> is a single catcode-12-digit>}%
            %% {<Tokens to be delivered in case <argument which is
            %% to be checked> is not a single catcode-12-digit>
            %%
            %% Due to romannumeral-expansion the result is delivered after two
            %% expansion-steps.
            %%.............................................................................
            newcommandUD@CheckWhetherdigitfork{}%
            longdefUD@CheckWhetherdigitfork#1!0!1!2!3!4!5!6!7!8!9!#2#3!!!!{#2}%
            newcommandUD@CheckWhetherdigit[1]{%
            romannumeral0%
            UD@CheckWhetherNoExclam{#1}{%
            UD@CheckWhetherdigitfork
            !#1!1!2!3!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
            !0!#1!2!3!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
            !0!1!#1!3!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
            !0!1!2!#1!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
            !0!1!2!3!#1!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
            !0!1!2!3!4!#1!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
            !0!1!2!3!4!5!#1!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
            !0!1!2!3!4!5!6!#1!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
            !0!1!2!3!4!5!6!7!#1!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
            !0!1!2!3!4!5!6!7!8!#1!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
            !0!1!2!3!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@secondoftwo}%
            !!!!%
            }{UD@firstoftwoexpandafter{} UD@secondoftwo}%
            }%
            %%=============================================================================
            %% Extract K-th inner undelimited argument:
            %%-----------------------------------------------------------------------------
            %% UD@ExtractKthArg{<integer K>}{<list of undelimited args>}
            %%
            %% In case there is no K-th argument in <list of indelimited args> :
            %% Does not deliver any token.
            %% In case there is a K-th argument in <list of indelimited args> :
            %% Does deliver that K-th argument with one level of braces removed.
            %%
            %% Examples:
            %%
            %% UD@ExtractKthArg{0}{ABCDE} yields: <nothing>
            %%
            %% UD@ExtractKthArg{3}{ABCDE} yields: C
            %%
            %% UD@ExtractKthArg{3}{AB{CD}E} yields: CD
            %%
            %% UD@ExtractKthArg{4}{{001}{002}{003}{004}{005}} yields: 004
            %%
            %% UD@ExtractKthArg{6}{{001}{002}{003}} yields: <nothing>
            %%
            %%
            %% Due to romannumeral-expansion the result is delivered after two
            %% expansion-steps.
            %%.............................................................................
            newcommandUD@ExtractKthArg[1]{%
            romannumeral0%
            % #1: <integer number K>
            expandafterUD@ExtractKthArgCheck
            expandafter{romannumeralnumbernumber#1 000}%
            }%
            newcommandUD@ExtractKthArgCheck[2]{%
            UD@CheckWhetherNull{#1}{ }{%
            expandafterUD@ExtractKthArgLoopexpandafter{UD@firstoftwo{}#1}{#2}%
            }%
            }%
            newcommandUD@ExtractKthArgLoop[2]{%
            UD@CheckWhetherNull{#2}{ }{%
            UD@CheckWhetherNull{#1}{%
            UD@ExtractFirstArgLoop{#2UD@SelDOm}%
            }{%
            expandafterUD@Exchangeexpandafter{expandafter{UD@firstoftwo{}#2}}%
            {expandafterUD@ExtractKthArgLoopexpandafter{UD@firstoftwo{}#1}}%
            }%
            }%
            }%
            newcommandUD@RemoveTillUD@SelDOm{}%
            longdefUD@RemoveTillUD@SelDOm#1#2UD@SelDOm{{#1}}%
            newcommandUD@ExtractFirstArgLoop[1]{%
            expandafterUD@CheckWhetherNullexpandafter{UD@firstoftwo{}#1}%
            {UD@firstoftwo{expandafter}{} UD@secondoftwo{}#1}%
            {expandafterUD@ExtractFirstArgLoopexpandafter{UD@RemoveTillUD@SelDOm#1}}%
            }%
            %%=============================================================================
            %% UD@ExtractDigitSequences{<token sequence>}
            %%-----------------------------------------------------------------------------
            %% Extracts sequences of explicit character tokens of category code 12
            %% that denote digits from <token sequence>, nests each such sequence
            %% into curly braces:
            %%
            %% E.g., UD@ExtractDigitSequences{00foo78Bar66}
            %% yields: {00}{78}{66}%
            %%
            %% E.g., UD@ExtractDigitSequences{00foo78Bar66Baz543BaT954}
            %% yields: {00}{78}{66}{543}{954}%
            %%
            %% Does not deliver any token in case <token sequence> does not contain
            %% explicit character-tokens of category code 12(other) that denote
            %% digits.
            %%
            %% Due to romannumeral-expansion the result is delivered after two
            %% expansion-steps.
            %%.............................................................................
            newcommandUD@ExtractDigitSequences[1]{%
            romannumeral0UD@extractDigitSequencesLoop{#1}{}{}%
            }%
            newcommandUD@extractDigitSequencesLoop[3]{%
            UD@CheckWhetherNull{#1}{%
            UD@CheckWhetherNull{#3}{ #2}{ #2{#3}}%
            }{%
            UD@CheckWhetherBrace{#1}{%
            expandafterUD@Exchangeexpandafter{%
            expandafter{romannumeral0%
            UD@CheckWhetherNull{#3}{UD@Exchange{{#2}}}{UD@Exchange{{#2{#3}}}}%
            {expandafterUD@extractDigitSequencesLoop
            expandafter{romannumeral0UD@ExtractKthArgCheck{m}{#1}}%
            }{}%
            }%
            }%
            {expandafterUD@extractDigitSequencesLoopexpandafter{UD@firstoftwo{}#1}}%
            {}%
            }{%
            UD@CheckWhetherLeadingSpace{#1}{%
            UD@CheckWhetherNull{#3}{UD@Exchange{{#2}}}{UD@Exchange{{#2{#3}}}}%
            {expandafterUD@extractDigitSequencesLoopexpandafter{UD@gobblespace#1}}%
            {}%
            }{%
            expandafterUD@CheckWhetherdigit
            expandafter{romannumeral0UD@ExtractKthArgCheck{m}{#1}}{%
            expandafterexpandafterexpandafterUD@Exchange
            expandafterexpandafterexpandafter{%
            expandafterexpandafterexpandafter{%
            expandafterUD@Exchange
            expandafter{romannumeral0UD@ExtractKthArgCheck{m}{#1}}{#3}%
            }%
            }%
            {expandafterUD@extractDigitSequencesLoopexpandafter{UD@firstoftwo{}#1}{#2}}%
            }{%
            UD@CheckWhetherNull{#3}{UD@Exchange{{#2}}}{UD@Exchange{{#2{#3}}}}%
            {expandafterUD@extractDigitSequencesLoopexpandafter{UD@firstoftwo{}#1}}%
            {}%
            }%
            }%
            }%
            }%
            }%
            %%=============================================================================
            %% UD@ExtractKthDigitSequence{<integer K>}{<token sequence>}
            %%-----------------------------------------------------------------------------
            %% Extracts the K-th sequence of explicit character-tokens of category
            %% code 12 (other) that denote digits from <token sequence> if existent.
            %% Otherwise doesn't deliver any token.
            %%
            %% Due to romannumeral-expansion the result is delivered after two
            %% expansion-steps.
            %%.............................................................................
            newcommandUD@ExtractKthDigitSequence[2]{%
            romannumeral0%
            expandafterUD@Exchangeexpandafter{%
            expandafter{romannumeral0UD@extractDigitSequencesLoop{#2}{}{}}%
            }{%
            expandafterUD@ExtractKthArgCheck
            expandafter{romannumeralnumbernumber#1 000}%
            }%
            }%
            %%=============================================================================
            %% UD@ExtractDigitSequencesFromJobname
            %%-----------------------------------------------------------------------------
            %% Extracts sequences of explicit character tokens of category code 12
            %% that denote digits from the top-level-expansion of the control-word-
            %% token jobname, nests each such sequence into curly braces:
            %%
            %% E.g., if jobname = 00foo78Bar66, then
            %%
            %% UD@ExtractDigitSequencesFromJobname
            %%
            %% yields: {00}{78}{66}%
            %%
            %% E.g., if jobname = 00foo78Bar66Baz543BaT954, then
            %%
            %% UD@ExtractDigitSequencesFromJobname
            %%
            %% yields: {00}{78}{66}{543}{954}%
            %%
            %% Does not deliver any token in case <token sequence> does not contain
            %% explicit character-tokens of category code 12(other) that denote
            %% digits.
            %%
            %% Due to romannumeral-expansion the result is delivered after two
            %% expansion-steps.
            %%.............................................................................
            newcommandUD@ExtractDigitSequencesFromJobname{%
            romannumeral0%
            expandafterUD@extractDigitSequencesLoopexpandafter{jobname}{}{}%
            }%
            %%=============================================================================
            %% UD@ExtractKthDigitSequenceFromJobname{<integer K>}
            %%-----------------------------------------------------------------------------
            %% Extracts the K-th sequence of explicit character-tokens of category
            %% code 12 (other) that denote digits from the top-level-expansion of the
            %% control-word-token jobname if existent.
            %% Otherwise doesn't deliver any token.
            %%
            %% Due to romannumeral-expansion the result is delivered after two
            %% expansion-steps.
            %%.............................................................................
            newcommandUD@ExtractKthDigitSequenceFromJobname[1]{%
            romannumeral
            expandafterUD@Exchangeexpandafter{expandafter{jobname}}%
            {expandafterUD@secondoftwoUD@ExtractKthDigitSequence{#1}}%
            }%
            makeatother

            begin{document}

            makeatletter

            defbraceshowloop#1{%
            ifxrelax#1expandafterUD@firstoftwoelseexpandafterUD@secondoftwofi
            {}{{#1}braceshowloop}%
            }%

            noindent
            verb|UD@ExtractDigitSequences{{{32}54{}t 65zk_+} 8}|:
            expandafterexpandafterexpandafterbraceshowloop
            UD@ExtractDigitSequences{{{32}54{}t 65zk_+} 8}relax\
            verb|UD@ExtractKthDigitSequence{-1}{{{32}54{}t 65zk_+} 8}|:
            UD@ExtractKthDigitSequence{-1}{{{32}54{}t 65zk_+} 8}\
            verb|UD@ExtractKthDigitSequence{0}{{{32}54{}t 65zk_+} 8}|:
            UD@ExtractKthDigitSequence{0}{{{32}54{}t 65zk_+} 8}\
            verb|UD@ExtractKthDigitSequence{1}{{{32}54{}t 65zk_+} 8}|:
            UD@ExtractKthDigitSequence{1}{{{32}54{}t 65zk_+} 8}\
            verb|UD@ExtractKthDigitSequence{2}{{{32}54{}t 65zk_+} 8}|:
            UD@ExtractKthDigitSequence{2}{{{32}54{}t 65zk_+} 8}\
            verb|UD@ExtractKthDigitSequence{3}{{{32}54{}t 65zk_+} 8}|:
            UD@ExtractKthDigitSequence{3}{{{32}54{}t 65zk_+} 8}\
            verb|UD@ExtractKthDigitSequence{4}{{{32}54{}t 65zk_+} 8}|:
            UD@ExtractKthDigitSequence{4}{{{32}54{}t 65zk_+} 8}\
            verb|UD@ExtractKthDigitSequence{5}{{{32}54{}t 65zk_+} 8}|:
            UD@ExtractKthDigitSequence{5}{{{32}54{}t 65zk_+} 8}\
            verb|jobname|:
            jobname\
            verb|UD@ExtractDigitSequencesFromJobname|:
            expandafterexpandafterexpandafterbraceshowloop
            UD@ExtractDigitSequencesFromJobnamerelax\
            verb|UD@ExtractKthDigitSequenceFromJobname{-1}|:
            UD@ExtractKthDigitSequenceFromJobname{-1}\
            verb|UD@ExtractKthDigitSequenceFromJobname{0}|:
            UD@ExtractKthDigitSequenceFromJobname{0}\
            verb|UD@ExtractKthDigitSequenceFromJobname{1}|:
            UD@ExtractKthDigitSequenceFromJobname{1}\
            verb|UD@ExtractKthDigitSequenceFromJobname{2}|:
            UD@ExtractKthDigitSequenceFromJobname{2}\
            verb|UD@ExtractKthDigitSequenceFromJobname{3}|:
            UD@ExtractKthDigitSequenceFromJobname{3}\
            verb|UD@ExtractKthDigitSequenceFromJobname{4}|:
            UD@ExtractKthDigitSequenceFromJobname{4}\
            verb|UD@ExtractKthDigitSequenceFromJobname{5}|:
            UD@ExtractKthDigitSequenceFromJobname{5}\
            verb|UD@ExtractKthDigitSequenceFromJobname{6}|:
            UD@ExtractKthDigitSequenceFromJobname{6}\

            end{document}


            enter image description here






            share|improve this answer




























              1














              Off the cuff I can offer four macros:





              1. UD@ExtractDigitSequences{<arbitrary token sequence>}

                This macro extracts all catcode-12-digit-sequences from <arbitrary token sequence>, nests each catcode-12-digit-sequence into curly braces.


              2. UD@ExtractKthDigitSequence{<number K>}{<arbitrary token sequence>}

                This macro extracts the K-th catcode-12-digit-sequence from <arbitrary token sequence>.


              3. UD@ExtractDigitSequencesFromJobname

                This macro extracts all catcode-12-digit-sequences from the expansion of jobname, nests each catcode-12-digit-sequence into curly braces.


              4. UD@ExtractKthDigitSequenceFromJobname{<number K>}

                This macro extracts the K-th catcode-12-digit-sequence from the expansion of jobname.


              Basically UD@ExtractDigitSequences{<arbitrary token sequence>} and UD@ExtractDigitSequencesFromJobname are wrappers for a recursive loop formed by the macro UD@extractDigitSequencesLoop.



              The gist of that recursive loop is:



              UD@extractDigitSequencesLoop processes three arguments:



              The first argument denotes the (remaining) <arbitrary token-sequence>.

              The second argument denotes the collection of brace-nested digit-sequences collected so far.

              The third argument denotes the collection of digits collected so far for the current digit-sequence.



              First the loop checks whether the (remaining) <arbitrary token-sequence> is empty.



              If so, you are done and the second argument will be delivered and in case the third argument is not empty, it will also be delivered, nested in braces.



              If not so, the loop will look at the first token of the (remaining) <arbitrary token-sequence>, hereby taking into account braces and spaces as cases that need special treatment.



              In case of the first token of the (remaining) <arbitrary token-sequence> being both a non-brace-token and a non-digit-token, the current digit sequence in argument 3 is finished and, if not empty, can be nested in braces and attached to argument 2 before calling the loop again with that token removed from the (remaining) <arbitrary token-sequence>.



              In case of the first token of the (remaining) <arbitrary token-sequence> being an opening-brace, the current digit sequence in argument 3 is finished and, if not empty, can be nested in braces and attached to argument 2. In this case we also need to attach to argument 2 the result of applying the entire routine on the brace-nested first component/on the leading undelimited argument of the (remaining) <arbitrary token-sequence> before calling the loop again with that undelimited argument removed from the (remaining) <arbitrary token-sequence>.



              (This case is important only as long as it is about extracting from arbitrary token sequences: The expansion of the jobname-primitive in any case does contain neither curly opening braces of category-code 1 nor closing braces of category code 2 but a collection of explicit character tokens that may contain explicit character tokens of category code 12(other but not with character code 32(space) and explicit character tokens of category code 10(space) and character code 32(space)=explicit non-funny space-tokens.)



              In case of the first token of the (remaining) <arbitrary token-sequence> being a digit-token, it needs to be attached to the current digit sequence in argument 3 before calling the loop again with that token removed from the (remaining) <arbitrary token-sequence>.



              Of course you also need routines for checking




              • whether an argument is empty.

              • whether an argument's first token is an opening brace.

              • whether an argument's first token is a space token.

              • whether an argument's first token is a digit-token.


              UD@ExtractKthDigitSequence{<number K>}{<arbitrary token sequence>} and UD@ExtractKthDigitSequenceFromJobname{<number K>} "feed" the result of carrying out that loop to another macro which is called UD@ExtractKthArg{<integer K>}{<list of undelimited args>} which in turn is a routine for delivering the K-th undelimited argument from a list of undelimited/brace-nested arguments.



              Everything is implemented so that it will also work in expansion-contexts like csname..endcsname.



              Neither do you need extensions like eTeX or LuaTeX, nor do you need any additional LaTeX2e packages like expl3 or substr or the like.



              documentclass{article}
              makeatletter
              %%=============================================================================
              %% Paraphernalia
              %%.............................................................................
              newcommandUD@firstoftwo[2]{#1}%
              newcommandUD@secondoftwo[2]{#2}%
              newcommandUD@Exchange[2]{#2#1}%
              newcommandUD@gobblespace{}UD@firstoftwo{defUD@gobblespace}{} {}%
              %%=============================================================================
              %% 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>}%
              %%
              %% Due to romannumeral-expansion the result is delivered after two
              %% expansion-steps.
              %%
              %% The gist of this macro comes from Robert R. Schneck's ifempty-macro:
              %% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
              %%
              %% Crank out the cases of string "hitting"
              %% - an opening-brace -> argument is not empty
              %% - a non-brace-token -> argument is not empty
              %% - a closing-brace -> argument is empty
              %%.............................................................................
              newcommandUD@CheckWhetherNull[1]{%
              romannumeral0expandafterUD@secondoftwostring{expandafter
              UD@secondoftwoexpandafter{expandafter{string#1}expandafter
              UD@secondoftwostring}expandafterUD@firstoftwoexpandafter{expandafter
              UD@secondoftwostring}expandafterexpandafterUD@firstoftwo{ }{}%
              UD@secondoftwo}{expandafterexpandafterUD@firstoftwo{ }{}UD@firstoftwo}%
              }%
              %%=============================================================================
              %% Check whether argument's first token is a catcode-1-character
              %%-----------------------------------------------------------------------------
              %% UD@CheckWhetherBrace{<Argument which is to be checked>}%
              %% {<Tokens to be delivered in case that argument
              %% which is to be checked has leading
              %% catcode-1-token>}%
              %% {<Tokens to be delivered in case that argument
              %% which is to be checked has no leading
              %% catcode-1-token>}%
              %%
              %% Due to romannumeral-expansion the result is delivered after two
              %% expansion-steps.
              %%
              %% Basically this is a variation of UD@CheckWhetherNull where non-emptiness
              %% is ensured so that you need to only crank out the cases of string "hitting"
              %% an opening-brace or a non-brace-token.
              %%.............................................................................
              newcommandUD@CheckWhetherBrace[1]{%
              romannumeral0expandafterUD@secondoftwoexpandafter{expandafter{%
              string#1.}expandafterUD@firstoftwoexpandafter{expandafter
              UD@secondoftwostring}expandafterexpandafterUD@firstoftwo{ }{}%
              UD@firstoftwo}{expandafterexpandafterUD@firstoftwo{ }{}UD@secondoftwo}%
              }%
              %%=============================================================================
              %% Check whether brace-balanced argument starts with a space-token
              %%-----------------------------------------------------------------------------
              %% UD@CheckWhetherLeadingSpace{<Argument which is to be checked>}%
              %% {<Tokens to be delivered in case <argument
              %% which is to be checked>'s 1st token is a
              %% space-token>}%
              %% {<Tokens to be delivered in case <argument
              %% which is to be checked>'s 1st token is not
              %% a space-token>}%
              %%
              %% Due to romannumeral-expansion the result is delivered after two
              %% expansion-steps.
              %%.............................................................................
              newcommandUD@CheckWhetherLeadingSpace[1]{%
              romannumeral0UD@CheckWhetherNull{#1}%
              {expandafterexpandafterUD@firstoftwo{ }{}UD@secondoftwo}%
              {expandafterUD@secondoftwostring{UD@CheckWhetherLeadingSpaceB.#1 }{}}%
              }%
              newcommandUD@CheckWhetherLeadingSpaceB{}%
              longdefUD@CheckWhetherLeadingSpaceB#1 {%
              expandafterUD@CheckWhetherNullexpandafter{UD@secondoftwo#1{}}%
              {UD@Exchange{UD@firstoftwo}}{UD@Exchange{UD@secondoftwo}}%
              {UD@Exchange{ }{expandafterexpandafterexpandafterexpandafter
              expandafterexpandafterexpandafter}expandafterexpandafter
              expandafter}expandafterUD@secondoftwoexpandafter{string}%
              }%
              %%=============================================================================
              %% Check whether argument does not contain "!" (unless nested in braces):
              %%-----------------------------------------------------------------------------
              %% UD@CheckWhetherNoExclam{<Argument which is to be checked>}%
              %% {<Tokens to be delivered in case <argument which is
              %% to be checked> does not contain !>}%
              %% {<Tokens to be delivered in case <argument which is
              %% to be checked> does contain !>
              %%.............................................................................
              newcommandUD@GobbleToExclam{}%
              longdefUD@GobbleToExclam#1!{}%
              newcommandUD@CheckWhetherNoExclam[1]{%
              expandafterUD@CheckWhetherNullexpandafter{UD@GobbleToExclam#1!}%
              }%
              %%=============================================================================
              %% Check whether argument is a single explicit character-token of
              %% category code 12 (other) that denotes digit:
              %%-----------------------------------------------------------------------------
              %% UD@CheckWhetherdigit{<Argument which is to be checked>}%
              %% {<Tokens to be delivered in case <argument which is
              %% to be checked> is a single catcode-12-digit>}%
              %% {<Tokens to be delivered in case <argument which is
              %% to be checked> is not a single catcode-12-digit>
              %%
              %% Due to romannumeral-expansion the result is delivered after two
              %% expansion-steps.
              %%.............................................................................
              newcommandUD@CheckWhetherdigitfork{}%
              longdefUD@CheckWhetherdigitfork#1!0!1!2!3!4!5!6!7!8!9!#2#3!!!!{#2}%
              newcommandUD@CheckWhetherdigit[1]{%
              romannumeral0%
              UD@CheckWhetherNoExclam{#1}{%
              UD@CheckWhetherdigitfork
              !#1!1!2!3!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
              !0!#1!2!3!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
              !0!1!#1!3!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
              !0!1!2!#1!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
              !0!1!2!3!#1!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
              !0!1!2!3!4!#1!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
              !0!1!2!3!4!5!#1!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
              !0!1!2!3!4!5!6!#1!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
              !0!1!2!3!4!5!6!7!#1!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
              !0!1!2!3!4!5!6!7!8!#1!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
              !0!1!2!3!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@secondoftwo}%
              !!!!%
              }{UD@firstoftwoexpandafter{} UD@secondoftwo}%
              }%
              %%=============================================================================
              %% Extract K-th inner undelimited argument:
              %%-----------------------------------------------------------------------------
              %% UD@ExtractKthArg{<integer K>}{<list of undelimited args>}
              %%
              %% In case there is no K-th argument in <list of indelimited args> :
              %% Does not deliver any token.
              %% In case there is a K-th argument in <list of indelimited args> :
              %% Does deliver that K-th argument with one level of braces removed.
              %%
              %% Examples:
              %%
              %% UD@ExtractKthArg{0}{ABCDE} yields: <nothing>
              %%
              %% UD@ExtractKthArg{3}{ABCDE} yields: C
              %%
              %% UD@ExtractKthArg{3}{AB{CD}E} yields: CD
              %%
              %% UD@ExtractKthArg{4}{{001}{002}{003}{004}{005}} yields: 004
              %%
              %% UD@ExtractKthArg{6}{{001}{002}{003}} yields: <nothing>
              %%
              %%
              %% Due to romannumeral-expansion the result is delivered after two
              %% expansion-steps.
              %%.............................................................................
              newcommandUD@ExtractKthArg[1]{%
              romannumeral0%
              % #1: <integer number K>
              expandafterUD@ExtractKthArgCheck
              expandafter{romannumeralnumbernumber#1 000}%
              }%
              newcommandUD@ExtractKthArgCheck[2]{%
              UD@CheckWhetherNull{#1}{ }{%
              expandafterUD@ExtractKthArgLoopexpandafter{UD@firstoftwo{}#1}{#2}%
              }%
              }%
              newcommandUD@ExtractKthArgLoop[2]{%
              UD@CheckWhetherNull{#2}{ }{%
              UD@CheckWhetherNull{#1}{%
              UD@ExtractFirstArgLoop{#2UD@SelDOm}%
              }{%
              expandafterUD@Exchangeexpandafter{expandafter{UD@firstoftwo{}#2}}%
              {expandafterUD@ExtractKthArgLoopexpandafter{UD@firstoftwo{}#1}}%
              }%
              }%
              }%
              newcommandUD@RemoveTillUD@SelDOm{}%
              longdefUD@RemoveTillUD@SelDOm#1#2UD@SelDOm{{#1}}%
              newcommandUD@ExtractFirstArgLoop[1]{%
              expandafterUD@CheckWhetherNullexpandafter{UD@firstoftwo{}#1}%
              {UD@firstoftwo{expandafter}{} UD@secondoftwo{}#1}%
              {expandafterUD@ExtractFirstArgLoopexpandafter{UD@RemoveTillUD@SelDOm#1}}%
              }%
              %%=============================================================================
              %% UD@ExtractDigitSequences{<token sequence>}
              %%-----------------------------------------------------------------------------
              %% Extracts sequences of explicit character tokens of category code 12
              %% that denote digits from <token sequence>, nests each such sequence
              %% into curly braces:
              %%
              %% E.g., UD@ExtractDigitSequences{00foo78Bar66}
              %% yields: {00}{78}{66}%
              %%
              %% E.g., UD@ExtractDigitSequences{00foo78Bar66Baz543BaT954}
              %% yields: {00}{78}{66}{543}{954}%
              %%
              %% Does not deliver any token in case <token sequence> does not contain
              %% explicit character-tokens of category code 12(other) that denote
              %% digits.
              %%
              %% Due to romannumeral-expansion the result is delivered after two
              %% expansion-steps.
              %%.............................................................................
              newcommandUD@ExtractDigitSequences[1]{%
              romannumeral0UD@extractDigitSequencesLoop{#1}{}{}%
              }%
              newcommandUD@extractDigitSequencesLoop[3]{%
              UD@CheckWhetherNull{#1}{%
              UD@CheckWhetherNull{#3}{ #2}{ #2{#3}}%
              }{%
              UD@CheckWhetherBrace{#1}{%
              expandafterUD@Exchangeexpandafter{%
              expandafter{romannumeral0%
              UD@CheckWhetherNull{#3}{UD@Exchange{{#2}}}{UD@Exchange{{#2{#3}}}}%
              {expandafterUD@extractDigitSequencesLoop
              expandafter{romannumeral0UD@ExtractKthArgCheck{m}{#1}}%
              }{}%
              }%
              }%
              {expandafterUD@extractDigitSequencesLoopexpandafter{UD@firstoftwo{}#1}}%
              {}%
              }{%
              UD@CheckWhetherLeadingSpace{#1}{%
              UD@CheckWhetherNull{#3}{UD@Exchange{{#2}}}{UD@Exchange{{#2{#3}}}}%
              {expandafterUD@extractDigitSequencesLoopexpandafter{UD@gobblespace#1}}%
              {}%
              }{%
              expandafterUD@CheckWhetherdigit
              expandafter{romannumeral0UD@ExtractKthArgCheck{m}{#1}}{%
              expandafterexpandafterexpandafterUD@Exchange
              expandafterexpandafterexpandafter{%
              expandafterexpandafterexpandafter{%
              expandafterUD@Exchange
              expandafter{romannumeral0UD@ExtractKthArgCheck{m}{#1}}{#3}%
              }%
              }%
              {expandafterUD@extractDigitSequencesLoopexpandafter{UD@firstoftwo{}#1}{#2}}%
              }{%
              UD@CheckWhetherNull{#3}{UD@Exchange{{#2}}}{UD@Exchange{{#2{#3}}}}%
              {expandafterUD@extractDigitSequencesLoopexpandafter{UD@firstoftwo{}#1}}%
              {}%
              }%
              }%
              }%
              }%
              }%
              %%=============================================================================
              %% UD@ExtractKthDigitSequence{<integer K>}{<token sequence>}
              %%-----------------------------------------------------------------------------
              %% Extracts the K-th sequence of explicit character-tokens of category
              %% code 12 (other) that denote digits from <token sequence> if existent.
              %% Otherwise doesn't deliver any token.
              %%
              %% Due to romannumeral-expansion the result is delivered after two
              %% expansion-steps.
              %%.............................................................................
              newcommandUD@ExtractKthDigitSequence[2]{%
              romannumeral0%
              expandafterUD@Exchangeexpandafter{%
              expandafter{romannumeral0UD@extractDigitSequencesLoop{#2}{}{}}%
              }{%
              expandafterUD@ExtractKthArgCheck
              expandafter{romannumeralnumbernumber#1 000}%
              }%
              }%
              %%=============================================================================
              %% UD@ExtractDigitSequencesFromJobname
              %%-----------------------------------------------------------------------------
              %% Extracts sequences of explicit character tokens of category code 12
              %% that denote digits from the top-level-expansion of the control-word-
              %% token jobname, nests each such sequence into curly braces:
              %%
              %% E.g., if jobname = 00foo78Bar66, then
              %%
              %% UD@ExtractDigitSequencesFromJobname
              %%
              %% yields: {00}{78}{66}%
              %%
              %% E.g., if jobname = 00foo78Bar66Baz543BaT954, then
              %%
              %% UD@ExtractDigitSequencesFromJobname
              %%
              %% yields: {00}{78}{66}{543}{954}%
              %%
              %% Does not deliver any token in case <token sequence> does not contain
              %% explicit character-tokens of category code 12(other) that denote
              %% digits.
              %%
              %% Due to romannumeral-expansion the result is delivered after two
              %% expansion-steps.
              %%.............................................................................
              newcommandUD@ExtractDigitSequencesFromJobname{%
              romannumeral0%
              expandafterUD@extractDigitSequencesLoopexpandafter{jobname}{}{}%
              }%
              %%=============================================================================
              %% UD@ExtractKthDigitSequenceFromJobname{<integer K>}
              %%-----------------------------------------------------------------------------
              %% Extracts the K-th sequence of explicit character-tokens of category
              %% code 12 (other) that denote digits from the top-level-expansion of the
              %% control-word-token jobname if existent.
              %% Otherwise doesn't deliver any token.
              %%
              %% Due to romannumeral-expansion the result is delivered after two
              %% expansion-steps.
              %%.............................................................................
              newcommandUD@ExtractKthDigitSequenceFromJobname[1]{%
              romannumeral
              expandafterUD@Exchangeexpandafter{expandafter{jobname}}%
              {expandafterUD@secondoftwoUD@ExtractKthDigitSequence{#1}}%
              }%
              makeatother

              begin{document}

              makeatletter

              defbraceshowloop#1{%
              ifxrelax#1expandafterUD@firstoftwoelseexpandafterUD@secondoftwofi
              {}{{#1}braceshowloop}%
              }%

              noindent
              verb|UD@ExtractDigitSequences{{{32}54{}t 65zk_+} 8}|:
              expandafterexpandafterexpandafterbraceshowloop
              UD@ExtractDigitSequences{{{32}54{}t 65zk_+} 8}relax\
              verb|UD@ExtractKthDigitSequence{-1}{{{32}54{}t 65zk_+} 8}|:
              UD@ExtractKthDigitSequence{-1}{{{32}54{}t 65zk_+} 8}\
              verb|UD@ExtractKthDigitSequence{0}{{{32}54{}t 65zk_+} 8}|:
              UD@ExtractKthDigitSequence{0}{{{32}54{}t 65zk_+} 8}\
              verb|UD@ExtractKthDigitSequence{1}{{{32}54{}t 65zk_+} 8}|:
              UD@ExtractKthDigitSequence{1}{{{32}54{}t 65zk_+} 8}\
              verb|UD@ExtractKthDigitSequence{2}{{{32}54{}t 65zk_+} 8}|:
              UD@ExtractKthDigitSequence{2}{{{32}54{}t 65zk_+} 8}\
              verb|UD@ExtractKthDigitSequence{3}{{{32}54{}t 65zk_+} 8}|:
              UD@ExtractKthDigitSequence{3}{{{32}54{}t 65zk_+} 8}\
              verb|UD@ExtractKthDigitSequence{4}{{{32}54{}t 65zk_+} 8}|:
              UD@ExtractKthDigitSequence{4}{{{32}54{}t 65zk_+} 8}\
              verb|UD@ExtractKthDigitSequence{5}{{{32}54{}t 65zk_+} 8}|:
              UD@ExtractKthDigitSequence{5}{{{32}54{}t 65zk_+} 8}\
              verb|jobname|:
              jobname\
              verb|UD@ExtractDigitSequencesFromJobname|:
              expandafterexpandafterexpandafterbraceshowloop
              UD@ExtractDigitSequencesFromJobnamerelax\
              verb|UD@ExtractKthDigitSequenceFromJobname{-1}|:
              UD@ExtractKthDigitSequenceFromJobname{-1}\
              verb|UD@ExtractKthDigitSequenceFromJobname{0}|:
              UD@ExtractKthDigitSequenceFromJobname{0}\
              verb|UD@ExtractKthDigitSequenceFromJobname{1}|:
              UD@ExtractKthDigitSequenceFromJobname{1}\
              verb|UD@ExtractKthDigitSequenceFromJobname{2}|:
              UD@ExtractKthDigitSequenceFromJobname{2}\
              verb|UD@ExtractKthDigitSequenceFromJobname{3}|:
              UD@ExtractKthDigitSequenceFromJobname{3}\
              verb|UD@ExtractKthDigitSequenceFromJobname{4}|:
              UD@ExtractKthDigitSequenceFromJobname{4}\
              verb|UD@ExtractKthDigitSequenceFromJobname{5}|:
              UD@ExtractKthDigitSequenceFromJobname{5}\
              verb|UD@ExtractKthDigitSequenceFromJobname{6}|:
              UD@ExtractKthDigitSequenceFromJobname{6}\

              end{document}


              enter image description here






              share|improve this answer


























                1












                1








                1






                Off the cuff I can offer four macros:





                1. UD@ExtractDigitSequences{<arbitrary token sequence>}

                  This macro extracts all catcode-12-digit-sequences from <arbitrary token sequence>, nests each catcode-12-digit-sequence into curly braces.


                2. UD@ExtractKthDigitSequence{<number K>}{<arbitrary token sequence>}

                  This macro extracts the K-th catcode-12-digit-sequence from <arbitrary token sequence>.


                3. UD@ExtractDigitSequencesFromJobname

                  This macro extracts all catcode-12-digit-sequences from the expansion of jobname, nests each catcode-12-digit-sequence into curly braces.


                4. UD@ExtractKthDigitSequenceFromJobname{<number K>}

                  This macro extracts the K-th catcode-12-digit-sequence from the expansion of jobname.


                Basically UD@ExtractDigitSequences{<arbitrary token sequence>} and UD@ExtractDigitSequencesFromJobname are wrappers for a recursive loop formed by the macro UD@extractDigitSequencesLoop.



                The gist of that recursive loop is:



                UD@extractDigitSequencesLoop processes three arguments:



                The first argument denotes the (remaining) <arbitrary token-sequence>.

                The second argument denotes the collection of brace-nested digit-sequences collected so far.

                The third argument denotes the collection of digits collected so far for the current digit-sequence.



                First the loop checks whether the (remaining) <arbitrary token-sequence> is empty.



                If so, you are done and the second argument will be delivered and in case the third argument is not empty, it will also be delivered, nested in braces.



                If not so, the loop will look at the first token of the (remaining) <arbitrary token-sequence>, hereby taking into account braces and spaces as cases that need special treatment.



                In case of the first token of the (remaining) <arbitrary token-sequence> being both a non-brace-token and a non-digit-token, the current digit sequence in argument 3 is finished and, if not empty, can be nested in braces and attached to argument 2 before calling the loop again with that token removed from the (remaining) <arbitrary token-sequence>.



                In case of the first token of the (remaining) <arbitrary token-sequence> being an opening-brace, the current digit sequence in argument 3 is finished and, if not empty, can be nested in braces and attached to argument 2. In this case we also need to attach to argument 2 the result of applying the entire routine on the brace-nested first component/on the leading undelimited argument of the (remaining) <arbitrary token-sequence> before calling the loop again with that undelimited argument removed from the (remaining) <arbitrary token-sequence>.



                (This case is important only as long as it is about extracting from arbitrary token sequences: The expansion of the jobname-primitive in any case does contain neither curly opening braces of category-code 1 nor closing braces of category code 2 but a collection of explicit character tokens that may contain explicit character tokens of category code 12(other but not with character code 32(space) and explicit character tokens of category code 10(space) and character code 32(space)=explicit non-funny space-tokens.)



                In case of the first token of the (remaining) <arbitrary token-sequence> being a digit-token, it needs to be attached to the current digit sequence in argument 3 before calling the loop again with that token removed from the (remaining) <arbitrary token-sequence>.



                Of course you also need routines for checking




                • whether an argument is empty.

                • whether an argument's first token is an opening brace.

                • whether an argument's first token is a space token.

                • whether an argument's first token is a digit-token.


                UD@ExtractKthDigitSequence{<number K>}{<arbitrary token sequence>} and UD@ExtractKthDigitSequenceFromJobname{<number K>} "feed" the result of carrying out that loop to another macro which is called UD@ExtractKthArg{<integer K>}{<list of undelimited args>} which in turn is a routine for delivering the K-th undelimited argument from a list of undelimited/brace-nested arguments.



                Everything is implemented so that it will also work in expansion-contexts like csname..endcsname.



                Neither do you need extensions like eTeX or LuaTeX, nor do you need any additional LaTeX2e packages like expl3 or substr or the like.



                documentclass{article}
                makeatletter
                %%=============================================================================
                %% Paraphernalia
                %%.............................................................................
                newcommandUD@firstoftwo[2]{#1}%
                newcommandUD@secondoftwo[2]{#2}%
                newcommandUD@Exchange[2]{#2#1}%
                newcommandUD@gobblespace{}UD@firstoftwo{defUD@gobblespace}{} {}%
                %%=============================================================================
                %% 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>}%
                %%
                %% Due to romannumeral-expansion the result is delivered after two
                %% expansion-steps.
                %%
                %% The gist of this macro comes from Robert R. Schneck's ifempty-macro:
                %% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
                %%
                %% Crank out the cases of string "hitting"
                %% - an opening-brace -> argument is not empty
                %% - a non-brace-token -> argument is not empty
                %% - a closing-brace -> argument is empty
                %%.............................................................................
                newcommandUD@CheckWhetherNull[1]{%
                romannumeral0expandafterUD@secondoftwostring{expandafter
                UD@secondoftwoexpandafter{expandafter{string#1}expandafter
                UD@secondoftwostring}expandafterUD@firstoftwoexpandafter{expandafter
                UD@secondoftwostring}expandafterexpandafterUD@firstoftwo{ }{}%
                UD@secondoftwo}{expandafterexpandafterUD@firstoftwo{ }{}UD@firstoftwo}%
                }%
                %%=============================================================================
                %% Check whether argument's first token is a catcode-1-character
                %%-----------------------------------------------------------------------------
                %% UD@CheckWhetherBrace{<Argument which is to be checked>}%
                %% {<Tokens to be delivered in case that argument
                %% which is to be checked has leading
                %% catcode-1-token>}%
                %% {<Tokens to be delivered in case that argument
                %% which is to be checked has no leading
                %% catcode-1-token>}%
                %%
                %% Due to romannumeral-expansion the result is delivered after two
                %% expansion-steps.
                %%
                %% Basically this is a variation of UD@CheckWhetherNull where non-emptiness
                %% is ensured so that you need to only crank out the cases of string "hitting"
                %% an opening-brace or a non-brace-token.
                %%.............................................................................
                newcommandUD@CheckWhetherBrace[1]{%
                romannumeral0expandafterUD@secondoftwoexpandafter{expandafter{%
                string#1.}expandafterUD@firstoftwoexpandafter{expandafter
                UD@secondoftwostring}expandafterexpandafterUD@firstoftwo{ }{}%
                UD@firstoftwo}{expandafterexpandafterUD@firstoftwo{ }{}UD@secondoftwo}%
                }%
                %%=============================================================================
                %% Check whether brace-balanced argument starts with a space-token
                %%-----------------------------------------------------------------------------
                %% UD@CheckWhetherLeadingSpace{<Argument which is to be checked>}%
                %% {<Tokens to be delivered in case <argument
                %% which is to be checked>'s 1st token is a
                %% space-token>}%
                %% {<Tokens to be delivered in case <argument
                %% which is to be checked>'s 1st token is not
                %% a space-token>}%
                %%
                %% Due to romannumeral-expansion the result is delivered after two
                %% expansion-steps.
                %%.............................................................................
                newcommandUD@CheckWhetherLeadingSpace[1]{%
                romannumeral0UD@CheckWhetherNull{#1}%
                {expandafterexpandafterUD@firstoftwo{ }{}UD@secondoftwo}%
                {expandafterUD@secondoftwostring{UD@CheckWhetherLeadingSpaceB.#1 }{}}%
                }%
                newcommandUD@CheckWhetherLeadingSpaceB{}%
                longdefUD@CheckWhetherLeadingSpaceB#1 {%
                expandafterUD@CheckWhetherNullexpandafter{UD@secondoftwo#1{}}%
                {UD@Exchange{UD@firstoftwo}}{UD@Exchange{UD@secondoftwo}}%
                {UD@Exchange{ }{expandafterexpandafterexpandafterexpandafter
                expandafterexpandafterexpandafter}expandafterexpandafter
                expandafter}expandafterUD@secondoftwoexpandafter{string}%
                }%
                %%=============================================================================
                %% Check whether argument does not contain "!" (unless nested in braces):
                %%-----------------------------------------------------------------------------
                %% UD@CheckWhetherNoExclam{<Argument which is to be checked>}%
                %% {<Tokens to be delivered in case <argument which is
                %% to be checked> does not contain !>}%
                %% {<Tokens to be delivered in case <argument which is
                %% to be checked> does contain !>
                %%.............................................................................
                newcommandUD@GobbleToExclam{}%
                longdefUD@GobbleToExclam#1!{}%
                newcommandUD@CheckWhetherNoExclam[1]{%
                expandafterUD@CheckWhetherNullexpandafter{UD@GobbleToExclam#1!}%
                }%
                %%=============================================================================
                %% Check whether argument is a single explicit character-token of
                %% category code 12 (other) that denotes digit:
                %%-----------------------------------------------------------------------------
                %% UD@CheckWhetherdigit{<Argument which is to be checked>}%
                %% {<Tokens to be delivered in case <argument which is
                %% to be checked> is a single catcode-12-digit>}%
                %% {<Tokens to be delivered in case <argument which is
                %% to be checked> is not a single catcode-12-digit>
                %%
                %% Due to romannumeral-expansion the result is delivered after two
                %% expansion-steps.
                %%.............................................................................
                newcommandUD@CheckWhetherdigitfork{}%
                longdefUD@CheckWhetherdigitfork#1!0!1!2!3!4!5!6!7!8!9!#2#3!!!!{#2}%
                newcommandUD@CheckWhetherdigit[1]{%
                romannumeral0%
                UD@CheckWhetherNoExclam{#1}{%
                UD@CheckWhetherdigitfork
                !#1!1!2!3!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
                !0!#1!2!3!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
                !0!1!#1!3!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
                !0!1!2!#1!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
                !0!1!2!3!#1!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
                !0!1!2!3!4!#1!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
                !0!1!2!3!4!5!#1!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
                !0!1!2!3!4!5!6!#1!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
                !0!1!2!3!4!5!6!7!#1!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
                !0!1!2!3!4!5!6!7!8!#1!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
                !0!1!2!3!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@secondoftwo}%
                !!!!%
                }{UD@firstoftwoexpandafter{} UD@secondoftwo}%
                }%
                %%=============================================================================
                %% Extract K-th inner undelimited argument:
                %%-----------------------------------------------------------------------------
                %% UD@ExtractKthArg{<integer K>}{<list of undelimited args>}
                %%
                %% In case there is no K-th argument in <list of indelimited args> :
                %% Does not deliver any token.
                %% In case there is a K-th argument in <list of indelimited args> :
                %% Does deliver that K-th argument with one level of braces removed.
                %%
                %% Examples:
                %%
                %% UD@ExtractKthArg{0}{ABCDE} yields: <nothing>
                %%
                %% UD@ExtractKthArg{3}{ABCDE} yields: C
                %%
                %% UD@ExtractKthArg{3}{AB{CD}E} yields: CD
                %%
                %% UD@ExtractKthArg{4}{{001}{002}{003}{004}{005}} yields: 004
                %%
                %% UD@ExtractKthArg{6}{{001}{002}{003}} yields: <nothing>
                %%
                %%
                %% Due to romannumeral-expansion the result is delivered after two
                %% expansion-steps.
                %%.............................................................................
                newcommandUD@ExtractKthArg[1]{%
                romannumeral0%
                % #1: <integer number K>
                expandafterUD@ExtractKthArgCheck
                expandafter{romannumeralnumbernumber#1 000}%
                }%
                newcommandUD@ExtractKthArgCheck[2]{%
                UD@CheckWhetherNull{#1}{ }{%
                expandafterUD@ExtractKthArgLoopexpandafter{UD@firstoftwo{}#1}{#2}%
                }%
                }%
                newcommandUD@ExtractKthArgLoop[2]{%
                UD@CheckWhetherNull{#2}{ }{%
                UD@CheckWhetherNull{#1}{%
                UD@ExtractFirstArgLoop{#2UD@SelDOm}%
                }{%
                expandafterUD@Exchangeexpandafter{expandafter{UD@firstoftwo{}#2}}%
                {expandafterUD@ExtractKthArgLoopexpandafter{UD@firstoftwo{}#1}}%
                }%
                }%
                }%
                newcommandUD@RemoveTillUD@SelDOm{}%
                longdefUD@RemoveTillUD@SelDOm#1#2UD@SelDOm{{#1}}%
                newcommandUD@ExtractFirstArgLoop[1]{%
                expandafterUD@CheckWhetherNullexpandafter{UD@firstoftwo{}#1}%
                {UD@firstoftwo{expandafter}{} UD@secondoftwo{}#1}%
                {expandafterUD@ExtractFirstArgLoopexpandafter{UD@RemoveTillUD@SelDOm#1}}%
                }%
                %%=============================================================================
                %% UD@ExtractDigitSequences{<token sequence>}
                %%-----------------------------------------------------------------------------
                %% Extracts sequences of explicit character tokens of category code 12
                %% that denote digits from <token sequence>, nests each such sequence
                %% into curly braces:
                %%
                %% E.g., UD@ExtractDigitSequences{00foo78Bar66}
                %% yields: {00}{78}{66}%
                %%
                %% E.g., UD@ExtractDigitSequences{00foo78Bar66Baz543BaT954}
                %% yields: {00}{78}{66}{543}{954}%
                %%
                %% Does not deliver any token in case <token sequence> does not contain
                %% explicit character-tokens of category code 12(other) that denote
                %% digits.
                %%
                %% Due to romannumeral-expansion the result is delivered after two
                %% expansion-steps.
                %%.............................................................................
                newcommandUD@ExtractDigitSequences[1]{%
                romannumeral0UD@extractDigitSequencesLoop{#1}{}{}%
                }%
                newcommandUD@extractDigitSequencesLoop[3]{%
                UD@CheckWhetherNull{#1}{%
                UD@CheckWhetherNull{#3}{ #2}{ #2{#3}}%
                }{%
                UD@CheckWhetherBrace{#1}{%
                expandafterUD@Exchangeexpandafter{%
                expandafter{romannumeral0%
                UD@CheckWhetherNull{#3}{UD@Exchange{{#2}}}{UD@Exchange{{#2{#3}}}}%
                {expandafterUD@extractDigitSequencesLoop
                expandafter{romannumeral0UD@ExtractKthArgCheck{m}{#1}}%
                }{}%
                }%
                }%
                {expandafterUD@extractDigitSequencesLoopexpandafter{UD@firstoftwo{}#1}}%
                {}%
                }{%
                UD@CheckWhetherLeadingSpace{#1}{%
                UD@CheckWhetherNull{#3}{UD@Exchange{{#2}}}{UD@Exchange{{#2{#3}}}}%
                {expandafterUD@extractDigitSequencesLoopexpandafter{UD@gobblespace#1}}%
                {}%
                }{%
                expandafterUD@CheckWhetherdigit
                expandafter{romannumeral0UD@ExtractKthArgCheck{m}{#1}}{%
                expandafterexpandafterexpandafterUD@Exchange
                expandafterexpandafterexpandafter{%
                expandafterexpandafterexpandafter{%
                expandafterUD@Exchange
                expandafter{romannumeral0UD@ExtractKthArgCheck{m}{#1}}{#3}%
                }%
                }%
                {expandafterUD@extractDigitSequencesLoopexpandafter{UD@firstoftwo{}#1}{#2}}%
                }{%
                UD@CheckWhetherNull{#3}{UD@Exchange{{#2}}}{UD@Exchange{{#2{#3}}}}%
                {expandafterUD@extractDigitSequencesLoopexpandafter{UD@firstoftwo{}#1}}%
                {}%
                }%
                }%
                }%
                }%
                }%
                %%=============================================================================
                %% UD@ExtractKthDigitSequence{<integer K>}{<token sequence>}
                %%-----------------------------------------------------------------------------
                %% Extracts the K-th sequence of explicit character-tokens of category
                %% code 12 (other) that denote digits from <token sequence> if existent.
                %% Otherwise doesn't deliver any token.
                %%
                %% Due to romannumeral-expansion the result is delivered after two
                %% expansion-steps.
                %%.............................................................................
                newcommandUD@ExtractKthDigitSequence[2]{%
                romannumeral0%
                expandafterUD@Exchangeexpandafter{%
                expandafter{romannumeral0UD@extractDigitSequencesLoop{#2}{}{}}%
                }{%
                expandafterUD@ExtractKthArgCheck
                expandafter{romannumeralnumbernumber#1 000}%
                }%
                }%
                %%=============================================================================
                %% UD@ExtractDigitSequencesFromJobname
                %%-----------------------------------------------------------------------------
                %% Extracts sequences of explicit character tokens of category code 12
                %% that denote digits from the top-level-expansion of the control-word-
                %% token jobname, nests each such sequence into curly braces:
                %%
                %% E.g., if jobname = 00foo78Bar66, then
                %%
                %% UD@ExtractDigitSequencesFromJobname
                %%
                %% yields: {00}{78}{66}%
                %%
                %% E.g., if jobname = 00foo78Bar66Baz543BaT954, then
                %%
                %% UD@ExtractDigitSequencesFromJobname
                %%
                %% yields: {00}{78}{66}{543}{954}%
                %%
                %% Does not deliver any token in case <token sequence> does not contain
                %% explicit character-tokens of category code 12(other) that denote
                %% digits.
                %%
                %% Due to romannumeral-expansion the result is delivered after two
                %% expansion-steps.
                %%.............................................................................
                newcommandUD@ExtractDigitSequencesFromJobname{%
                romannumeral0%
                expandafterUD@extractDigitSequencesLoopexpandafter{jobname}{}{}%
                }%
                %%=============================================================================
                %% UD@ExtractKthDigitSequenceFromJobname{<integer K>}
                %%-----------------------------------------------------------------------------
                %% Extracts the K-th sequence of explicit character-tokens of category
                %% code 12 (other) that denote digits from the top-level-expansion of the
                %% control-word-token jobname if existent.
                %% Otherwise doesn't deliver any token.
                %%
                %% Due to romannumeral-expansion the result is delivered after two
                %% expansion-steps.
                %%.............................................................................
                newcommandUD@ExtractKthDigitSequenceFromJobname[1]{%
                romannumeral
                expandafterUD@Exchangeexpandafter{expandafter{jobname}}%
                {expandafterUD@secondoftwoUD@ExtractKthDigitSequence{#1}}%
                }%
                makeatother

                begin{document}

                makeatletter

                defbraceshowloop#1{%
                ifxrelax#1expandafterUD@firstoftwoelseexpandafterUD@secondoftwofi
                {}{{#1}braceshowloop}%
                }%

                noindent
                verb|UD@ExtractDigitSequences{{{32}54{}t 65zk_+} 8}|:
                expandafterexpandafterexpandafterbraceshowloop
                UD@ExtractDigitSequences{{{32}54{}t 65zk_+} 8}relax\
                verb|UD@ExtractKthDigitSequence{-1}{{{32}54{}t 65zk_+} 8}|:
                UD@ExtractKthDigitSequence{-1}{{{32}54{}t 65zk_+} 8}\
                verb|UD@ExtractKthDigitSequence{0}{{{32}54{}t 65zk_+} 8}|:
                UD@ExtractKthDigitSequence{0}{{{32}54{}t 65zk_+} 8}\
                verb|UD@ExtractKthDigitSequence{1}{{{32}54{}t 65zk_+} 8}|:
                UD@ExtractKthDigitSequence{1}{{{32}54{}t 65zk_+} 8}\
                verb|UD@ExtractKthDigitSequence{2}{{{32}54{}t 65zk_+} 8}|:
                UD@ExtractKthDigitSequence{2}{{{32}54{}t 65zk_+} 8}\
                verb|UD@ExtractKthDigitSequence{3}{{{32}54{}t 65zk_+} 8}|:
                UD@ExtractKthDigitSequence{3}{{{32}54{}t 65zk_+} 8}\
                verb|UD@ExtractKthDigitSequence{4}{{{32}54{}t 65zk_+} 8}|:
                UD@ExtractKthDigitSequence{4}{{{32}54{}t 65zk_+} 8}\
                verb|UD@ExtractKthDigitSequence{5}{{{32}54{}t 65zk_+} 8}|:
                UD@ExtractKthDigitSequence{5}{{{32}54{}t 65zk_+} 8}\
                verb|jobname|:
                jobname\
                verb|UD@ExtractDigitSequencesFromJobname|:
                expandafterexpandafterexpandafterbraceshowloop
                UD@ExtractDigitSequencesFromJobnamerelax\
                verb|UD@ExtractKthDigitSequenceFromJobname{-1}|:
                UD@ExtractKthDigitSequenceFromJobname{-1}\
                verb|UD@ExtractKthDigitSequenceFromJobname{0}|:
                UD@ExtractKthDigitSequenceFromJobname{0}\
                verb|UD@ExtractKthDigitSequenceFromJobname{1}|:
                UD@ExtractKthDigitSequenceFromJobname{1}\
                verb|UD@ExtractKthDigitSequenceFromJobname{2}|:
                UD@ExtractKthDigitSequenceFromJobname{2}\
                verb|UD@ExtractKthDigitSequenceFromJobname{3}|:
                UD@ExtractKthDigitSequenceFromJobname{3}\
                verb|UD@ExtractKthDigitSequenceFromJobname{4}|:
                UD@ExtractKthDigitSequenceFromJobname{4}\
                verb|UD@ExtractKthDigitSequenceFromJobname{5}|:
                UD@ExtractKthDigitSequenceFromJobname{5}\
                verb|UD@ExtractKthDigitSequenceFromJobname{6}|:
                UD@ExtractKthDigitSequenceFromJobname{6}\

                end{document}


                enter image description here






                share|improve this answer














                Off the cuff I can offer four macros:





                1. UD@ExtractDigitSequences{<arbitrary token sequence>}

                  This macro extracts all catcode-12-digit-sequences from <arbitrary token sequence>, nests each catcode-12-digit-sequence into curly braces.


                2. UD@ExtractKthDigitSequence{<number K>}{<arbitrary token sequence>}

                  This macro extracts the K-th catcode-12-digit-sequence from <arbitrary token sequence>.


                3. UD@ExtractDigitSequencesFromJobname

                  This macro extracts all catcode-12-digit-sequences from the expansion of jobname, nests each catcode-12-digit-sequence into curly braces.


                4. UD@ExtractKthDigitSequenceFromJobname{<number K>}

                  This macro extracts the K-th catcode-12-digit-sequence from the expansion of jobname.


                Basically UD@ExtractDigitSequences{<arbitrary token sequence>} and UD@ExtractDigitSequencesFromJobname are wrappers for a recursive loop formed by the macro UD@extractDigitSequencesLoop.



                The gist of that recursive loop is:



                UD@extractDigitSequencesLoop processes three arguments:



                The first argument denotes the (remaining) <arbitrary token-sequence>.

                The second argument denotes the collection of brace-nested digit-sequences collected so far.

                The third argument denotes the collection of digits collected so far for the current digit-sequence.



                First the loop checks whether the (remaining) <arbitrary token-sequence> is empty.



                If so, you are done and the second argument will be delivered and in case the third argument is not empty, it will also be delivered, nested in braces.



                If not so, the loop will look at the first token of the (remaining) <arbitrary token-sequence>, hereby taking into account braces and spaces as cases that need special treatment.



                In case of the first token of the (remaining) <arbitrary token-sequence> being both a non-brace-token and a non-digit-token, the current digit sequence in argument 3 is finished and, if not empty, can be nested in braces and attached to argument 2 before calling the loop again with that token removed from the (remaining) <arbitrary token-sequence>.



                In case of the first token of the (remaining) <arbitrary token-sequence> being an opening-brace, the current digit sequence in argument 3 is finished and, if not empty, can be nested in braces and attached to argument 2. In this case we also need to attach to argument 2 the result of applying the entire routine on the brace-nested first component/on the leading undelimited argument of the (remaining) <arbitrary token-sequence> before calling the loop again with that undelimited argument removed from the (remaining) <arbitrary token-sequence>.



                (This case is important only as long as it is about extracting from arbitrary token sequences: The expansion of the jobname-primitive in any case does contain neither curly opening braces of category-code 1 nor closing braces of category code 2 but a collection of explicit character tokens that may contain explicit character tokens of category code 12(other but not with character code 32(space) and explicit character tokens of category code 10(space) and character code 32(space)=explicit non-funny space-tokens.)



                In case of the first token of the (remaining) <arbitrary token-sequence> being a digit-token, it needs to be attached to the current digit sequence in argument 3 before calling the loop again with that token removed from the (remaining) <arbitrary token-sequence>.



                Of course you also need routines for checking




                • whether an argument is empty.

                • whether an argument's first token is an opening brace.

                • whether an argument's first token is a space token.

                • whether an argument's first token is a digit-token.


                UD@ExtractKthDigitSequence{<number K>}{<arbitrary token sequence>} and UD@ExtractKthDigitSequenceFromJobname{<number K>} "feed" the result of carrying out that loop to another macro which is called UD@ExtractKthArg{<integer K>}{<list of undelimited args>} which in turn is a routine for delivering the K-th undelimited argument from a list of undelimited/brace-nested arguments.



                Everything is implemented so that it will also work in expansion-contexts like csname..endcsname.



                Neither do you need extensions like eTeX or LuaTeX, nor do you need any additional LaTeX2e packages like expl3 or substr or the like.



                documentclass{article}
                makeatletter
                %%=============================================================================
                %% Paraphernalia
                %%.............................................................................
                newcommandUD@firstoftwo[2]{#1}%
                newcommandUD@secondoftwo[2]{#2}%
                newcommandUD@Exchange[2]{#2#1}%
                newcommandUD@gobblespace{}UD@firstoftwo{defUD@gobblespace}{} {}%
                %%=============================================================================
                %% 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>}%
                %%
                %% Due to romannumeral-expansion the result is delivered after two
                %% expansion-steps.
                %%
                %% The gist of this macro comes from Robert R. Schneck's ifempty-macro:
                %% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
                %%
                %% Crank out the cases of string "hitting"
                %% - an opening-brace -> argument is not empty
                %% - a non-brace-token -> argument is not empty
                %% - a closing-brace -> argument is empty
                %%.............................................................................
                newcommandUD@CheckWhetherNull[1]{%
                romannumeral0expandafterUD@secondoftwostring{expandafter
                UD@secondoftwoexpandafter{expandafter{string#1}expandafter
                UD@secondoftwostring}expandafterUD@firstoftwoexpandafter{expandafter
                UD@secondoftwostring}expandafterexpandafterUD@firstoftwo{ }{}%
                UD@secondoftwo}{expandafterexpandafterUD@firstoftwo{ }{}UD@firstoftwo}%
                }%
                %%=============================================================================
                %% Check whether argument's first token is a catcode-1-character
                %%-----------------------------------------------------------------------------
                %% UD@CheckWhetherBrace{<Argument which is to be checked>}%
                %% {<Tokens to be delivered in case that argument
                %% which is to be checked has leading
                %% catcode-1-token>}%
                %% {<Tokens to be delivered in case that argument
                %% which is to be checked has no leading
                %% catcode-1-token>}%
                %%
                %% Due to romannumeral-expansion the result is delivered after two
                %% expansion-steps.
                %%
                %% Basically this is a variation of UD@CheckWhetherNull where non-emptiness
                %% is ensured so that you need to only crank out the cases of string "hitting"
                %% an opening-brace or a non-brace-token.
                %%.............................................................................
                newcommandUD@CheckWhetherBrace[1]{%
                romannumeral0expandafterUD@secondoftwoexpandafter{expandafter{%
                string#1.}expandafterUD@firstoftwoexpandafter{expandafter
                UD@secondoftwostring}expandafterexpandafterUD@firstoftwo{ }{}%
                UD@firstoftwo}{expandafterexpandafterUD@firstoftwo{ }{}UD@secondoftwo}%
                }%
                %%=============================================================================
                %% Check whether brace-balanced argument starts with a space-token
                %%-----------------------------------------------------------------------------
                %% UD@CheckWhetherLeadingSpace{<Argument which is to be checked>}%
                %% {<Tokens to be delivered in case <argument
                %% which is to be checked>'s 1st token is a
                %% space-token>}%
                %% {<Tokens to be delivered in case <argument
                %% which is to be checked>'s 1st token is not
                %% a space-token>}%
                %%
                %% Due to romannumeral-expansion the result is delivered after two
                %% expansion-steps.
                %%.............................................................................
                newcommandUD@CheckWhetherLeadingSpace[1]{%
                romannumeral0UD@CheckWhetherNull{#1}%
                {expandafterexpandafterUD@firstoftwo{ }{}UD@secondoftwo}%
                {expandafterUD@secondoftwostring{UD@CheckWhetherLeadingSpaceB.#1 }{}}%
                }%
                newcommandUD@CheckWhetherLeadingSpaceB{}%
                longdefUD@CheckWhetherLeadingSpaceB#1 {%
                expandafterUD@CheckWhetherNullexpandafter{UD@secondoftwo#1{}}%
                {UD@Exchange{UD@firstoftwo}}{UD@Exchange{UD@secondoftwo}}%
                {UD@Exchange{ }{expandafterexpandafterexpandafterexpandafter
                expandafterexpandafterexpandafter}expandafterexpandafter
                expandafter}expandafterUD@secondoftwoexpandafter{string}%
                }%
                %%=============================================================================
                %% Check whether argument does not contain "!" (unless nested in braces):
                %%-----------------------------------------------------------------------------
                %% UD@CheckWhetherNoExclam{<Argument which is to be checked>}%
                %% {<Tokens to be delivered in case <argument which is
                %% to be checked> does not contain !>}%
                %% {<Tokens to be delivered in case <argument which is
                %% to be checked> does contain !>
                %%.............................................................................
                newcommandUD@GobbleToExclam{}%
                longdefUD@GobbleToExclam#1!{}%
                newcommandUD@CheckWhetherNoExclam[1]{%
                expandafterUD@CheckWhetherNullexpandafter{UD@GobbleToExclam#1!}%
                }%
                %%=============================================================================
                %% Check whether argument is a single explicit character-token of
                %% category code 12 (other) that denotes digit:
                %%-----------------------------------------------------------------------------
                %% UD@CheckWhetherdigit{<Argument which is to be checked>}%
                %% {<Tokens to be delivered in case <argument which is
                %% to be checked> is a single catcode-12-digit>}%
                %% {<Tokens to be delivered in case <argument which is
                %% to be checked> is not a single catcode-12-digit>
                %%
                %% Due to romannumeral-expansion the result is delivered after two
                %% expansion-steps.
                %%.............................................................................
                newcommandUD@CheckWhetherdigitfork{}%
                longdefUD@CheckWhetherdigitfork#1!0!1!2!3!4!5!6!7!8!9!#2#3!!!!{#2}%
                newcommandUD@CheckWhetherdigit[1]{%
                romannumeral0%
                UD@CheckWhetherNoExclam{#1}{%
                UD@CheckWhetherdigitfork
                !#1!1!2!3!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
                !0!#1!2!3!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
                !0!1!#1!3!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
                !0!1!2!#1!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
                !0!1!2!3!#1!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
                !0!1!2!3!4!#1!6!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
                !0!1!2!3!4!5!#1!7!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
                !0!1!2!3!4!5!6!#1!8!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
                !0!1!2!3!4!5!6!7!#1!9!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
                !0!1!2!3!4!5!6!7!8!#1!{UD@firstoftwoexpandafter{} UD@firstoftwo}%
                !0!1!2!3!4!5!6!7!8!9!{UD@firstoftwoexpandafter{} UD@secondoftwo}%
                !!!!%
                }{UD@firstoftwoexpandafter{} UD@secondoftwo}%
                }%
                %%=============================================================================
                %% Extract K-th inner undelimited argument:
                %%-----------------------------------------------------------------------------
                %% UD@ExtractKthArg{<integer K>}{<list of undelimited args>}
                %%
                %% In case there is no K-th argument in <list of indelimited args> :
                %% Does not deliver any token.
                %% In case there is a K-th argument in <list of indelimited args> :
                %% Does deliver that K-th argument with one level of braces removed.
                %%
                %% Examples:
                %%
                %% UD@ExtractKthArg{0}{ABCDE} yields: <nothing>
                %%
                %% UD@ExtractKthArg{3}{ABCDE} yields: C
                %%
                %% UD@ExtractKthArg{3}{AB{CD}E} yields: CD
                %%
                %% UD@ExtractKthArg{4}{{001}{002}{003}{004}{005}} yields: 004
                %%
                %% UD@ExtractKthArg{6}{{001}{002}{003}} yields: <nothing>
                %%
                %%
                %% Due to romannumeral-expansion the result is delivered after two
                %% expansion-steps.
                %%.............................................................................
                newcommandUD@ExtractKthArg[1]{%
                romannumeral0%
                % #1: <integer number K>
                expandafterUD@ExtractKthArgCheck
                expandafter{romannumeralnumbernumber#1 000}%
                }%
                newcommandUD@ExtractKthArgCheck[2]{%
                UD@CheckWhetherNull{#1}{ }{%
                expandafterUD@ExtractKthArgLoopexpandafter{UD@firstoftwo{}#1}{#2}%
                }%
                }%
                newcommandUD@ExtractKthArgLoop[2]{%
                UD@CheckWhetherNull{#2}{ }{%
                UD@CheckWhetherNull{#1}{%
                UD@ExtractFirstArgLoop{#2UD@SelDOm}%
                }{%
                expandafterUD@Exchangeexpandafter{expandafter{UD@firstoftwo{}#2}}%
                {expandafterUD@ExtractKthArgLoopexpandafter{UD@firstoftwo{}#1}}%
                }%
                }%
                }%
                newcommandUD@RemoveTillUD@SelDOm{}%
                longdefUD@RemoveTillUD@SelDOm#1#2UD@SelDOm{{#1}}%
                newcommandUD@ExtractFirstArgLoop[1]{%
                expandafterUD@CheckWhetherNullexpandafter{UD@firstoftwo{}#1}%
                {UD@firstoftwo{expandafter}{} UD@secondoftwo{}#1}%
                {expandafterUD@ExtractFirstArgLoopexpandafter{UD@RemoveTillUD@SelDOm#1}}%
                }%
                %%=============================================================================
                %% UD@ExtractDigitSequences{<token sequence>}
                %%-----------------------------------------------------------------------------
                %% Extracts sequences of explicit character tokens of category code 12
                %% that denote digits from <token sequence>, nests each such sequence
                %% into curly braces:
                %%
                %% E.g., UD@ExtractDigitSequences{00foo78Bar66}
                %% yields: {00}{78}{66}%
                %%
                %% E.g., UD@ExtractDigitSequences{00foo78Bar66Baz543BaT954}
                %% yields: {00}{78}{66}{543}{954}%
                %%
                %% Does not deliver any token in case <token sequence> does not contain
                %% explicit character-tokens of category code 12(other) that denote
                %% digits.
                %%
                %% Due to romannumeral-expansion the result is delivered after two
                %% expansion-steps.
                %%.............................................................................
                newcommandUD@ExtractDigitSequences[1]{%
                romannumeral0UD@extractDigitSequencesLoop{#1}{}{}%
                }%
                newcommandUD@extractDigitSequencesLoop[3]{%
                UD@CheckWhetherNull{#1}{%
                UD@CheckWhetherNull{#3}{ #2}{ #2{#3}}%
                }{%
                UD@CheckWhetherBrace{#1}{%
                expandafterUD@Exchangeexpandafter{%
                expandafter{romannumeral0%
                UD@CheckWhetherNull{#3}{UD@Exchange{{#2}}}{UD@Exchange{{#2{#3}}}}%
                {expandafterUD@extractDigitSequencesLoop
                expandafter{romannumeral0UD@ExtractKthArgCheck{m}{#1}}%
                }{}%
                }%
                }%
                {expandafterUD@extractDigitSequencesLoopexpandafter{UD@firstoftwo{}#1}}%
                {}%
                }{%
                UD@CheckWhetherLeadingSpace{#1}{%
                UD@CheckWhetherNull{#3}{UD@Exchange{{#2}}}{UD@Exchange{{#2{#3}}}}%
                {expandafterUD@extractDigitSequencesLoopexpandafter{UD@gobblespace#1}}%
                {}%
                }{%
                expandafterUD@CheckWhetherdigit
                expandafter{romannumeral0UD@ExtractKthArgCheck{m}{#1}}{%
                expandafterexpandafterexpandafterUD@Exchange
                expandafterexpandafterexpandafter{%
                expandafterexpandafterexpandafter{%
                expandafterUD@Exchange
                expandafter{romannumeral0UD@ExtractKthArgCheck{m}{#1}}{#3}%
                }%
                }%
                {expandafterUD@extractDigitSequencesLoopexpandafter{UD@firstoftwo{}#1}{#2}}%
                }{%
                UD@CheckWhetherNull{#3}{UD@Exchange{{#2}}}{UD@Exchange{{#2{#3}}}}%
                {expandafterUD@extractDigitSequencesLoopexpandafter{UD@firstoftwo{}#1}}%
                {}%
                }%
                }%
                }%
                }%
                }%
                %%=============================================================================
                %% UD@ExtractKthDigitSequence{<integer K>}{<token sequence>}
                %%-----------------------------------------------------------------------------
                %% Extracts the K-th sequence of explicit character-tokens of category
                %% code 12 (other) that denote digits from <token sequence> if existent.
                %% Otherwise doesn't deliver any token.
                %%
                %% Due to romannumeral-expansion the result is delivered after two
                %% expansion-steps.
                %%.............................................................................
                newcommandUD@ExtractKthDigitSequence[2]{%
                romannumeral0%
                expandafterUD@Exchangeexpandafter{%
                expandafter{romannumeral0UD@extractDigitSequencesLoop{#2}{}{}}%
                }{%
                expandafterUD@ExtractKthArgCheck
                expandafter{romannumeralnumbernumber#1 000}%
                }%
                }%
                %%=============================================================================
                %% UD@ExtractDigitSequencesFromJobname
                %%-----------------------------------------------------------------------------
                %% Extracts sequences of explicit character tokens of category code 12
                %% that denote digits from the top-level-expansion of the control-word-
                %% token jobname, nests each such sequence into curly braces:
                %%
                %% E.g., if jobname = 00foo78Bar66, then
                %%
                %% UD@ExtractDigitSequencesFromJobname
                %%
                %% yields: {00}{78}{66}%
                %%
                %% E.g., if jobname = 00foo78Bar66Baz543BaT954, then
                %%
                %% UD@ExtractDigitSequencesFromJobname
                %%
                %% yields: {00}{78}{66}{543}{954}%
                %%
                %% Does not deliver any token in case <token sequence> does not contain
                %% explicit character-tokens of category code 12(other) that denote
                %% digits.
                %%
                %% Due to romannumeral-expansion the result is delivered after two
                %% expansion-steps.
                %%.............................................................................
                newcommandUD@ExtractDigitSequencesFromJobname{%
                romannumeral0%
                expandafterUD@extractDigitSequencesLoopexpandafter{jobname}{}{}%
                }%
                %%=============================================================================
                %% UD@ExtractKthDigitSequenceFromJobname{<integer K>}
                %%-----------------------------------------------------------------------------
                %% Extracts the K-th sequence of explicit character-tokens of category
                %% code 12 (other) that denote digits from the top-level-expansion of the
                %% control-word-token jobname if existent.
                %% Otherwise doesn't deliver any token.
                %%
                %% Due to romannumeral-expansion the result is delivered after two
                %% expansion-steps.
                %%.............................................................................
                newcommandUD@ExtractKthDigitSequenceFromJobname[1]{%
                romannumeral
                expandafterUD@Exchangeexpandafter{expandafter{jobname}}%
                {expandafterUD@secondoftwoUD@ExtractKthDigitSequence{#1}}%
                }%
                makeatother

                begin{document}

                makeatletter

                defbraceshowloop#1{%
                ifxrelax#1expandafterUD@firstoftwoelseexpandafterUD@secondoftwofi
                {}{{#1}braceshowloop}%
                }%

                noindent
                verb|UD@ExtractDigitSequences{{{32}54{}t 65zk_+} 8}|:
                expandafterexpandafterexpandafterbraceshowloop
                UD@ExtractDigitSequences{{{32}54{}t 65zk_+} 8}relax\
                verb|UD@ExtractKthDigitSequence{-1}{{{32}54{}t 65zk_+} 8}|:
                UD@ExtractKthDigitSequence{-1}{{{32}54{}t 65zk_+} 8}\
                verb|UD@ExtractKthDigitSequence{0}{{{32}54{}t 65zk_+} 8}|:
                UD@ExtractKthDigitSequence{0}{{{32}54{}t 65zk_+} 8}\
                verb|UD@ExtractKthDigitSequence{1}{{{32}54{}t 65zk_+} 8}|:
                UD@ExtractKthDigitSequence{1}{{{32}54{}t 65zk_+} 8}\
                verb|UD@ExtractKthDigitSequence{2}{{{32}54{}t 65zk_+} 8}|:
                UD@ExtractKthDigitSequence{2}{{{32}54{}t 65zk_+} 8}\
                verb|UD@ExtractKthDigitSequence{3}{{{32}54{}t 65zk_+} 8}|:
                UD@ExtractKthDigitSequence{3}{{{32}54{}t 65zk_+} 8}\
                verb|UD@ExtractKthDigitSequence{4}{{{32}54{}t 65zk_+} 8}|:
                UD@ExtractKthDigitSequence{4}{{{32}54{}t 65zk_+} 8}\
                verb|UD@ExtractKthDigitSequence{5}{{{32}54{}t 65zk_+} 8}|:
                UD@ExtractKthDigitSequence{5}{{{32}54{}t 65zk_+} 8}\
                verb|jobname|:
                jobname\
                verb|UD@ExtractDigitSequencesFromJobname|:
                expandafterexpandafterexpandafterbraceshowloop
                UD@ExtractDigitSequencesFromJobnamerelax\
                verb|UD@ExtractKthDigitSequenceFromJobname{-1}|:
                UD@ExtractKthDigitSequenceFromJobname{-1}\
                verb|UD@ExtractKthDigitSequenceFromJobname{0}|:
                UD@ExtractKthDigitSequenceFromJobname{0}\
                verb|UD@ExtractKthDigitSequenceFromJobname{1}|:
                UD@ExtractKthDigitSequenceFromJobname{1}\
                verb|UD@ExtractKthDigitSequenceFromJobname{2}|:
                UD@ExtractKthDigitSequenceFromJobname{2}\
                verb|UD@ExtractKthDigitSequenceFromJobname{3}|:
                UD@ExtractKthDigitSequenceFromJobname{3}\
                verb|UD@ExtractKthDigitSequenceFromJobname{4}|:
                UD@ExtractKthDigitSequenceFromJobname{4}\
                verb|UD@ExtractKthDigitSequenceFromJobname{5}|:
                UD@ExtractKthDigitSequenceFromJobname{5}\
                verb|UD@ExtractKthDigitSequenceFromJobname{6}|:
                UD@ExtractKthDigitSequenceFromJobname{6}\

                end{document}


                enter image description here







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Dec 12 at 10:43

























                answered Dec 12 at 3:44









                Ulrich Diez

                4,085615




                4,085615






























                    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.





                    Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                    Please pay close attention to the following guidance:


                    • 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%2f464025%2fpulling-numbers-out-of-a-file-name%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

                    If I really need a card on my start hand, how many mulligans make sense? [duplicate]

                    Alcedinidae

                    Can an atomic nucleus contain both particles and antiparticles? [duplicate]