Passing arguments to a macro hidden in the text

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











up vote
4
down vote

favorite












Context:



I'm trying to write a macro that behaves somewhat like C's printf family of functions. For instance, the following C code:



#include <stdio.h>
int main()

printf("Hello %s! Today's a good day to write obscure %s macros.n",
"World","TeX");



prints



Hello World! Today's a good day to write obscure TeX macros.


by replacing the first %s by "World" and the second %s by "TeX".



I'm trying to provide a similar syntax:



PrintfHello %! Today's a good day to write obscure % macros.
world,TeX


which should print the same sentence in TeX. Right now I'm failing because TeX is not C :)




The problem:



I can't find a way to pass the items in the second argument of Printf to % because the % macro can be hidden anywhere in the middle of the text.



A simple definition for Printf and % would be:



defPrintf#1#2%
#1% What do I do with #2?

def%% How do I define this macro?
:(%

PrintfHello %! Today's a good day to write obscure % macros.
world,TeX
bye


then the output would be: enter image description here



The question is: how do I define Printf and % such that it prints the correct sentence?




Requirements (because I'm picky :P):




  • The strongest requirement is that I would like the Printf function to be expandable, so that:



    edeftempaPrintfObscure %space Macros.TeX
    showtempa


    would print:



    > tempa=macro:
    ->Obscure TeX Macros..


  • It has to work inside brace groups. I tried a delimited macro approach that kind of worked, but failed miserably if the % appeared inside a brace pair1.


  • I would also like engine independence.


  • The syntax, on the other hand, can change slightly. That is, the Printftextreplacement. I would like to keep the % thingy :)



What I tried:



1Here's my attempt using % delimited macros. I like this approach better because I don't have to redefine the % control character anywhere. The downside is that it fails miserably when the % token appears inside a braced group. What a bold...



input expl3-generic.tex
ExplSyntaxOn
cs_generate_variant:Nn clist_item:nn nf
cs_set_eq:NN clistItem clist_item:nf
cs_new:Npn Printf #1 #2
__printf_step:nnn 0 #2 #1
cs_new:Npn __printf_step:nnn #1 #2 #3
__printf_step:nnw #1 #2 #3 % q_nil
cs_new:Npn __printf_step:nnw #1 #2 #3 % #4

#3
quark_if_nil:NF #4

exp_args:Nf __printf_percent:nn
int_eval:n #1 + 1 #2
exp_args:Nf __printf_step:nnw
int_eval:n #1 + 1 #2 #4


cs_new:Npn __printf_percent:nn #1 #2
clist_item:nn #2 #1
ExplSyntaxOff

PrintfHello %! Today's a good day to write obscure % macros.
world,TeX

PrintfOh, %, my macro doesn't work bf with % text. What a %dots
drat,bold,shame

bye


This prints:



enter image description here










share|improve this question

























    up vote
    4
    down vote

    favorite












    Context:



    I'm trying to write a macro that behaves somewhat like C's printf family of functions. For instance, the following C code:



    #include <stdio.h>
    int main()

    printf("Hello %s! Today's a good day to write obscure %s macros.n",
    "World","TeX");



    prints



    Hello World! Today's a good day to write obscure TeX macros.


    by replacing the first %s by "World" and the second %s by "TeX".



    I'm trying to provide a similar syntax:



    PrintfHello %! Today's a good day to write obscure % macros.
    world,TeX


    which should print the same sentence in TeX. Right now I'm failing because TeX is not C :)




    The problem:



    I can't find a way to pass the items in the second argument of Printf to % because the % macro can be hidden anywhere in the middle of the text.



    A simple definition for Printf and % would be:



    defPrintf#1#2%
    #1% What do I do with #2?

    def%% How do I define this macro?
    :(%

    PrintfHello %! Today's a good day to write obscure % macros.
    world,TeX
    bye


    then the output would be: enter image description here



    The question is: how do I define Printf and % such that it prints the correct sentence?




    Requirements (because I'm picky :P):




    • The strongest requirement is that I would like the Printf function to be expandable, so that:



      edeftempaPrintfObscure %space Macros.TeX
      showtempa


      would print:



      > tempa=macro:
      ->Obscure TeX Macros..


    • It has to work inside brace groups. I tried a delimited macro approach that kind of worked, but failed miserably if the % appeared inside a brace pair1.


    • I would also like engine independence.


    • The syntax, on the other hand, can change slightly. That is, the Printftextreplacement. I would like to keep the % thingy :)



    What I tried:



    1Here's my attempt using % delimited macros. I like this approach better because I don't have to redefine the % control character anywhere. The downside is that it fails miserably when the % token appears inside a braced group. What a bold...



    input expl3-generic.tex
    ExplSyntaxOn
    cs_generate_variant:Nn clist_item:nn nf
    cs_set_eq:NN clistItem clist_item:nf
    cs_new:Npn Printf #1 #2
    __printf_step:nnn 0 #2 #1
    cs_new:Npn __printf_step:nnn #1 #2 #3
    __printf_step:nnw #1 #2 #3 % q_nil
    cs_new:Npn __printf_step:nnw #1 #2 #3 % #4

    #3
    quark_if_nil:NF #4

    exp_args:Nf __printf_percent:nn
    int_eval:n #1 + 1 #2
    exp_args:Nf __printf_step:nnw
    int_eval:n #1 + 1 #2 #4


    cs_new:Npn __printf_percent:nn #1 #2
    clist_item:nn #2 #1
    ExplSyntaxOff

    PrintfHello %! Today's a good day to write obscure % macros.
    world,TeX

    PrintfOh, %, my macro doesn't work bf with % text. What a %dots
    drat,bold,shame

    bye


    This prints:



    enter image description here










    share|improve this question























      up vote
      4
      down vote

      favorite









      up vote
      4
      down vote

      favorite











      Context:



      I'm trying to write a macro that behaves somewhat like C's printf family of functions. For instance, the following C code:



      #include <stdio.h>
      int main()

      printf("Hello %s! Today's a good day to write obscure %s macros.n",
      "World","TeX");



      prints



      Hello World! Today's a good day to write obscure TeX macros.


      by replacing the first %s by "World" and the second %s by "TeX".



      I'm trying to provide a similar syntax:



      PrintfHello %! Today's a good day to write obscure % macros.
      world,TeX


      which should print the same sentence in TeX. Right now I'm failing because TeX is not C :)




      The problem:



      I can't find a way to pass the items in the second argument of Printf to % because the % macro can be hidden anywhere in the middle of the text.



      A simple definition for Printf and % would be:



      defPrintf#1#2%
      #1% What do I do with #2?

      def%% How do I define this macro?
      :(%

      PrintfHello %! Today's a good day to write obscure % macros.
      world,TeX
      bye


      then the output would be: enter image description here



      The question is: how do I define Printf and % such that it prints the correct sentence?




      Requirements (because I'm picky :P):




      • The strongest requirement is that I would like the Printf function to be expandable, so that:



        edeftempaPrintfObscure %space Macros.TeX
        showtempa


        would print:



        > tempa=macro:
        ->Obscure TeX Macros..


      • It has to work inside brace groups. I tried a delimited macro approach that kind of worked, but failed miserably if the % appeared inside a brace pair1.


      • I would also like engine independence.


      • The syntax, on the other hand, can change slightly. That is, the Printftextreplacement. I would like to keep the % thingy :)



      What I tried:



      1Here's my attempt using % delimited macros. I like this approach better because I don't have to redefine the % control character anywhere. The downside is that it fails miserably when the % token appears inside a braced group. What a bold...



      input expl3-generic.tex
      ExplSyntaxOn
      cs_generate_variant:Nn clist_item:nn nf
      cs_set_eq:NN clistItem clist_item:nf
      cs_new:Npn Printf #1 #2
      __printf_step:nnn 0 #2 #1
      cs_new:Npn __printf_step:nnn #1 #2 #3
      __printf_step:nnw #1 #2 #3 % q_nil
      cs_new:Npn __printf_step:nnw #1 #2 #3 % #4

      #3
      quark_if_nil:NF #4

      exp_args:Nf __printf_percent:nn
      int_eval:n #1 + 1 #2
      exp_args:Nf __printf_step:nnw
      int_eval:n #1 + 1 #2 #4


      cs_new:Npn __printf_percent:nn #1 #2
      clist_item:nn #2 #1
      ExplSyntaxOff

      PrintfHello %! Today's a good day to write obscure % macros.
      world,TeX

      PrintfOh, %, my macro doesn't work bf with % text. What a %dots
      drat,bold,shame

      bye


      This prints:



      enter image description here










      share|improve this question













      Context:



      I'm trying to write a macro that behaves somewhat like C's printf family of functions. For instance, the following C code:



      #include <stdio.h>
      int main()

      printf("Hello %s! Today's a good day to write obscure %s macros.n",
      "World","TeX");



      prints



      Hello World! Today's a good day to write obscure TeX macros.


      by replacing the first %s by "World" and the second %s by "TeX".



      I'm trying to provide a similar syntax:



      PrintfHello %! Today's a good day to write obscure % macros.
      world,TeX


      which should print the same sentence in TeX. Right now I'm failing because TeX is not C :)




      The problem:



      I can't find a way to pass the items in the second argument of Printf to % because the % macro can be hidden anywhere in the middle of the text.



      A simple definition for Printf and % would be:



      defPrintf#1#2%
      #1% What do I do with #2?

      def%% How do I define this macro?
      :(%

      PrintfHello %! Today's a good day to write obscure % macros.
      world,TeX
      bye


      then the output would be: enter image description here



      The question is: how do I define Printf and % such that it prints the correct sentence?




      Requirements (because I'm picky :P):




      • The strongest requirement is that I would like the Printf function to be expandable, so that:



        edeftempaPrintfObscure %space Macros.TeX
        showtempa


        would print:



        > tempa=macro:
        ->Obscure TeX Macros..


      • It has to work inside brace groups. I tried a delimited macro approach that kind of worked, but failed miserably if the % appeared inside a brace pair1.


      • I would also like engine independence.


      • The syntax, on the other hand, can change slightly. That is, the Printftextreplacement. I would like to keep the % thingy :)



      What I tried:



      1Here's my attempt using % delimited macros. I like this approach better because I don't have to redefine the % control character anywhere. The downside is that it fails miserably when the % token appears inside a braced group. What a bold...



      input expl3-generic.tex
      ExplSyntaxOn
      cs_generate_variant:Nn clist_item:nn nf
      cs_set_eq:NN clistItem clist_item:nf
      cs_new:Npn Printf #1 #2
      __printf_step:nnn 0 #2 #1
      cs_new:Npn __printf_step:nnn #1 #2 #3
      __printf_step:nnw #1 #2 #3 % q_nil
      cs_new:Npn __printf_step:nnw #1 #2 #3 % #4

      #3
      quark_if_nil:NF #4

      exp_args:Nf __printf_percent:nn
      int_eval:n #1 + 1 #2
      exp_args:Nf __printf_step:nnw
      int_eval:n #1 + 1 #2 #4


      cs_new:Npn __printf_percent:nn #1 #2
      clist_item:nn #2 #1
      ExplSyntaxOff

      PrintfHello %! Today's a good day to write obscure % macros.
      world,TeX

      PrintfOh, %, my macro doesn't work bf with % text. What a %dots
      drat,bold,shame

      bye


      This prints:



      enter image description here







      macros expansion expl3






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked 1 hour ago









      Phelype Oleinik

      19.5k54275




      19.5k54275




















          2 Answers
          2






          active

          oldest

          votes

















          up vote
          5
          down vote













          Regular expressions are your friend! You can step through the clist of arguments and use regex_replace_once:nnN to replace each one in turn in a token list for the printed text to produce:



          enter image description here



          This approach is shorter too! Here's the code:



          input expl3-generic.tex

          ExplSyntaxOn
          clist_new:N l_printf_args_clist
          tl_new:N l_printf_tl
          cs_new:Npn Printf #1 #2

          tl_set:Nn l_printf_tl #1
          clist_set:Nn l_printf_args_clist #2
          clist_map_inline:Nn l_printf_args_clist
          regex_replace_once:nnN c% ##1 l_printf_tl

          tl_use:N l_printf_tl

          ExplSyntaxOff

          PrintfHello %! Today's a good day to write obscure % macros.
          world,TeX

          PrintfOh, %, my macro doesn't work bf with % text. What a %dots
          drat,bold,shame

          bye


          Hmm, although this may not fit the expandability requirement...






          share|improve this answer






















          • Hmmm... I didn't think of regular expressions. They do make things work. But the regex functions aren't expandable (as you noted yourself while I was writing this). But it's a nice idea nonetheless :)
            – Phelype Oleinik
            36 mins ago

















          up vote
          4
          down vote













          Totally insane, of course, but doable! Here, I use the same approach as in for example tl_lower_case:n. We step through the tokens, examining each one. There are three cases, a brace group, a space, and a 'normal' token. In the latter case, we split between % and anything else. The only tricky part is tracking the substitution number inside brace groups. I do that by keeping the tracking number at the 'top level', and 'passing back' the number from inside any brace groups before they are added to the 'output'.



          input expl3-generic.tex
          ExplSyntaxOn
          cs_generate_variant:Nn clist_item:nn nf
          cs_set_eq:NN clistItem clist_item:nf
          cs_new:Npn Printf #1#2

          __kernel_exp_not:w exp_after:wN

          exp:w
          exp_args:Nf __printf_outer:n __printf:nnn 1 #1 #2


          cs_new:Npn __printf_outer:n #1
          __printf_outer:nn #1
          cs_new:Npn __printf_outer:nn #1#2

          exp_end:
          #1

          cs_new:Npn __printf:nnn #1#2#3

          group_align_safe_begin:
          __printf_loop:w
          #2 q_recursion_tail q_recursion_stop #3
          __printf_result:nn #1

          cs_new:Npn __printf_loop:w #1 q_recursion_stop

          tl_if_head_is_N_type:nTF #1
          __printf_N_type:N

          tl_if_head_is_group:nTF #1
          __printf_group:nw
          __printf_space:w

          #1 q_recursion_stop

          cs_new:Npn __printf_N_type:N #1

          quark_if_recursion_tail_stop_do:Nn #1
          __printf_end:w
          token_if_eq_meaning:NNTF #1 %
          __printf_N_type:w

          __printf_output:nw #1
          __printf_loop:w


          cs_new:Npn __printf_N_type:w #1 q_recursion_stop #2 __printf_result:nn #3#4

          exp_args:Nff __printf_N_type:nnnnn
          clist_item:nn #2 #4
          int_eval:n #4 + 1
          #1 #2 #3

          cs_new:Npn __printf_N_type:nnnnn #1#2#3#4#5

          __printf_loop:w #3 q_recursion_stop
          #4
          __printf_result:nn #5 #1 #2

          cs_new:Npn __printf_group:nw #1#2 q_recursion_stop #3 __printf_result:nn #4#5

          exp_args:Nf __printf_group:nnnn
          __printf:nnn #5 #1 #3
          #2 #3 #4

          cs_new:Npn __printf_group:nnnn #1#2#3#4
          __printf_group:nnnnn #1 #2 #3 #4
          cs_new:Npn __printf_group:nnnnn #1#2#3#4#5

          __printf_loop:w #3 q_recursion_stop
          #4
          __printf_result:nn #5 #1 #2

          exp_last_unbraced:NNo cs_new:Npn __printf_space:w c_space_tl

          __printf_output:nw ~
          __printf_loop:w

          cs_new:Npn __printf_output:nw #1#2 __printf_result:nn #3
          #2 __printf_result:nn #3 #1
          cs_new:Npn __printf_end:w #1 __printf_result:nn

          group_align_safe_end:


          ExplSyntaxOff

          PrintfHello %! Today's a good day to write obscure % macros.
          world,TeX

          PrintfOh, %, my macro doesn't work bf with % text. What a %dots
          drat,bold,shame

          bye





          share|improve this answer




















          • Basic idea here is from __tl_act:NNNnn, used internally in the kernel: one of Bruno's. You can't directly use that here, which is much the same as tl_lower_case:n, due to the need to keep extra data on the stack. But it's fundamentally Bruno's approach ...
            – Joseph Wright♦
            17 mins ago










          • Note: I've not worried about preventing f-type expansion of the replacement text. That would be doable (if for example you want to examine the tokens in the case of adding TeX), but I'll leave as an exercise for the reader :) [Hint: see tl_lower_case:n]
            – Joseph Wright♦
            16 mins ago










          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',
          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%2f457787%2fpassing-arguments-to-a-macro-hidden-in-the-text%23new-answer', 'question_page');

          );

          Post as a guest






























          2 Answers
          2






          active

          oldest

          votes








          2 Answers
          2






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          5
          down vote













          Regular expressions are your friend! You can step through the clist of arguments and use regex_replace_once:nnN to replace each one in turn in a token list for the printed text to produce:



          enter image description here



          This approach is shorter too! Here's the code:



          input expl3-generic.tex

          ExplSyntaxOn
          clist_new:N l_printf_args_clist
          tl_new:N l_printf_tl
          cs_new:Npn Printf #1 #2

          tl_set:Nn l_printf_tl #1
          clist_set:Nn l_printf_args_clist #2
          clist_map_inline:Nn l_printf_args_clist
          regex_replace_once:nnN c% ##1 l_printf_tl

          tl_use:N l_printf_tl

          ExplSyntaxOff

          PrintfHello %! Today's a good day to write obscure % macros.
          world,TeX

          PrintfOh, %, my macro doesn't work bf with % text. What a %dots
          drat,bold,shame

          bye


          Hmm, although this may not fit the expandability requirement...






          share|improve this answer






















          • Hmmm... I didn't think of regular expressions. They do make things work. But the regex functions aren't expandable (as you noted yourself while I was writing this). But it's a nice idea nonetheless :)
            – Phelype Oleinik
            36 mins ago














          up vote
          5
          down vote













          Regular expressions are your friend! You can step through the clist of arguments and use regex_replace_once:nnN to replace each one in turn in a token list for the printed text to produce:



          enter image description here



          This approach is shorter too! Here's the code:



          input expl3-generic.tex

          ExplSyntaxOn
          clist_new:N l_printf_args_clist
          tl_new:N l_printf_tl
          cs_new:Npn Printf #1 #2

          tl_set:Nn l_printf_tl #1
          clist_set:Nn l_printf_args_clist #2
          clist_map_inline:Nn l_printf_args_clist
          regex_replace_once:nnN c% ##1 l_printf_tl

          tl_use:N l_printf_tl

          ExplSyntaxOff

          PrintfHello %! Today's a good day to write obscure % macros.
          world,TeX

          PrintfOh, %, my macro doesn't work bf with % text. What a %dots
          drat,bold,shame

          bye


          Hmm, although this may not fit the expandability requirement...






          share|improve this answer






















          • Hmmm... I didn't think of regular expressions. They do make things work. But the regex functions aren't expandable (as you noted yourself while I was writing this). But it's a nice idea nonetheless :)
            – Phelype Oleinik
            36 mins ago












          up vote
          5
          down vote










          up vote
          5
          down vote









          Regular expressions are your friend! You can step through the clist of arguments and use regex_replace_once:nnN to replace each one in turn in a token list for the printed text to produce:



          enter image description here



          This approach is shorter too! Here's the code:



          input expl3-generic.tex

          ExplSyntaxOn
          clist_new:N l_printf_args_clist
          tl_new:N l_printf_tl
          cs_new:Npn Printf #1 #2

          tl_set:Nn l_printf_tl #1
          clist_set:Nn l_printf_args_clist #2
          clist_map_inline:Nn l_printf_args_clist
          regex_replace_once:nnN c% ##1 l_printf_tl

          tl_use:N l_printf_tl

          ExplSyntaxOff

          PrintfHello %! Today's a good day to write obscure % macros.
          world,TeX

          PrintfOh, %, my macro doesn't work bf with % text. What a %dots
          drat,bold,shame

          bye


          Hmm, although this may not fit the expandability requirement...






          share|improve this answer














          Regular expressions are your friend! You can step through the clist of arguments and use regex_replace_once:nnN to replace each one in turn in a token list for the printed text to produce:



          enter image description here



          This approach is shorter too! Here's the code:



          input expl3-generic.tex

          ExplSyntaxOn
          clist_new:N l_printf_args_clist
          tl_new:N l_printf_tl
          cs_new:Npn Printf #1 #2

          tl_set:Nn l_printf_tl #1
          clist_set:Nn l_printf_args_clist #2
          clist_map_inline:Nn l_printf_args_clist
          regex_replace_once:nnN c% ##1 l_printf_tl

          tl_use:N l_printf_tl

          ExplSyntaxOff

          PrintfHello %! Today's a good day to write obscure % macros.
          world,TeX

          PrintfOh, %, my macro doesn't work bf with % text. What a %dots
          drat,bold,shame

          bye


          Hmm, although this may not fit the expandability requirement...







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited 37 mins ago

























          answered 42 mins ago









          Andrew

          28.6k34075




          28.6k34075











          • Hmmm... I didn't think of regular expressions. They do make things work. But the regex functions aren't expandable (as you noted yourself while I was writing this). But it's a nice idea nonetheless :)
            – Phelype Oleinik
            36 mins ago
















          • Hmmm... I didn't think of regular expressions. They do make things work. But the regex functions aren't expandable (as you noted yourself while I was writing this). But it's a nice idea nonetheless :)
            – Phelype Oleinik
            36 mins ago















          Hmmm... I didn't think of regular expressions. They do make things work. But the regex functions aren't expandable (as you noted yourself while I was writing this). But it's a nice idea nonetheless :)
          – Phelype Oleinik
          36 mins ago




          Hmmm... I didn't think of regular expressions. They do make things work. But the regex functions aren't expandable (as you noted yourself while I was writing this). But it's a nice idea nonetheless :)
          – Phelype Oleinik
          36 mins ago










          up vote
          4
          down vote













          Totally insane, of course, but doable! Here, I use the same approach as in for example tl_lower_case:n. We step through the tokens, examining each one. There are three cases, a brace group, a space, and a 'normal' token. In the latter case, we split between % and anything else. The only tricky part is tracking the substitution number inside brace groups. I do that by keeping the tracking number at the 'top level', and 'passing back' the number from inside any brace groups before they are added to the 'output'.



          input expl3-generic.tex
          ExplSyntaxOn
          cs_generate_variant:Nn clist_item:nn nf
          cs_set_eq:NN clistItem clist_item:nf
          cs_new:Npn Printf #1#2

          __kernel_exp_not:w exp_after:wN

          exp:w
          exp_args:Nf __printf_outer:n __printf:nnn 1 #1 #2


          cs_new:Npn __printf_outer:n #1
          __printf_outer:nn #1
          cs_new:Npn __printf_outer:nn #1#2

          exp_end:
          #1

          cs_new:Npn __printf:nnn #1#2#3

          group_align_safe_begin:
          __printf_loop:w
          #2 q_recursion_tail q_recursion_stop #3
          __printf_result:nn #1

          cs_new:Npn __printf_loop:w #1 q_recursion_stop

          tl_if_head_is_N_type:nTF #1
          __printf_N_type:N

          tl_if_head_is_group:nTF #1
          __printf_group:nw
          __printf_space:w

          #1 q_recursion_stop

          cs_new:Npn __printf_N_type:N #1

          quark_if_recursion_tail_stop_do:Nn #1
          __printf_end:w
          token_if_eq_meaning:NNTF #1 %
          __printf_N_type:w

          __printf_output:nw #1
          __printf_loop:w


          cs_new:Npn __printf_N_type:w #1 q_recursion_stop #2 __printf_result:nn #3#4

          exp_args:Nff __printf_N_type:nnnnn
          clist_item:nn #2 #4
          int_eval:n #4 + 1
          #1 #2 #3

          cs_new:Npn __printf_N_type:nnnnn #1#2#3#4#5

          __printf_loop:w #3 q_recursion_stop
          #4
          __printf_result:nn #5 #1 #2

          cs_new:Npn __printf_group:nw #1#2 q_recursion_stop #3 __printf_result:nn #4#5

          exp_args:Nf __printf_group:nnnn
          __printf:nnn #5 #1 #3
          #2 #3 #4

          cs_new:Npn __printf_group:nnnn #1#2#3#4
          __printf_group:nnnnn #1 #2 #3 #4
          cs_new:Npn __printf_group:nnnnn #1#2#3#4#5

          __printf_loop:w #3 q_recursion_stop
          #4
          __printf_result:nn #5 #1 #2

          exp_last_unbraced:NNo cs_new:Npn __printf_space:w c_space_tl

          __printf_output:nw ~
          __printf_loop:w

          cs_new:Npn __printf_output:nw #1#2 __printf_result:nn #3
          #2 __printf_result:nn #3 #1
          cs_new:Npn __printf_end:w #1 __printf_result:nn

          group_align_safe_end:


          ExplSyntaxOff

          PrintfHello %! Today's a good day to write obscure % macros.
          world,TeX

          PrintfOh, %, my macro doesn't work bf with % text. What a %dots
          drat,bold,shame

          bye





          share|improve this answer




















          • Basic idea here is from __tl_act:NNNnn, used internally in the kernel: one of Bruno's. You can't directly use that here, which is much the same as tl_lower_case:n, due to the need to keep extra data on the stack. But it's fundamentally Bruno's approach ...
            – Joseph Wright♦
            17 mins ago










          • Note: I've not worried about preventing f-type expansion of the replacement text. That would be doable (if for example you want to examine the tokens in the case of adding TeX), but I'll leave as an exercise for the reader :) [Hint: see tl_lower_case:n]
            – Joseph Wright♦
            16 mins ago














          up vote
          4
          down vote













          Totally insane, of course, but doable! Here, I use the same approach as in for example tl_lower_case:n. We step through the tokens, examining each one. There are three cases, a brace group, a space, and a 'normal' token. In the latter case, we split between % and anything else. The only tricky part is tracking the substitution number inside brace groups. I do that by keeping the tracking number at the 'top level', and 'passing back' the number from inside any brace groups before they are added to the 'output'.



          input expl3-generic.tex
          ExplSyntaxOn
          cs_generate_variant:Nn clist_item:nn nf
          cs_set_eq:NN clistItem clist_item:nf
          cs_new:Npn Printf #1#2

          __kernel_exp_not:w exp_after:wN

          exp:w
          exp_args:Nf __printf_outer:n __printf:nnn 1 #1 #2


          cs_new:Npn __printf_outer:n #1
          __printf_outer:nn #1
          cs_new:Npn __printf_outer:nn #1#2

          exp_end:
          #1

          cs_new:Npn __printf:nnn #1#2#3

          group_align_safe_begin:
          __printf_loop:w
          #2 q_recursion_tail q_recursion_stop #3
          __printf_result:nn #1

          cs_new:Npn __printf_loop:w #1 q_recursion_stop

          tl_if_head_is_N_type:nTF #1
          __printf_N_type:N

          tl_if_head_is_group:nTF #1
          __printf_group:nw
          __printf_space:w

          #1 q_recursion_stop

          cs_new:Npn __printf_N_type:N #1

          quark_if_recursion_tail_stop_do:Nn #1
          __printf_end:w
          token_if_eq_meaning:NNTF #1 %
          __printf_N_type:w

          __printf_output:nw #1
          __printf_loop:w


          cs_new:Npn __printf_N_type:w #1 q_recursion_stop #2 __printf_result:nn #3#4

          exp_args:Nff __printf_N_type:nnnnn
          clist_item:nn #2 #4
          int_eval:n #4 + 1
          #1 #2 #3

          cs_new:Npn __printf_N_type:nnnnn #1#2#3#4#5

          __printf_loop:w #3 q_recursion_stop
          #4
          __printf_result:nn #5 #1 #2

          cs_new:Npn __printf_group:nw #1#2 q_recursion_stop #3 __printf_result:nn #4#5

          exp_args:Nf __printf_group:nnnn
          __printf:nnn #5 #1 #3
          #2 #3 #4

          cs_new:Npn __printf_group:nnnn #1#2#3#4
          __printf_group:nnnnn #1 #2 #3 #4
          cs_new:Npn __printf_group:nnnnn #1#2#3#4#5

          __printf_loop:w #3 q_recursion_stop
          #4
          __printf_result:nn #5 #1 #2

          exp_last_unbraced:NNo cs_new:Npn __printf_space:w c_space_tl

          __printf_output:nw ~
          __printf_loop:w

          cs_new:Npn __printf_output:nw #1#2 __printf_result:nn #3
          #2 __printf_result:nn #3 #1
          cs_new:Npn __printf_end:w #1 __printf_result:nn

          group_align_safe_end:


          ExplSyntaxOff

          PrintfHello %! Today's a good day to write obscure % macros.
          world,TeX

          PrintfOh, %, my macro doesn't work bf with % text. What a %dots
          drat,bold,shame

          bye





          share|improve this answer




















          • Basic idea here is from __tl_act:NNNnn, used internally in the kernel: one of Bruno's. You can't directly use that here, which is much the same as tl_lower_case:n, due to the need to keep extra data on the stack. But it's fundamentally Bruno's approach ...
            – Joseph Wright♦
            17 mins ago










          • Note: I've not worried about preventing f-type expansion of the replacement text. That would be doable (if for example you want to examine the tokens in the case of adding TeX), but I'll leave as an exercise for the reader :) [Hint: see tl_lower_case:n]
            – Joseph Wright♦
            16 mins ago












          up vote
          4
          down vote










          up vote
          4
          down vote









          Totally insane, of course, but doable! Here, I use the same approach as in for example tl_lower_case:n. We step through the tokens, examining each one. There are three cases, a brace group, a space, and a 'normal' token. In the latter case, we split between % and anything else. The only tricky part is tracking the substitution number inside brace groups. I do that by keeping the tracking number at the 'top level', and 'passing back' the number from inside any brace groups before they are added to the 'output'.



          input expl3-generic.tex
          ExplSyntaxOn
          cs_generate_variant:Nn clist_item:nn nf
          cs_set_eq:NN clistItem clist_item:nf
          cs_new:Npn Printf #1#2

          __kernel_exp_not:w exp_after:wN

          exp:w
          exp_args:Nf __printf_outer:n __printf:nnn 1 #1 #2


          cs_new:Npn __printf_outer:n #1
          __printf_outer:nn #1
          cs_new:Npn __printf_outer:nn #1#2

          exp_end:
          #1

          cs_new:Npn __printf:nnn #1#2#3

          group_align_safe_begin:
          __printf_loop:w
          #2 q_recursion_tail q_recursion_stop #3
          __printf_result:nn #1

          cs_new:Npn __printf_loop:w #1 q_recursion_stop

          tl_if_head_is_N_type:nTF #1
          __printf_N_type:N

          tl_if_head_is_group:nTF #1
          __printf_group:nw
          __printf_space:w

          #1 q_recursion_stop

          cs_new:Npn __printf_N_type:N #1

          quark_if_recursion_tail_stop_do:Nn #1
          __printf_end:w
          token_if_eq_meaning:NNTF #1 %
          __printf_N_type:w

          __printf_output:nw #1
          __printf_loop:w


          cs_new:Npn __printf_N_type:w #1 q_recursion_stop #2 __printf_result:nn #3#4

          exp_args:Nff __printf_N_type:nnnnn
          clist_item:nn #2 #4
          int_eval:n #4 + 1
          #1 #2 #3

          cs_new:Npn __printf_N_type:nnnnn #1#2#3#4#5

          __printf_loop:w #3 q_recursion_stop
          #4
          __printf_result:nn #5 #1 #2

          cs_new:Npn __printf_group:nw #1#2 q_recursion_stop #3 __printf_result:nn #4#5

          exp_args:Nf __printf_group:nnnn
          __printf:nnn #5 #1 #3
          #2 #3 #4

          cs_new:Npn __printf_group:nnnn #1#2#3#4
          __printf_group:nnnnn #1 #2 #3 #4
          cs_new:Npn __printf_group:nnnnn #1#2#3#4#5

          __printf_loop:w #3 q_recursion_stop
          #4
          __printf_result:nn #5 #1 #2

          exp_last_unbraced:NNo cs_new:Npn __printf_space:w c_space_tl

          __printf_output:nw ~
          __printf_loop:w

          cs_new:Npn __printf_output:nw #1#2 __printf_result:nn #3
          #2 __printf_result:nn #3 #1
          cs_new:Npn __printf_end:w #1 __printf_result:nn

          group_align_safe_end:


          ExplSyntaxOff

          PrintfHello %! Today's a good day to write obscure % macros.
          world,TeX

          PrintfOh, %, my macro doesn't work bf with % text. What a %dots
          drat,bold,shame

          bye





          share|improve this answer












          Totally insane, of course, but doable! Here, I use the same approach as in for example tl_lower_case:n. We step through the tokens, examining each one. There are three cases, a brace group, a space, and a 'normal' token. In the latter case, we split between % and anything else. The only tricky part is tracking the substitution number inside brace groups. I do that by keeping the tracking number at the 'top level', and 'passing back' the number from inside any brace groups before they are added to the 'output'.



          input expl3-generic.tex
          ExplSyntaxOn
          cs_generate_variant:Nn clist_item:nn nf
          cs_set_eq:NN clistItem clist_item:nf
          cs_new:Npn Printf #1#2

          __kernel_exp_not:w exp_after:wN

          exp:w
          exp_args:Nf __printf_outer:n __printf:nnn 1 #1 #2


          cs_new:Npn __printf_outer:n #1
          __printf_outer:nn #1
          cs_new:Npn __printf_outer:nn #1#2

          exp_end:
          #1

          cs_new:Npn __printf:nnn #1#2#3

          group_align_safe_begin:
          __printf_loop:w
          #2 q_recursion_tail q_recursion_stop #3
          __printf_result:nn #1

          cs_new:Npn __printf_loop:w #1 q_recursion_stop

          tl_if_head_is_N_type:nTF #1
          __printf_N_type:N

          tl_if_head_is_group:nTF #1
          __printf_group:nw
          __printf_space:w

          #1 q_recursion_stop

          cs_new:Npn __printf_N_type:N #1

          quark_if_recursion_tail_stop_do:Nn #1
          __printf_end:w
          token_if_eq_meaning:NNTF #1 %
          __printf_N_type:w

          __printf_output:nw #1
          __printf_loop:w


          cs_new:Npn __printf_N_type:w #1 q_recursion_stop #2 __printf_result:nn #3#4

          exp_args:Nff __printf_N_type:nnnnn
          clist_item:nn #2 #4
          int_eval:n #4 + 1
          #1 #2 #3

          cs_new:Npn __printf_N_type:nnnnn #1#2#3#4#5

          __printf_loop:w #3 q_recursion_stop
          #4
          __printf_result:nn #5 #1 #2

          cs_new:Npn __printf_group:nw #1#2 q_recursion_stop #3 __printf_result:nn #4#5

          exp_args:Nf __printf_group:nnnn
          __printf:nnn #5 #1 #3
          #2 #3 #4

          cs_new:Npn __printf_group:nnnn #1#2#3#4
          __printf_group:nnnnn #1 #2 #3 #4
          cs_new:Npn __printf_group:nnnnn #1#2#3#4#5

          __printf_loop:w #3 q_recursion_stop
          #4
          __printf_result:nn #5 #1 #2

          exp_last_unbraced:NNo cs_new:Npn __printf_space:w c_space_tl

          __printf_output:nw ~
          __printf_loop:w

          cs_new:Npn __printf_output:nw #1#2 __printf_result:nn #3
          #2 __printf_result:nn #3 #1
          cs_new:Npn __printf_end:w #1 __printf_result:nn

          group_align_safe_end:


          ExplSyntaxOff

          PrintfHello %! Today's a good day to write obscure % macros.
          world,TeX

          PrintfOh, %, my macro doesn't work bf with % text. What a %dots
          drat,bold,shame

          bye






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered 19 mins ago









          Joseph Wright♦

          199k21549870




          199k21549870











          • Basic idea here is from __tl_act:NNNnn, used internally in the kernel: one of Bruno's. You can't directly use that here, which is much the same as tl_lower_case:n, due to the need to keep extra data on the stack. But it's fundamentally Bruno's approach ...
            – Joseph Wright♦
            17 mins ago










          • Note: I've not worried about preventing f-type expansion of the replacement text. That would be doable (if for example you want to examine the tokens in the case of adding TeX), but I'll leave as an exercise for the reader :) [Hint: see tl_lower_case:n]
            – Joseph Wright♦
            16 mins ago
















          • Basic idea here is from __tl_act:NNNnn, used internally in the kernel: one of Bruno's. You can't directly use that here, which is much the same as tl_lower_case:n, due to the need to keep extra data on the stack. But it's fundamentally Bruno's approach ...
            – Joseph Wright♦
            17 mins ago










          • Note: I've not worried about preventing f-type expansion of the replacement text. That would be doable (if for example you want to examine the tokens in the case of adding TeX), but I'll leave as an exercise for the reader :) [Hint: see tl_lower_case:n]
            – Joseph Wright♦
            16 mins ago















          Basic idea here is from __tl_act:NNNnn, used internally in the kernel: one of Bruno's. You can't directly use that here, which is much the same as tl_lower_case:n, due to the need to keep extra data on the stack. But it's fundamentally Bruno's approach ...
          – Joseph Wright♦
          17 mins ago




          Basic idea here is from __tl_act:NNNnn, used internally in the kernel: one of Bruno's. You can't directly use that here, which is much the same as tl_lower_case:n, due to the need to keep extra data on the stack. But it's fundamentally Bruno's approach ...
          – Joseph Wright♦
          17 mins ago












          Note: I've not worried about preventing f-type expansion of the replacement text. That would be doable (if for example you want to examine the tokens in the case of adding TeX), but I'll leave as an exercise for the reader :) [Hint: see tl_lower_case:n]
          – Joseph Wright♦
          16 mins ago




          Note: I've not worried about preventing f-type expansion of the replacement text. That would be doable (if for example you want to examine the tokens in the case of adding TeX), but I'll leave as an exercise for the reader :) [Hint: see tl_lower_case:n]
          – Joseph Wright♦
          16 mins ago

















           

          draft saved


          draft discarded















































           


          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f457787%2fpassing-arguments-to-a-macro-hidden-in-the-text%23new-answer', 'question_page');

          );

          Post as a guest













































































          Comments

          Popular posts from this blog

          What does second last employer means? [closed]

          Installing NextGIS Connect into QGIS 3?

          One-line joke