Let me start with an unexpandable version:
\documentclass{article}
\usepackage{xparse,l3regex}
\ExplSyntaxOn
\NewDocumentCommand{\IfLengthTF}{mmm}
{
\lentest_if_length:NTF #1 { #2 } { #3 }
}
\NewDocumentCommand{\IfLengthF}{mm}
{
\lentest_if_length:NF #1 { #2 }
}
\NewDocumentCommand{\IfLengthT}{mm}
{
\lentest_if_length:NT #1 { #2 }
}
\prg_new_protected_conditional:Npnn \lentest_if_length:N #1 {p,T,F,TF}
{
\regex_match:nxTF {\A\\??(skip|dimen).+} { \token_to_meaning:N #1 }
{ \prg_return_true: }
{ \prg_return_false: }
}
\cs_generate_variant:Nn \regex_match:nnTF {nx}
\ExplSyntaxOff
\newlength\pippo
\newdimen\pluto
\IfLengthTF{\pippo}{\typeout{It's a length}}{\typeout{It's NOT a length}}
\IfLengthTF{\pluto}{\typeout{It's a length}}{\typeout{It's NOT a length}}
\IfLengthTF{\skip}{\typeout{It's a length}}{\typeout{It's NOT a length}}
\IfLengthTF{\xxeey}{\typeout{It's a length}}{\typeout{It's NOT a length}}
The output is
It's a length
It's a length
It's NOT a length
It's NOT a length
One can also use \IfLengthT or \IfLengthF, when the true or false branches are not needed.
The regex matches \skip or \dimen, followed by at least one character, at the start of the argument's meaning. The \\?? means that the backslash may not be present (it happens if \escapechar is -1; other possibilities for the value of \escapechar are not taken care of, but they could if needed).
Now an expandable test (thanks to Joseph Wright for suggesting it):
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\IfLengthTF}{mmm}
{
\lentest_if_length:NTF #1 { #2 } { #3 }
}
\NewDocumentCommand{\IfLengthF}{mm}
{
\lentest_if_length:NF #1 { #2 }
}
\NewDocumentCommand{\IfLengthT}{mm}
{
\lentest_if_length:NT #1 { #2 }
}
\prg_new_conditional:Npnn \lentest_if_length:N #1 {p,T,F,TF}
{
\bool_if:nTF
{
\token_if_dim_register_p:N #1 || \token_if_skip_register_p:N #1
}
{ \prg_return_true: }
{ \prg_return_false: }
}
\ExplSyntaxOff
Of course the \IFLength... commands are not expandable; but the \lentest_if_length:NTF test and its siblings are.
Why choose one or the other? It depends on what's the purpose of the macros. The second version can be made expandable, which might be desirable in certain contexts. The first version can be generalized in various ways, testing for whatever is necessary with a suitable regular expression.
Caveat: these tests don't distinguish among control sequences which are not symbolic names for skip or dimen registers and other control sequences. So \IfLengthTF{\hsize}{...}{...} will choose the "false" branch. It's impossible to recognize an internal dimen or skip register only via \meaning: one way might be to check the meaning against a list of the primitive names of the parameters (which might be added to the first method).
\csname! Again something I wouldn't have thought off. – Martin Scharrer May 22 '12 at 14:08#6#7and the\ifx#6!!\fi? – egreg May 22 '12 at 14:17!after\meaning#1there should be no problem. – egreg May 22 '12 at 14:25\testforskip\foogives\ndef=\relax. So every call of\testforskipmight have a date with the hash table. – Ahmed Musa May 22 '12 at 17:15\meaningskipseems to be unused. – Henri Menke Nov 27 '19 at 03:42