Iterate over tokens












4














Assume I have a macro like



defmyMacro#1{<some stuff>}


And I am calling it like this



myMacro{There are some arguments in here g}


How can I iterate over each single token in the #1 argument inside myMacro? So basically I want to know how I can iterate over a list whose delimiter is not a comma or any other character but rather the token boundaries as applied by TeX. Note that the argument may contain control sequences that are undefined so they must not be expanded.



Example of what I mean:



defmyMacro#1{<iterate over all tokens>|string<current token>|}
myMacro{A test}


which should result in



|A|| ||test|


It is important to note that I also care about spaces so they shouldn't be gobbled away. Also I don't want to execute any code outside of mymacro in order for this to work (e.g. changing the catcode of spaces before calling myMacro).



As I am really into understanding how such a thing works I'd appreciate if you could also explain how and why your provided code works :)





My attempt at this was



defiterate#1{%
tokenGrabber#1relax<!;!>%
}
deftokenGrabber#1#2<!;!>{%
|string#1|%
noexpandarg%
IfStrEq{#2}{relax}{%
}{%
tokenGrabber#2<!;!>%
}%
}


But this gobbles away spaces and it produces an error for empty inputs or inputs ending with a space.










share|improve this question






















  • Does the solution need to be expandable? It's not possible to get the charcode of {/} if it does ...
    – Joseph Wright
    Dec 15 at 9:54










  • @JosephWright It would be nice if it was but I am primarily interested in the principle, so I don't care too much about it...
    – Raven
    Dec 15 at 9:57










  • given a{xyz}b do you want to iterate three times, with a, xyz and b or 7 times with a, {, x, y,z,},b and it is presumably Ok to use something like bgroup for { as you can't hold an unmatched brace in a macro.
    – David Carlisle
    Dec 15 at 10:07












  • @DavidCarlisle 7 times - though I'd also be interested in the other alternative but I guess that is another story
    – Raven
    Dec 15 at 10:27






  • 1




    it's not really just edge cases, the mechanism you choose affects pretty much all uses, I've added an answer but I'll add some notes about the consequences of this design.
    – David Carlisle
    Dec 15 at 11:20
















4














Assume I have a macro like



defmyMacro#1{<some stuff>}


And I am calling it like this



myMacro{There are some arguments in here g}


How can I iterate over each single token in the #1 argument inside myMacro? So basically I want to know how I can iterate over a list whose delimiter is not a comma or any other character but rather the token boundaries as applied by TeX. Note that the argument may contain control sequences that are undefined so they must not be expanded.



Example of what I mean:



defmyMacro#1{<iterate over all tokens>|string<current token>|}
myMacro{A test}


which should result in



|A|| ||test|


It is important to note that I also care about spaces so they shouldn't be gobbled away. Also I don't want to execute any code outside of mymacro in order for this to work (e.g. changing the catcode of spaces before calling myMacro).



As I am really into understanding how such a thing works I'd appreciate if you could also explain how and why your provided code works :)





My attempt at this was



defiterate#1{%
tokenGrabber#1relax<!;!>%
}
deftokenGrabber#1#2<!;!>{%
|string#1|%
noexpandarg%
IfStrEq{#2}{relax}{%
}{%
tokenGrabber#2<!;!>%
}%
}


But this gobbles away spaces and it produces an error for empty inputs or inputs ending with a space.










share|improve this question






















  • Does the solution need to be expandable? It's not possible to get the charcode of {/} if it does ...
    – Joseph Wright
    Dec 15 at 9:54










  • @JosephWright It would be nice if it was but I am primarily interested in the principle, so I don't care too much about it...
    – Raven
    Dec 15 at 9:57










  • given a{xyz}b do you want to iterate three times, with a, xyz and b or 7 times with a, {, x, y,z,},b and it is presumably Ok to use something like bgroup for { as you can't hold an unmatched brace in a macro.
    – David Carlisle
    Dec 15 at 10:07












  • @DavidCarlisle 7 times - though I'd also be interested in the other alternative but I guess that is another story
    – Raven
    Dec 15 at 10:27






  • 1




    it's not really just edge cases, the mechanism you choose affects pretty much all uses, I've added an answer but I'll add some notes about the consequences of this design.
    – David Carlisle
    Dec 15 at 11:20














4












4








4







Assume I have a macro like



defmyMacro#1{<some stuff>}


And I am calling it like this



myMacro{There are some arguments in here g}


How can I iterate over each single token in the #1 argument inside myMacro? So basically I want to know how I can iterate over a list whose delimiter is not a comma or any other character but rather the token boundaries as applied by TeX. Note that the argument may contain control sequences that are undefined so they must not be expanded.



Example of what I mean:



defmyMacro#1{<iterate over all tokens>|string<current token>|}
myMacro{A test}


which should result in



|A|| ||test|


It is important to note that I also care about spaces so they shouldn't be gobbled away. Also I don't want to execute any code outside of mymacro in order for this to work (e.g. changing the catcode of spaces before calling myMacro).



As I am really into understanding how such a thing works I'd appreciate if you could also explain how and why your provided code works :)





My attempt at this was



defiterate#1{%
tokenGrabber#1relax<!;!>%
}
deftokenGrabber#1#2<!;!>{%
|string#1|%
noexpandarg%
IfStrEq{#2}{relax}{%
}{%
tokenGrabber#2<!;!>%
}%
}


But this gobbles away spaces and it produces an error for empty inputs or inputs ending with a space.










share|improve this question













Assume I have a macro like



defmyMacro#1{<some stuff>}


And I am calling it like this



myMacro{There are some arguments in here g}


How can I iterate over each single token in the #1 argument inside myMacro? So basically I want to know how I can iterate over a list whose delimiter is not a comma or any other character but rather the token boundaries as applied by TeX. Note that the argument may contain control sequences that are undefined so they must not be expanded.



Example of what I mean:



defmyMacro#1{<iterate over all tokens>|string<current token>|}
myMacro{A test}


which should result in



|A|| ||test|


It is important to note that I also care about spaces so they shouldn't be gobbled away. Also I don't want to execute any code outside of mymacro in order for this to work (e.g. changing the catcode of spaces before calling myMacro).



As I am really into understanding how such a thing works I'd appreciate if you could also explain how and why your provided code works :)





My attempt at this was



defiterate#1{%
tokenGrabber#1relax<!;!>%
}
deftokenGrabber#1#2<!;!>{%
|string#1|%
noexpandarg%
IfStrEq{#2}{relax}{%
}{%
tokenGrabber#2<!;!>%
}%
}


But this gobbles away spaces and it produces an error for empty inputs or inputs ending with a space.







tex-core






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Dec 15 at 9:48









Raven

806111




806111












  • Does the solution need to be expandable? It's not possible to get the charcode of {/} if it does ...
    – Joseph Wright
    Dec 15 at 9:54










  • @JosephWright It would be nice if it was but I am primarily interested in the principle, so I don't care too much about it...
    – Raven
    Dec 15 at 9:57










  • given a{xyz}b do you want to iterate three times, with a, xyz and b or 7 times with a, {, x, y,z,},b and it is presumably Ok to use something like bgroup for { as you can't hold an unmatched brace in a macro.
    – David Carlisle
    Dec 15 at 10:07












  • @DavidCarlisle 7 times - though I'd also be interested in the other alternative but I guess that is another story
    – Raven
    Dec 15 at 10:27






  • 1




    it's not really just edge cases, the mechanism you choose affects pretty much all uses, I've added an answer but I'll add some notes about the consequences of this design.
    – David Carlisle
    Dec 15 at 11:20


















  • Does the solution need to be expandable? It's not possible to get the charcode of {/} if it does ...
    – Joseph Wright
    Dec 15 at 9:54










  • @JosephWright It would be nice if it was but I am primarily interested in the principle, so I don't care too much about it...
    – Raven
    Dec 15 at 9:57










  • given a{xyz}b do you want to iterate three times, with a, xyz and b or 7 times with a, {, x, y,z,},b and it is presumably Ok to use something like bgroup for { as you can't hold an unmatched brace in a macro.
    – David Carlisle
    Dec 15 at 10:07












  • @DavidCarlisle 7 times - though I'd also be interested in the other alternative but I guess that is another story
    – Raven
    Dec 15 at 10:27






  • 1




    it's not really just edge cases, the mechanism you choose affects pretty much all uses, I've added an answer but I'll add some notes about the consequences of this design.
    – David Carlisle
    Dec 15 at 11:20
















Does the solution need to be expandable? It's not possible to get the charcode of {/} if it does ...
– Joseph Wright
Dec 15 at 9:54




Does the solution need to be expandable? It's not possible to get the charcode of {/} if it does ...
– Joseph Wright
Dec 15 at 9:54












@JosephWright It would be nice if it was but I am primarily interested in the principle, so I don't care too much about it...
– Raven
Dec 15 at 9:57




@JosephWright It would be nice if it was but I am primarily interested in the principle, so I don't care too much about it...
– Raven
Dec 15 at 9:57












given a{xyz}b do you want to iterate three times, with a, xyz and b or 7 times with a, {, x, y,z,},b and it is presumably Ok to use something like bgroup for { as you can't hold an unmatched brace in a macro.
– David Carlisle
Dec 15 at 10:07






given a{xyz}b do you want to iterate three times, with a, xyz and b or 7 times with a, {, x, y,z,},b and it is presumably Ok to use something like bgroup for { as you can't hold an unmatched brace in a macro.
– David Carlisle
Dec 15 at 10:07














@DavidCarlisle 7 times - though I'd also be interested in the other alternative but I guess that is another story
– Raven
Dec 15 at 10:27




@DavidCarlisle 7 times - though I'd also be interested in the other alternative but I guess that is another story
– Raven
Dec 15 at 10:27




1




1




it's not really just edge cases, the mechanism you choose affects pretty much all uses, I've added an answer but I'll add some notes about the consequences of this design.
– David Carlisle
Dec 15 at 11:20




it's not really just edge cases, the mechanism you choose affects pretty much all uses, I've added an answer but I'll add some notes about the consequences of this design.
– David Carlisle
Dec 15 at 11:20










3 Answers
3






active

oldest

votes


















5














enter image description here



documentclass{article}

makeatletter
defendtest{test!!!!}
deftest#1{%
par bigskiptextbf{TESTING:} texttt{detokenize{#1}}par
testzz#1endtest}

deftestzz{afterassignmenttestzzzlettmp= }

deftestzzz{%
ifxtmpendtest
else texttt{meaningtmp}par
expandaftertestzz
fi
}

begin{document}

test{123}

test{There are some arguments in here g}

test{ a+ {x sqrt{frac}}}

end{document}


Note that this mechanism consumes the supplied list using let (the form with = and exactly one space is important so it does not drop spaces or = in the input) that makes it easy to detect spaces and braces but for example it only captures the meaning of the token, it can not distinguish { from bgroup nor can it distinguish between any undefined commands, or show which name was used, zzzfoo undefined etc will all appear the same in the loop, as undefined.



For similar reasons, you can not re-construct anything equivalent to the original input from within the loop. given frac{a}{b} you get essentially fracbgroup aegrupbgroup begroup from which it isn't possible in general to reconstruct a working fraction.



So... whether these restrictions matter depend on the intended use of the loop.






share|improve this answer























  • If I was using string instead of meaning I should be able to reconstruct the input, shouldn't I?
    – Raven
    Dec 15 at 12:29










  • @Raven no. there is no way to reconstruct it from inside the loop.
    – David Carlisle
    Dec 15 at 12:30






  • 1




    @Raven this is why we were pushing you to clarify the question before answering. there are lots of ways of implementing a loop but they all have consequences.
    – David Carlisle
    Dec 15 at 12:32



















4














If you need it for debugging, it's a one-liner:



documentclass{article}
usepackage{xparse}

ExplSyntaxOn
NewDocumentCommand{test}{m}
{
tl_show_analysis:n { #1 }
}
ExplSyntaxOff

begin{document}

test{123}

test{There are some arguments in here g}

test{ a+ {x sqrt{frac}}}

end{document}


If you run it with pdflatex -interaction=nonstopmode, the console will show



The token list contains the tokens:
> 1 (the character 1)
> 2 (the character 2)
> 3 (the character 3).
<recently read> }

l.13 test{123}

The token list contains the tokens:
> T (the letter T)
> h (the letter h)
> e (the letter e)
> r (the letter r)
> e (the letter e)
> (blank space )
> a (the letter a)
> r (the letter r)
> e (the letter e)
> (blank space )
> some (control sequence=undefined)
> a (the letter a)
> r (the letter r)
> g (the letter g)
> u (the letter u)
> m (the letter m)
> e (the letter e)
> n (the letter n)
> t (the letter t)
> s (the letter s)
> (blank space )
> in (control sequence=mathchar"3232=12850)
> here (control sequence=undefined)
> g (the letter g).
<recently read> }

l.15 test{There are some arguments in here g}

The token list contains the tokens:
> (blank space )
> a (the letter a)
> + (the character +)
> (blank space )
> { (begin-group character {)
> x (the letter x)
> (blank space )
> sqrt (control sequence=macro:->protect sqrt )
> { (begin-group character {)
> frac (control sequence=macro:#1#2->{begingroup #1endgroup over #2})
> } (end-group character })
> } (end-group character }).
<recently read> }

l.17 test{ a+ {x sqrt{frac}}}





share|improve this answer





















  • Is there also a way to print those statements into the document rather than the console?
    – Raven
    Dec 15 at 12:30










  • @Raven Not at the moment. If you can show a real use case, it can possibly be added.
    – egreg
    Dec 15 at 12:31










  • @egreg see the comment I just made under my answer:-)
    – David Carlisle
    Dec 15 at 12:33



















2














Taking the expandable code from l3tl and recoding in classical style, we might do something like



catcode`@=11 %

chardeftl@exp@end=0 %

longdef@firstoftwo#1#2{#1}
longdef@secondoftwo#1#2{#2}
longdef@secondofthree#1#2#3{#2}
longdef@gobble#1{}

longdeftl@if@empty#1{%
expandafterifxexpandafterrelaxdetokenize{#1}relax
expandafter@secondofthree
fi
@secondoftwo
}

longdeftl@if@head@N#1{%
ifcat
iffalse{fitl@if@head@N@aux?#1 }%
expandafter@gobbleexpandafter{expandafter{string#1?}}%
**%
expandafter@firstoftwo
else
expandafter@secondoftwo
fi
}
longdeftl@if@head@N@aux#1 {%
expandaftertl@if@emptyexpandafter{@gobble#1}{^}{}%
expandafter@gobbleexpandafter{iffalse}fi
}

longdeftl@if@head@group#1{%
ifcatexpandafter@gobbleexpandafter{expandafter{string#1?}}**%
expandafter@secondoftwo
else
expandafter@firstoftwo
fi
}

defq@act@mark{q@act@mark}
defq@act@stop{q@act@stop}

longdeftl@act#1#2#3#4#5{%
ifnumiffalse{fi`}=z@fi
tl@act@loop#5q@act@markq@act@stop
{#4}#1#2#3%
tl@act@result{}%
}
longdeftl@act@loop#1q@act@stop{%
tl@if@head@N{#1}
{tl@act@normal}
{%
tl@if@head@group{#1}
{tl@act@group}
{tl@act@space}%
}%
#1q@act@stop
}
longdeftl@act@normal#1#2q@act@stop#3#4{%
ifxq@act@mark#1expandaftertl@act@endfi
#4{#3}#1%
tl@act@loop#2q@act@stop
{#3}#4%
}
longdeftl@act@group#1#2q@act@stop#3#4#5{%
#5{#3}{#1}%
tl@act@loop#2q@act@stop
{#3}#4#5%
}
expandafterlongexpandafterdefexpandafter
tl@act@spacespace#1q@act@stop#2#3#4#5{%
#5{#2}%
tl@act@loop#1q@act@stop
{#2}#3#4#5%
}
longdeftl@act@end#1tl@act@result#2{%
ifnum`{=z@}fi
tl@exp@end
#2%
}

longdefiterate#1{%
unexpandedexpandafter{%
romannumeraltl@act
tl@iterate@normal
tl@iterate@group
tl@iterate@space
{ }
{#1}%
}%
}
longdeftl@iterate@normal#1#2{tl@iterate@action{string#2}}
longdeftl@iterate@group#1#2{tl@iterate@action{{detokenize{#2}}}}
longdeftl@iterate@space#1{tl@iterate@action{ }}
longdeftl@iterate@action#1#2tl@act@result#3{%
#2%
tl@act@result{#3|#1|}%
}

catcode`@=12 %

iterate{There are some arguments in here g}

bye


(This uses e-TeX, but that can be avoided.)



The basic idea is to grab the token list and examine the first token before branching and handling as required. I've not done it, but recursion inside groups is doable. Notice that all brace groups become { ... } (unavoidable in expandable code).






share|improve this answer





















  • Thanks for your answer. It will probably take me a while to figure out how exactly it is working with all the expandafters but that's not your fault :)
    – Raven
    Dec 15 at 13:58











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%2f464950%2fiterate-over-tokens%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























3 Answers
3






active

oldest

votes








3 Answers
3






active

oldest

votes









active

oldest

votes






active

oldest

votes









5














enter image description here



documentclass{article}

makeatletter
defendtest{test!!!!}
deftest#1{%
par bigskiptextbf{TESTING:} texttt{detokenize{#1}}par
testzz#1endtest}

deftestzz{afterassignmenttestzzzlettmp= }

deftestzzz{%
ifxtmpendtest
else texttt{meaningtmp}par
expandaftertestzz
fi
}

begin{document}

test{123}

test{There are some arguments in here g}

test{ a+ {x sqrt{frac}}}

end{document}


Note that this mechanism consumes the supplied list using let (the form with = and exactly one space is important so it does not drop spaces or = in the input) that makes it easy to detect spaces and braces but for example it only captures the meaning of the token, it can not distinguish { from bgroup nor can it distinguish between any undefined commands, or show which name was used, zzzfoo undefined etc will all appear the same in the loop, as undefined.



For similar reasons, you can not re-construct anything equivalent to the original input from within the loop. given frac{a}{b} you get essentially fracbgroup aegrupbgroup begroup from which it isn't possible in general to reconstruct a working fraction.



So... whether these restrictions matter depend on the intended use of the loop.






share|improve this answer























  • If I was using string instead of meaning I should be able to reconstruct the input, shouldn't I?
    – Raven
    Dec 15 at 12:29










  • @Raven no. there is no way to reconstruct it from inside the loop.
    – David Carlisle
    Dec 15 at 12:30






  • 1




    @Raven this is why we were pushing you to clarify the question before answering. there are lots of ways of implementing a loop but they all have consequences.
    – David Carlisle
    Dec 15 at 12:32
















5














enter image description here



documentclass{article}

makeatletter
defendtest{test!!!!}
deftest#1{%
par bigskiptextbf{TESTING:} texttt{detokenize{#1}}par
testzz#1endtest}

deftestzz{afterassignmenttestzzzlettmp= }

deftestzzz{%
ifxtmpendtest
else texttt{meaningtmp}par
expandaftertestzz
fi
}

begin{document}

test{123}

test{There are some arguments in here g}

test{ a+ {x sqrt{frac}}}

end{document}


Note that this mechanism consumes the supplied list using let (the form with = and exactly one space is important so it does not drop spaces or = in the input) that makes it easy to detect spaces and braces but for example it only captures the meaning of the token, it can not distinguish { from bgroup nor can it distinguish between any undefined commands, or show which name was used, zzzfoo undefined etc will all appear the same in the loop, as undefined.



For similar reasons, you can not re-construct anything equivalent to the original input from within the loop. given frac{a}{b} you get essentially fracbgroup aegrupbgroup begroup from which it isn't possible in general to reconstruct a working fraction.



So... whether these restrictions matter depend on the intended use of the loop.






share|improve this answer























  • If I was using string instead of meaning I should be able to reconstruct the input, shouldn't I?
    – Raven
    Dec 15 at 12:29










  • @Raven no. there is no way to reconstruct it from inside the loop.
    – David Carlisle
    Dec 15 at 12:30






  • 1




    @Raven this is why we were pushing you to clarify the question before answering. there are lots of ways of implementing a loop but they all have consequences.
    – David Carlisle
    Dec 15 at 12:32














5












5








5






enter image description here



documentclass{article}

makeatletter
defendtest{test!!!!}
deftest#1{%
par bigskiptextbf{TESTING:} texttt{detokenize{#1}}par
testzz#1endtest}

deftestzz{afterassignmenttestzzzlettmp= }

deftestzzz{%
ifxtmpendtest
else texttt{meaningtmp}par
expandaftertestzz
fi
}

begin{document}

test{123}

test{There are some arguments in here g}

test{ a+ {x sqrt{frac}}}

end{document}


Note that this mechanism consumes the supplied list using let (the form with = and exactly one space is important so it does not drop spaces or = in the input) that makes it easy to detect spaces and braces but for example it only captures the meaning of the token, it can not distinguish { from bgroup nor can it distinguish between any undefined commands, or show which name was used, zzzfoo undefined etc will all appear the same in the loop, as undefined.



For similar reasons, you can not re-construct anything equivalent to the original input from within the loop. given frac{a}{b} you get essentially fracbgroup aegrupbgroup begroup from which it isn't possible in general to reconstruct a working fraction.



So... whether these restrictions matter depend on the intended use of the loop.






share|improve this answer














enter image description here



documentclass{article}

makeatletter
defendtest{test!!!!}
deftest#1{%
par bigskiptextbf{TESTING:} texttt{detokenize{#1}}par
testzz#1endtest}

deftestzz{afterassignmenttestzzzlettmp= }

deftestzzz{%
ifxtmpendtest
else texttt{meaningtmp}par
expandaftertestzz
fi
}

begin{document}

test{123}

test{There are some arguments in here g}

test{ a+ {x sqrt{frac}}}

end{document}


Note that this mechanism consumes the supplied list using let (the form with = and exactly one space is important so it does not drop spaces or = in the input) that makes it easy to detect spaces and braces but for example it only captures the meaning of the token, it can not distinguish { from bgroup nor can it distinguish between any undefined commands, or show which name was used, zzzfoo undefined etc will all appear the same in the loop, as undefined.



For similar reasons, you can not re-construct anything equivalent to the original input from within the loop. given frac{a}{b} you get essentially fracbgroup aegrupbgroup begroup from which it isn't possible in general to reconstruct a working fraction.



So... whether these restrictions matter depend on the intended use of the loop.







share|improve this answer














share|improve this answer



share|improve this answer








edited Dec 15 at 11:25

























answered Dec 15 at 11:15









David Carlisle

482k3811141851




482k3811141851












  • If I was using string instead of meaning I should be able to reconstruct the input, shouldn't I?
    – Raven
    Dec 15 at 12:29










  • @Raven no. there is no way to reconstruct it from inside the loop.
    – David Carlisle
    Dec 15 at 12:30






  • 1




    @Raven this is why we were pushing you to clarify the question before answering. there are lots of ways of implementing a loop but they all have consequences.
    – David Carlisle
    Dec 15 at 12:32


















  • If I was using string instead of meaning I should be able to reconstruct the input, shouldn't I?
    – Raven
    Dec 15 at 12:29










  • @Raven no. there is no way to reconstruct it from inside the loop.
    – David Carlisle
    Dec 15 at 12:30






  • 1




    @Raven this is why we were pushing you to clarify the question before answering. there are lots of ways of implementing a loop but they all have consequences.
    – David Carlisle
    Dec 15 at 12:32
















If I was using string instead of meaning I should be able to reconstruct the input, shouldn't I?
– Raven
Dec 15 at 12:29




If I was using string instead of meaning I should be able to reconstruct the input, shouldn't I?
– Raven
Dec 15 at 12:29












@Raven no. there is no way to reconstruct it from inside the loop.
– David Carlisle
Dec 15 at 12:30




@Raven no. there is no way to reconstruct it from inside the loop.
– David Carlisle
Dec 15 at 12:30




1




1




@Raven this is why we were pushing you to clarify the question before answering. there are lots of ways of implementing a loop but they all have consequences.
– David Carlisle
Dec 15 at 12:32




@Raven this is why we were pushing you to clarify the question before answering. there are lots of ways of implementing a loop but they all have consequences.
– David Carlisle
Dec 15 at 12:32











4














If you need it for debugging, it's a one-liner:



documentclass{article}
usepackage{xparse}

ExplSyntaxOn
NewDocumentCommand{test}{m}
{
tl_show_analysis:n { #1 }
}
ExplSyntaxOff

begin{document}

test{123}

test{There are some arguments in here g}

test{ a+ {x sqrt{frac}}}

end{document}


If you run it with pdflatex -interaction=nonstopmode, the console will show



The token list contains the tokens:
> 1 (the character 1)
> 2 (the character 2)
> 3 (the character 3).
<recently read> }

l.13 test{123}

The token list contains the tokens:
> T (the letter T)
> h (the letter h)
> e (the letter e)
> r (the letter r)
> e (the letter e)
> (blank space )
> a (the letter a)
> r (the letter r)
> e (the letter e)
> (blank space )
> some (control sequence=undefined)
> a (the letter a)
> r (the letter r)
> g (the letter g)
> u (the letter u)
> m (the letter m)
> e (the letter e)
> n (the letter n)
> t (the letter t)
> s (the letter s)
> (blank space )
> in (control sequence=mathchar"3232=12850)
> here (control sequence=undefined)
> g (the letter g).
<recently read> }

l.15 test{There are some arguments in here g}

The token list contains the tokens:
> (blank space )
> a (the letter a)
> + (the character +)
> (blank space )
> { (begin-group character {)
> x (the letter x)
> (blank space )
> sqrt (control sequence=macro:->protect sqrt )
> { (begin-group character {)
> frac (control sequence=macro:#1#2->{begingroup #1endgroup over #2})
> } (end-group character })
> } (end-group character }).
<recently read> }

l.17 test{ a+ {x sqrt{frac}}}





share|improve this answer





















  • Is there also a way to print those statements into the document rather than the console?
    – Raven
    Dec 15 at 12:30










  • @Raven Not at the moment. If you can show a real use case, it can possibly be added.
    – egreg
    Dec 15 at 12:31










  • @egreg see the comment I just made under my answer:-)
    – David Carlisle
    Dec 15 at 12:33
















4














If you need it for debugging, it's a one-liner:



documentclass{article}
usepackage{xparse}

ExplSyntaxOn
NewDocumentCommand{test}{m}
{
tl_show_analysis:n { #1 }
}
ExplSyntaxOff

begin{document}

test{123}

test{There are some arguments in here g}

test{ a+ {x sqrt{frac}}}

end{document}


If you run it with pdflatex -interaction=nonstopmode, the console will show



The token list contains the tokens:
> 1 (the character 1)
> 2 (the character 2)
> 3 (the character 3).
<recently read> }

l.13 test{123}

The token list contains the tokens:
> T (the letter T)
> h (the letter h)
> e (the letter e)
> r (the letter r)
> e (the letter e)
> (blank space )
> a (the letter a)
> r (the letter r)
> e (the letter e)
> (blank space )
> some (control sequence=undefined)
> a (the letter a)
> r (the letter r)
> g (the letter g)
> u (the letter u)
> m (the letter m)
> e (the letter e)
> n (the letter n)
> t (the letter t)
> s (the letter s)
> (blank space )
> in (control sequence=mathchar"3232=12850)
> here (control sequence=undefined)
> g (the letter g).
<recently read> }

l.15 test{There are some arguments in here g}

The token list contains the tokens:
> (blank space )
> a (the letter a)
> + (the character +)
> (blank space )
> { (begin-group character {)
> x (the letter x)
> (blank space )
> sqrt (control sequence=macro:->protect sqrt )
> { (begin-group character {)
> frac (control sequence=macro:#1#2->{begingroup #1endgroup over #2})
> } (end-group character })
> } (end-group character }).
<recently read> }

l.17 test{ a+ {x sqrt{frac}}}





share|improve this answer





















  • Is there also a way to print those statements into the document rather than the console?
    – Raven
    Dec 15 at 12:30










  • @Raven Not at the moment. If you can show a real use case, it can possibly be added.
    – egreg
    Dec 15 at 12:31










  • @egreg see the comment I just made under my answer:-)
    – David Carlisle
    Dec 15 at 12:33














4












4








4






If you need it for debugging, it's a one-liner:



documentclass{article}
usepackage{xparse}

ExplSyntaxOn
NewDocumentCommand{test}{m}
{
tl_show_analysis:n { #1 }
}
ExplSyntaxOff

begin{document}

test{123}

test{There are some arguments in here g}

test{ a+ {x sqrt{frac}}}

end{document}


If you run it with pdflatex -interaction=nonstopmode, the console will show



The token list contains the tokens:
> 1 (the character 1)
> 2 (the character 2)
> 3 (the character 3).
<recently read> }

l.13 test{123}

The token list contains the tokens:
> T (the letter T)
> h (the letter h)
> e (the letter e)
> r (the letter r)
> e (the letter e)
> (blank space )
> a (the letter a)
> r (the letter r)
> e (the letter e)
> (blank space )
> some (control sequence=undefined)
> a (the letter a)
> r (the letter r)
> g (the letter g)
> u (the letter u)
> m (the letter m)
> e (the letter e)
> n (the letter n)
> t (the letter t)
> s (the letter s)
> (blank space )
> in (control sequence=mathchar"3232=12850)
> here (control sequence=undefined)
> g (the letter g).
<recently read> }

l.15 test{There are some arguments in here g}

The token list contains the tokens:
> (blank space )
> a (the letter a)
> + (the character +)
> (blank space )
> { (begin-group character {)
> x (the letter x)
> (blank space )
> sqrt (control sequence=macro:->protect sqrt )
> { (begin-group character {)
> frac (control sequence=macro:#1#2->{begingroup #1endgroup over #2})
> } (end-group character })
> } (end-group character }).
<recently read> }

l.17 test{ a+ {x sqrt{frac}}}





share|improve this answer












If you need it for debugging, it's a one-liner:



documentclass{article}
usepackage{xparse}

ExplSyntaxOn
NewDocumentCommand{test}{m}
{
tl_show_analysis:n { #1 }
}
ExplSyntaxOff

begin{document}

test{123}

test{There are some arguments in here g}

test{ a+ {x sqrt{frac}}}

end{document}


If you run it with pdflatex -interaction=nonstopmode, the console will show



The token list contains the tokens:
> 1 (the character 1)
> 2 (the character 2)
> 3 (the character 3).
<recently read> }

l.13 test{123}

The token list contains the tokens:
> T (the letter T)
> h (the letter h)
> e (the letter e)
> r (the letter r)
> e (the letter e)
> (blank space )
> a (the letter a)
> r (the letter r)
> e (the letter e)
> (blank space )
> some (control sequence=undefined)
> a (the letter a)
> r (the letter r)
> g (the letter g)
> u (the letter u)
> m (the letter m)
> e (the letter e)
> n (the letter n)
> t (the letter t)
> s (the letter s)
> (blank space )
> in (control sequence=mathchar"3232=12850)
> here (control sequence=undefined)
> g (the letter g).
<recently read> }

l.15 test{There are some arguments in here g}

The token list contains the tokens:
> (blank space )
> a (the letter a)
> + (the character +)
> (blank space )
> { (begin-group character {)
> x (the letter x)
> (blank space )
> sqrt (control sequence=macro:->protect sqrt )
> { (begin-group character {)
> frac (control sequence=macro:#1#2->{begingroup #1endgroup over #2})
> } (end-group character })
> } (end-group character }).
<recently read> }

l.17 test{ a+ {x sqrt{frac}}}






share|improve this answer












share|improve this answer



share|improve this answer










answered Dec 15 at 11:25









egreg

708k8618813163




708k8618813163












  • Is there also a way to print those statements into the document rather than the console?
    – Raven
    Dec 15 at 12:30










  • @Raven Not at the moment. If you can show a real use case, it can possibly be added.
    – egreg
    Dec 15 at 12:31










  • @egreg see the comment I just made under my answer:-)
    – David Carlisle
    Dec 15 at 12:33


















  • Is there also a way to print those statements into the document rather than the console?
    – Raven
    Dec 15 at 12:30










  • @Raven Not at the moment. If you can show a real use case, it can possibly be added.
    – egreg
    Dec 15 at 12:31










  • @egreg see the comment I just made under my answer:-)
    – David Carlisle
    Dec 15 at 12:33
















Is there also a way to print those statements into the document rather than the console?
– Raven
Dec 15 at 12:30




Is there also a way to print those statements into the document rather than the console?
– Raven
Dec 15 at 12:30












@Raven Not at the moment. If you can show a real use case, it can possibly be added.
– egreg
Dec 15 at 12:31




@Raven Not at the moment. If you can show a real use case, it can possibly be added.
– egreg
Dec 15 at 12:31












@egreg see the comment I just made under my answer:-)
– David Carlisle
Dec 15 at 12:33




@egreg see the comment I just made under my answer:-)
– David Carlisle
Dec 15 at 12:33











2














Taking the expandable code from l3tl and recoding in classical style, we might do something like



catcode`@=11 %

chardeftl@exp@end=0 %

longdef@firstoftwo#1#2{#1}
longdef@secondoftwo#1#2{#2}
longdef@secondofthree#1#2#3{#2}
longdef@gobble#1{}

longdeftl@if@empty#1{%
expandafterifxexpandafterrelaxdetokenize{#1}relax
expandafter@secondofthree
fi
@secondoftwo
}

longdeftl@if@head@N#1{%
ifcat
iffalse{fitl@if@head@N@aux?#1 }%
expandafter@gobbleexpandafter{expandafter{string#1?}}%
**%
expandafter@firstoftwo
else
expandafter@secondoftwo
fi
}
longdeftl@if@head@N@aux#1 {%
expandaftertl@if@emptyexpandafter{@gobble#1}{^}{}%
expandafter@gobbleexpandafter{iffalse}fi
}

longdeftl@if@head@group#1{%
ifcatexpandafter@gobbleexpandafter{expandafter{string#1?}}**%
expandafter@secondoftwo
else
expandafter@firstoftwo
fi
}

defq@act@mark{q@act@mark}
defq@act@stop{q@act@stop}

longdeftl@act#1#2#3#4#5{%
ifnumiffalse{fi`}=z@fi
tl@act@loop#5q@act@markq@act@stop
{#4}#1#2#3%
tl@act@result{}%
}
longdeftl@act@loop#1q@act@stop{%
tl@if@head@N{#1}
{tl@act@normal}
{%
tl@if@head@group{#1}
{tl@act@group}
{tl@act@space}%
}%
#1q@act@stop
}
longdeftl@act@normal#1#2q@act@stop#3#4{%
ifxq@act@mark#1expandaftertl@act@endfi
#4{#3}#1%
tl@act@loop#2q@act@stop
{#3}#4%
}
longdeftl@act@group#1#2q@act@stop#3#4#5{%
#5{#3}{#1}%
tl@act@loop#2q@act@stop
{#3}#4#5%
}
expandafterlongexpandafterdefexpandafter
tl@act@spacespace#1q@act@stop#2#3#4#5{%
#5{#2}%
tl@act@loop#1q@act@stop
{#2}#3#4#5%
}
longdeftl@act@end#1tl@act@result#2{%
ifnum`{=z@}fi
tl@exp@end
#2%
}

longdefiterate#1{%
unexpandedexpandafter{%
romannumeraltl@act
tl@iterate@normal
tl@iterate@group
tl@iterate@space
{ }
{#1}%
}%
}
longdeftl@iterate@normal#1#2{tl@iterate@action{string#2}}
longdeftl@iterate@group#1#2{tl@iterate@action{{detokenize{#2}}}}
longdeftl@iterate@space#1{tl@iterate@action{ }}
longdeftl@iterate@action#1#2tl@act@result#3{%
#2%
tl@act@result{#3|#1|}%
}

catcode`@=12 %

iterate{There are some arguments in here g}

bye


(This uses e-TeX, but that can be avoided.)



The basic idea is to grab the token list and examine the first token before branching and handling as required. I've not done it, but recursion inside groups is doable. Notice that all brace groups become { ... } (unavoidable in expandable code).






share|improve this answer





















  • Thanks for your answer. It will probably take me a while to figure out how exactly it is working with all the expandafters but that's not your fault :)
    – Raven
    Dec 15 at 13:58
















2














Taking the expandable code from l3tl and recoding in classical style, we might do something like



catcode`@=11 %

chardeftl@exp@end=0 %

longdef@firstoftwo#1#2{#1}
longdef@secondoftwo#1#2{#2}
longdef@secondofthree#1#2#3{#2}
longdef@gobble#1{}

longdeftl@if@empty#1{%
expandafterifxexpandafterrelaxdetokenize{#1}relax
expandafter@secondofthree
fi
@secondoftwo
}

longdeftl@if@head@N#1{%
ifcat
iffalse{fitl@if@head@N@aux?#1 }%
expandafter@gobbleexpandafter{expandafter{string#1?}}%
**%
expandafter@firstoftwo
else
expandafter@secondoftwo
fi
}
longdeftl@if@head@N@aux#1 {%
expandaftertl@if@emptyexpandafter{@gobble#1}{^}{}%
expandafter@gobbleexpandafter{iffalse}fi
}

longdeftl@if@head@group#1{%
ifcatexpandafter@gobbleexpandafter{expandafter{string#1?}}**%
expandafter@secondoftwo
else
expandafter@firstoftwo
fi
}

defq@act@mark{q@act@mark}
defq@act@stop{q@act@stop}

longdeftl@act#1#2#3#4#5{%
ifnumiffalse{fi`}=z@fi
tl@act@loop#5q@act@markq@act@stop
{#4}#1#2#3%
tl@act@result{}%
}
longdeftl@act@loop#1q@act@stop{%
tl@if@head@N{#1}
{tl@act@normal}
{%
tl@if@head@group{#1}
{tl@act@group}
{tl@act@space}%
}%
#1q@act@stop
}
longdeftl@act@normal#1#2q@act@stop#3#4{%
ifxq@act@mark#1expandaftertl@act@endfi
#4{#3}#1%
tl@act@loop#2q@act@stop
{#3}#4%
}
longdeftl@act@group#1#2q@act@stop#3#4#5{%
#5{#3}{#1}%
tl@act@loop#2q@act@stop
{#3}#4#5%
}
expandafterlongexpandafterdefexpandafter
tl@act@spacespace#1q@act@stop#2#3#4#5{%
#5{#2}%
tl@act@loop#1q@act@stop
{#2}#3#4#5%
}
longdeftl@act@end#1tl@act@result#2{%
ifnum`{=z@}fi
tl@exp@end
#2%
}

longdefiterate#1{%
unexpandedexpandafter{%
romannumeraltl@act
tl@iterate@normal
tl@iterate@group
tl@iterate@space
{ }
{#1}%
}%
}
longdeftl@iterate@normal#1#2{tl@iterate@action{string#2}}
longdeftl@iterate@group#1#2{tl@iterate@action{{detokenize{#2}}}}
longdeftl@iterate@space#1{tl@iterate@action{ }}
longdeftl@iterate@action#1#2tl@act@result#3{%
#2%
tl@act@result{#3|#1|}%
}

catcode`@=12 %

iterate{There are some arguments in here g}

bye


(This uses e-TeX, but that can be avoided.)



The basic idea is to grab the token list and examine the first token before branching and handling as required. I've not done it, but recursion inside groups is doable. Notice that all brace groups become { ... } (unavoidable in expandable code).






share|improve this answer





















  • Thanks for your answer. It will probably take me a while to figure out how exactly it is working with all the expandafters but that's not your fault :)
    – Raven
    Dec 15 at 13:58














2












2








2






Taking the expandable code from l3tl and recoding in classical style, we might do something like



catcode`@=11 %

chardeftl@exp@end=0 %

longdef@firstoftwo#1#2{#1}
longdef@secondoftwo#1#2{#2}
longdef@secondofthree#1#2#3{#2}
longdef@gobble#1{}

longdeftl@if@empty#1{%
expandafterifxexpandafterrelaxdetokenize{#1}relax
expandafter@secondofthree
fi
@secondoftwo
}

longdeftl@if@head@N#1{%
ifcat
iffalse{fitl@if@head@N@aux?#1 }%
expandafter@gobbleexpandafter{expandafter{string#1?}}%
**%
expandafter@firstoftwo
else
expandafter@secondoftwo
fi
}
longdeftl@if@head@N@aux#1 {%
expandaftertl@if@emptyexpandafter{@gobble#1}{^}{}%
expandafter@gobbleexpandafter{iffalse}fi
}

longdeftl@if@head@group#1{%
ifcatexpandafter@gobbleexpandafter{expandafter{string#1?}}**%
expandafter@secondoftwo
else
expandafter@firstoftwo
fi
}

defq@act@mark{q@act@mark}
defq@act@stop{q@act@stop}

longdeftl@act#1#2#3#4#5{%
ifnumiffalse{fi`}=z@fi
tl@act@loop#5q@act@markq@act@stop
{#4}#1#2#3%
tl@act@result{}%
}
longdeftl@act@loop#1q@act@stop{%
tl@if@head@N{#1}
{tl@act@normal}
{%
tl@if@head@group{#1}
{tl@act@group}
{tl@act@space}%
}%
#1q@act@stop
}
longdeftl@act@normal#1#2q@act@stop#3#4{%
ifxq@act@mark#1expandaftertl@act@endfi
#4{#3}#1%
tl@act@loop#2q@act@stop
{#3}#4%
}
longdeftl@act@group#1#2q@act@stop#3#4#5{%
#5{#3}{#1}%
tl@act@loop#2q@act@stop
{#3}#4#5%
}
expandafterlongexpandafterdefexpandafter
tl@act@spacespace#1q@act@stop#2#3#4#5{%
#5{#2}%
tl@act@loop#1q@act@stop
{#2}#3#4#5%
}
longdeftl@act@end#1tl@act@result#2{%
ifnum`{=z@}fi
tl@exp@end
#2%
}

longdefiterate#1{%
unexpandedexpandafter{%
romannumeraltl@act
tl@iterate@normal
tl@iterate@group
tl@iterate@space
{ }
{#1}%
}%
}
longdeftl@iterate@normal#1#2{tl@iterate@action{string#2}}
longdeftl@iterate@group#1#2{tl@iterate@action{{detokenize{#2}}}}
longdeftl@iterate@space#1{tl@iterate@action{ }}
longdeftl@iterate@action#1#2tl@act@result#3{%
#2%
tl@act@result{#3|#1|}%
}

catcode`@=12 %

iterate{There are some arguments in here g}

bye


(This uses e-TeX, but that can be avoided.)



The basic idea is to grab the token list and examine the first token before branching and handling as required. I've not done it, but recursion inside groups is doable. Notice that all brace groups become { ... } (unavoidable in expandable code).






share|improve this answer












Taking the expandable code from l3tl and recoding in classical style, we might do something like



catcode`@=11 %

chardeftl@exp@end=0 %

longdef@firstoftwo#1#2{#1}
longdef@secondoftwo#1#2{#2}
longdef@secondofthree#1#2#3{#2}
longdef@gobble#1{}

longdeftl@if@empty#1{%
expandafterifxexpandafterrelaxdetokenize{#1}relax
expandafter@secondofthree
fi
@secondoftwo
}

longdeftl@if@head@N#1{%
ifcat
iffalse{fitl@if@head@N@aux?#1 }%
expandafter@gobbleexpandafter{expandafter{string#1?}}%
**%
expandafter@firstoftwo
else
expandafter@secondoftwo
fi
}
longdeftl@if@head@N@aux#1 {%
expandaftertl@if@emptyexpandafter{@gobble#1}{^}{}%
expandafter@gobbleexpandafter{iffalse}fi
}

longdeftl@if@head@group#1{%
ifcatexpandafter@gobbleexpandafter{expandafter{string#1?}}**%
expandafter@secondoftwo
else
expandafter@firstoftwo
fi
}

defq@act@mark{q@act@mark}
defq@act@stop{q@act@stop}

longdeftl@act#1#2#3#4#5{%
ifnumiffalse{fi`}=z@fi
tl@act@loop#5q@act@markq@act@stop
{#4}#1#2#3%
tl@act@result{}%
}
longdeftl@act@loop#1q@act@stop{%
tl@if@head@N{#1}
{tl@act@normal}
{%
tl@if@head@group{#1}
{tl@act@group}
{tl@act@space}%
}%
#1q@act@stop
}
longdeftl@act@normal#1#2q@act@stop#3#4{%
ifxq@act@mark#1expandaftertl@act@endfi
#4{#3}#1%
tl@act@loop#2q@act@stop
{#3}#4%
}
longdeftl@act@group#1#2q@act@stop#3#4#5{%
#5{#3}{#1}%
tl@act@loop#2q@act@stop
{#3}#4#5%
}
expandafterlongexpandafterdefexpandafter
tl@act@spacespace#1q@act@stop#2#3#4#5{%
#5{#2}%
tl@act@loop#1q@act@stop
{#2}#3#4#5%
}
longdeftl@act@end#1tl@act@result#2{%
ifnum`{=z@}fi
tl@exp@end
#2%
}

longdefiterate#1{%
unexpandedexpandafter{%
romannumeraltl@act
tl@iterate@normal
tl@iterate@group
tl@iterate@space
{ }
{#1}%
}%
}
longdeftl@iterate@normal#1#2{tl@iterate@action{string#2}}
longdeftl@iterate@group#1#2{tl@iterate@action{{detokenize{#2}}}}
longdeftl@iterate@space#1{tl@iterate@action{ }}
longdeftl@iterate@action#1#2tl@act@result#3{%
#2%
tl@act@result{#3|#1|}%
}

catcode`@=12 %

iterate{There are some arguments in here g}

bye


(This uses e-TeX, but that can be avoided.)



The basic idea is to grab the token list and examine the first token before branching and handling as required. I've not done it, but recursion inside groups is doable. Notice that all brace groups become { ... } (unavoidable in expandable code).







share|improve this answer












share|improve this answer



share|improve this answer










answered Dec 15 at 13:17









Joseph Wright

202k21554880




202k21554880












  • Thanks for your answer. It will probably take me a while to figure out how exactly it is working with all the expandafters but that's not your fault :)
    – Raven
    Dec 15 at 13:58


















  • Thanks for your answer. It will probably take me a while to figure out how exactly it is working with all the expandafters but that's not your fault :)
    – Raven
    Dec 15 at 13:58
















Thanks for your answer. It will probably take me a while to figure out how exactly it is working with all the expandafters but that's not your fault :)
– Raven
Dec 15 at 13:58




Thanks for your answer. It will probably take me a while to figure out how exactly it is working with all the expandafters but that's not your fault :)
– Raven
Dec 15 at 13:58


















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%2f464950%2fiterate-over-tokens%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

Index of /

Tribalistas

Listed building