Is there an easy way to peek ahead for a digit? Something like
\peek_charcode:NTF [0-9]
The approach to nest 10 \peek_charcode:NTF
is quite cumbersome.
I want to match digits only. Digits, parenthesis and others share the same catcode.
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It only takes a minute to sign up.
Sign up to join this communityIs there an easy way to peek ahead for a digit? Something like
\peek_charcode:NTF [0-9]
The approach to nest 10 \peek_charcode:NTF
is quite cumbersome.
I want to match digits only. Digits, parenthesis and others share the same catcode.
Standing on the shoulders of giants and extending the idea of Manuel, I came up with this solution.
I think, a \regex_peek:nTF
would be so versatile that it should be added to l3regex
.
\documentclass{scrartcl}
\usepackage{expl3}
\usepackage{l3regex}
\begin{document}
\ExplSyntaxOn
\cs_generate_variant:Nn \regex_match:nnTF { no }
\cs_new_protected:Npn \mh_regex_peek:nTF #1 #2 #3
{
\peek_catcode:NTF ##
{#3}
{
\regex_match:noTF
{ \A the\ (character|letter)\ (#1) \Z }
{ \token_to_meaning:N \l_peek_token } {#2} {#3}
}
}
\mh_regex_peek:nTF { [0-9] } { digit: ~ } { no ~ digit: ~ } 1 \par
\mh_regex_peek:nTF { [0-9] } { digit: ~ } { no ~ digit: ~ } 2 \par
\mh_regex_peek:nTF { [0-9] } { digit: ~ } { no ~ digit: ~ } ( \par
\mh_regex_peek:nTF { [0-9] } { digit: ~ } { no ~ digit: ~ } {1} ~ (group) \par
\mh_regex_peek:nTF { [a] } { is ~ letter ~ a: ~ } { not ~ letter ~ a: ~ } 1 \par
\mh_regex_peek:nTF { [a] } { is ~ letter ~ a: ~ } { not ~ letter ~ a: ~ } a \par
\mh_regex_peek:nTF { [abc] } { is ~ a, ~ b ~ or ~ c: ~ } { not ~ a, ~ b ~ or ~ c: ~ } b \par
\mh_regex_peek:nTF { a|b|c } { is ~ a, ~ b ~ or ~ c: ~ } { not ~ a, ~ b ~ or ~ c: ~ } b \par
\mh_regex_peek:nTF { a|b|c } { is ~ a, ~ b ~ or ~ c: ~ } { not ~ a, ~ b ~ or ~ c: ~ } e \par
\end{document}
Edit: Made more robust, by filtering out #
Edit: Switched to the regex { \A the\ (character|letter)\ (#1) \Z }
. If anybody knows a nice way to convert \l_peek_token
into a token list, then I could get rid of this workaround. PS. It seems that egreg had a very similar idea at the same time.
PPS This solution is being used in mhchem v4.00, now.
\cs_set_nopar:Npn
should be also protected
, because it's not expandable. In any case, what's the intention of expanding \token_to_meaning:N \l_peek_token
? Is it correct?
\l_peek_token
has been set to 0
, then \token_to_meaning:N \l_peek_token
will expand to the character 0
, so the search string a
will match.
a
instead of 0
? Yes, I was wrong in my comment above, but only because of the category codes assigned by \token_to_meaning:N
A starting point (coming from someone who knows nothing about the deep internals of expl3
, this, to me, just seems to work). I would use \token_case:NnTF
but that function doesn't exist.
\documentclass{scrartcl}
\usepackage{xparse}
\ExplSyntaxOn
\cs_new_protected:Npn \mh_peek_case:nTF #1 #2 #3
{
\cs_set_nopar:Npn \__mh_peek_case:w
{
\tl_case:NnTF \l_peek_token { #1 } { #2 } { #3 }
}
\peek_after:Nw \__mh_peek_case:w
}
\NewDocumentCommand \checkfordigit { }
{
\mh_peek_case:nTF
{
{0}{} {1}{} {2}{} {3}{} {4}{}
{5}{} {6}{} {7}{} {8}{} {9}{}
}
{ Next ~ token ~ is ~ a ~ digit: ~ }
{ Next ~ token ~ is ~ not ~ a ~ digit: ~ }
}
\ExplSyntaxOff
\begin{document}
\checkfordigit 1 \par
\checkfordigit 2 \par
\checkfordigit A \par
\checkfordigit -- \par
\end{document}
In case you don't care if it's \checkfordigit{1}
you could define it just with \tl_set:Nn \l_tmpa_tl {#1} \tl_case:NnTF \l_tmpa_tl { .. } { .. } { .. }
.
The idea of \peek_regex:NTF
is very nice, but it has a problem: the expansion of \token_to_meaning:N \l_peek_token
, when the following token is 0
is
the character 0
so in your case
\mh_peek_regex:nTF { a } { true } { false } 0
will return true
, because a
matches the character 0
.
If you limit yourself to looking for characters and not other tokens, then the idea can be made to work, still allowing ranges in the first argument:
\documentclass{scrartcl}
\usepackage{expl3}
\usepackage{l3regex}
\begin{document}
\ExplSyntaxOn
\cs_generate_variant:Nn \regex_match:nnTF { nV }
\tl_new:N \l__mh_char_peek_tl
\cs_new_protected:Npn \mh_char_peek:nTF #1 #2 #3
{
\peek_catcode:NTF ##
{ #3 }
{
\tl_set:Nx \l__mh_char_peek_tl { \token_to_meaning:N \l_peek_token }
\regex_match:nVTF { \A the } \l__mh_char_peek_tl
{
\regex_replace_once:nnN { \A the \s .* \s } { } \l__mh_char_peek_tl
\regex_match:nVTF {#1} \l__mh_char_peek_tl {#2} {#3}
}
{ #3 }
}
}
\mh_char_peek:nTF { [0-9] } { digit: ~ } { no ~ digit: ~ } 1 \par
\mh_char_peek:nTF { [0-9] } { digit: ~ } { no ~ digit: ~ } 2 \par
\mh_char_peek:nTF { [0-9] } { digit: ~ } { no ~ digit: ~ } ( \par
\mh_char_peek:nTF { [0-9] } { digit: ~ } { no ~ digit: ~ } {1} ~ (group) \par
\mh_char_peek:nTF { [0-9] } { digit: ~ } { no ~ digit: ~ } - \par
\mh_char_peek:nTF { a } { is ~ letter ~ a: ~ } { not ~ letter ~ a: ~ } 0 \par
\mh_char_peek:nTF { [a-z] } { is ~ letter ~ a: ~ } { not ~ letter ~ a: ~ } a \par
\end{document}
I check that the expansion of \token_to_meaning:N \l_peek_token
starts with the
and, in this case I know it will either be the character <?>
or the letter <?>
so I can remove the unwanted tokens from that expansion and do the correct check.
Tests for other tokens can go on with the appropriate \peek_...:NTF
function.
\peek_case:nTF { {1}{..} {2}{..} } { .. } { .. }
would be nice (although the name is not correct since allcase
functions are expandable, something of that kind would be nice).