Detecting subscript in command argument
I have defined a command low
that adds a subscript to an argument:
newcommand{low}[1]{{#1}_{l_{mathcal{A}}}}
However, if the argument of low
contains subscripts itsself (for example in the case of low{low{Sigma}}
) it is not easy to see that the subscripts introduced by the outer low
belong to the whole argument and not just to the first subscript. Therefore I would like to automatically introduce parentheses if the argument of low
contains a subscript (so low{low{Sigma}}
should look like low{(low{Sigma})}
.
In order to achieve this I tried the following using the xifthen package:
newcommand{low}[1]{ifthenelse{isin{_}{#1}}{{(#1)}_{l_{mathcal{A}}}}{{#1}_{l_{mathcal{A}}}}}
However to my surprise this command only sometimes inserts the parantheses.
In particular it does not do so in the example given above. Why does this happen and what can I do to fix this?
EDIT: It seems that the problem is that isin
does not unroll the definitions of commands. @egreg has already provided an answer that allows me to check for nested calls of low
but does not work for arguments that contain other commands with subscripts. Does anyone have a solution that works for arbitrary arguments?
macros conditionals subscripts ifthenelse xifthen
New contributor
add a comment |
I have defined a command low
that adds a subscript to an argument:
newcommand{low}[1]{{#1}_{l_{mathcal{A}}}}
However, if the argument of low
contains subscripts itsself (for example in the case of low{low{Sigma}}
) it is not easy to see that the subscripts introduced by the outer low
belong to the whole argument and not just to the first subscript. Therefore I would like to automatically introduce parentheses if the argument of low
contains a subscript (so low{low{Sigma}}
should look like low{(low{Sigma})}
.
In order to achieve this I tried the following using the xifthen package:
newcommand{low}[1]{ifthenelse{isin{_}{#1}}{{(#1)}_{l_{mathcal{A}}}}{{#1}_{l_{mathcal{A}}}}}
However to my surprise this command only sometimes inserts the parantheses.
In particular it does not do so in the example given above. Why does this happen and what can I do to fix this?
EDIT: It seems that the problem is that isin
does not unroll the definitions of commands. @egreg has already provided an answer that allows me to check for nested calls of low
but does not work for arguments that contain other commands with subscripts. Does anyone have a solution that works for arbitrary arguments?
macros conditionals subscripts ifthenelse xifthen
New contributor
add a comment |
I have defined a command low
that adds a subscript to an argument:
newcommand{low}[1]{{#1}_{l_{mathcal{A}}}}
However, if the argument of low
contains subscripts itsself (for example in the case of low{low{Sigma}}
) it is not easy to see that the subscripts introduced by the outer low
belong to the whole argument and not just to the first subscript. Therefore I would like to automatically introduce parentheses if the argument of low
contains a subscript (so low{low{Sigma}}
should look like low{(low{Sigma})}
.
In order to achieve this I tried the following using the xifthen package:
newcommand{low}[1]{ifthenelse{isin{_}{#1}}{{(#1)}_{l_{mathcal{A}}}}{{#1}_{l_{mathcal{A}}}}}
However to my surprise this command only sometimes inserts the parantheses.
In particular it does not do so in the example given above. Why does this happen and what can I do to fix this?
EDIT: It seems that the problem is that isin
does not unroll the definitions of commands. @egreg has already provided an answer that allows me to check for nested calls of low
but does not work for arguments that contain other commands with subscripts. Does anyone have a solution that works for arbitrary arguments?
macros conditionals subscripts ifthenelse xifthen
New contributor
I have defined a command low
that adds a subscript to an argument:
newcommand{low}[1]{{#1}_{l_{mathcal{A}}}}
However, if the argument of low
contains subscripts itsself (for example in the case of low{low{Sigma}}
) it is not easy to see that the subscripts introduced by the outer low
belong to the whole argument and not just to the first subscript. Therefore I would like to automatically introduce parentheses if the argument of low
contains a subscript (so low{low{Sigma}}
should look like low{(low{Sigma})}
.
In order to achieve this I tried the following using the xifthen package:
newcommand{low}[1]{ifthenelse{isin{_}{#1}}{{(#1)}_{l_{mathcal{A}}}}{{#1}_{l_{mathcal{A}}}}}
However to my surprise this command only sometimes inserts the parantheses.
In particular it does not do so in the example given above. Why does this happen and what can I do to fix this?
EDIT: It seems that the problem is that isin
does not unroll the definitions of commands. @egreg has already provided an answer that allows me to check for nested calls of low
but does not work for arguments that contain other commands with subscripts. Does anyone have a solution that works for arbitrary arguments?
macros conditionals subscripts ifthenelse xifthen
macros conditionals subscripts ifthenelse xifthen
New contributor
New contributor
edited 12 hours ago
Rincewind
New contributor
asked 15 hours ago
RincewindRincewind
113
113
New contributor
New contributor
add a comment |
add a comment |
3 Answers
3
active
oldest
votes
You can use a conditional. If it is true, add parentheses, if it is false, set it to true and don't add parentheses.
documentclass{article}
usepackage{amsmath}
newififnestedlow
newcommand{low}[1]{%
begingroup
ifnestedlow
(normallow{#1})%
else
nestedlowtrue
normallow{#1}%
fi
endgroup
}
newcommand{normallow}[1]{{#1}_{l_{mathcal{A}}}}
begin{document}
[
low{Sigma} qquad low{low{Sigma}} qquad low{Sigma}
]
end{document}
Doing this in a group ensures the conditional will be false at the next call.
Thanks for the suggestion. This does, however, only check whether I have nested calls of low. It does not seem to do anything in cases where I have for examplelow{Sigma_1}
or evenlow{subs}
wheresubs
produces some output with a subscript.
– Rincewind
13 hours ago
@Rincewind The problem is underspecified, then. And very hard to solve in the general case:subs
may expand to something containing_
. If you allow whatever command that may expand to something with_
, then no, you can't do it.
– egreg
13 hours ago
add a comment |
In some cases applying protected@edef
and @onelevel@sanitize
before checking for a "stringified" _
might work out:
documentclass{article}
usepackage{amsmath}
usepackage{xifthen}
newififnownestlownownestlowfalse
makeatletter
DeclareRobustCommandlow[1]{%
begingroup
begingroup
protected@edef@tempa{#1}%
@onelevel@sanitize@tempa
expandafterexpandafterexpandafterendgroup
expandafterexpandafterexpandafterifthenelse
expandafterexpandafterexpandafter{%
expandafterexpandafterexpandafterisin
expandafterexpandafterexpandafter{%
expandafterexpandafterstring_%
expandafter}%
expandafter{%
@tempa}}%
{ifnownestlow(nownestlowfalsenormallow{(#1)})elsenownestlowfalsenormallow{(#1)}fi}%
{ifnownestlow(nownestlowtruenormallow{#1})elsenownestlowtruenormallow{#1}fi}%
endgroup
}
makeatother
newcommand{normallow}[1]{{#1}_{l_{mathcal{A}}}}
begin{document}
[
low{Sigma} qquad
low{low{Sigma}} qquad
low{low{low{Sigma}}} qquad
]
[
low{Sigma_b} qquad
low{low{Sigma_b}} qquad
low{low{low{Sigma_b}}} qquad
]
[
low{{Sigma_b}} qquad
low{b_{low{c_{low{Sigma_d}}}}} qquad
(Sigma_b)_{l_mathcal{A}}
]
end{document}
expandafter
causes that the next but one token —if expandable—gets expanded exactly once before the next token gets expanded if expandable. (La)TeX considers the work of expandafter
done when expansion of the next but one token is done. Therefore you can use chains/dequences of expandafter
to have (La)TeX "jump" over k tokens for first expanding the (k+1)-th token.
@onelevel@sanitizemacro
changes the definition of macro
so that macro
spits out a sequence of character tokens of category code 12(other) that looks like the token-sequence that would have been "spit out" by macro
before applying @onelevel@sanitize
. It is almost like redefining macro
to what you get by applying string
to each token of macro
's definition.
protected@edef
defines a macro but before doing so, it expands all expandable tokens of the definition-text except those that either are defined via DeclareRobustCommand
or are preceded by the token protect
. You might say: protected@edef
does "unroll" the definitions of the tokens contained in its definition-text before actually performing the assignment.
@tempa
is a scratch-macro which gets defined by means of protected@edef
to expand to the argument #1
with all definitions in #1
"unrolled".
The ifthenelse{isin...}
-test does not find _
that are nested in curly-braces as curly braces usually have a special function. Therefore @onelevel@sanitize
is applied for turning all tokens, and thus also the curly braces, into ordinary harmless character-tokens of category code 12(other) which do not disturb the ifthenelse{isin...}
test.
To be honest, I don't really understand what is going on here. What doprotected@edef
,tempa
,@onelevel@sanitize
,string
andexpandafter
do? As it is it does not seem to be doing what I want. I'd likelow{Sigma_b}
to have the same output as(Sigma_b)_{l_mathcal{A}}
. Because I don't really understand what's going on, I can't tell whether this can be done by slightly modifying your solution or not.
– Rincewind
11 hours ago
@Rincewind I have revised and modified my answer. I hope the code now does what you need. I also tried to add some explanation. ;-)
– Ulrich Diez
7 hours ago
add a comment |
An idea (not straight forward solution) is to place the argument inside a box and check its height with the height of a character you suppose is not too tall to need parenthesis but not too short to add parenthesis to your Sigma.
And guess what will be our default argument: Sigma
... P
The code (containing some tests) is this:
documentclass{article}
defDefLowArg{$Sigma$}
letoldDefLowArgDefLowArg
newsavebox{myAbox}
newsavebox{myBbox}
newcommand{low}[2][DefLowArg]{saveboxmyAbox{vbox{#1}}saveboxmyBbox{vbox{ensuremath{#2}}}
ifdimdimexprhtmyAbox+dpmyAbox<dimexprhtmyBbox+dpmyBboxrelax
left({#2}right)_{l_{mathcal{A}}}
else {#2}_{l_{mathcal{A}}}fi
}
begin{document}
[low{low{Sigma}}]
[low{Sigma}]
[
low{sum_{i=3}^5 F(x)}
]
[
low{frac{F(x)}{x+5}}
]
[low{F_x}]
[low[1/4]{F(x)}]
[low{x^2}]
[
low{G_x}
]
These commands may be should add without parentheses
[
low{g(z)}
]
[
low{F(x)}
]
{bfseries Solution 1 Add an tall optional argument in the command like: verb|low[/]{F(x)}|}
[
low[/]{g(z)}
]
[
low[/]{F(x)}
]
{bfseries Solution 2 Change the Default argument verb|DefLowArg| to something tall enough (return with verb|letDefLowArgoldDefLowArg|):}
xdefDefLowArg{/}
[
low{g(z)}
]
[
low{F(x)}
]
letDefLowArgoldDefLowArg
{bfseries And back to default}
[
low{F(X)}
]
end{document}
That produces:
PS:Of course manual solutions should be added in special cases but anyway in your command I am sure you would have exceptions for many cases.
add a comment |
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
});
}
});
Rincewind is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f479070%2fdetecting-subscript-in-command-argument%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
You can use a conditional. If it is true, add parentheses, if it is false, set it to true and don't add parentheses.
documentclass{article}
usepackage{amsmath}
newififnestedlow
newcommand{low}[1]{%
begingroup
ifnestedlow
(normallow{#1})%
else
nestedlowtrue
normallow{#1}%
fi
endgroup
}
newcommand{normallow}[1]{{#1}_{l_{mathcal{A}}}}
begin{document}
[
low{Sigma} qquad low{low{Sigma}} qquad low{Sigma}
]
end{document}
Doing this in a group ensures the conditional will be false at the next call.
Thanks for the suggestion. This does, however, only check whether I have nested calls of low. It does not seem to do anything in cases where I have for examplelow{Sigma_1}
or evenlow{subs}
wheresubs
produces some output with a subscript.
– Rincewind
13 hours ago
@Rincewind The problem is underspecified, then. And very hard to solve in the general case:subs
may expand to something containing_
. If you allow whatever command that may expand to something with_
, then no, you can't do it.
– egreg
13 hours ago
add a comment |
You can use a conditional. If it is true, add parentheses, if it is false, set it to true and don't add parentheses.
documentclass{article}
usepackage{amsmath}
newififnestedlow
newcommand{low}[1]{%
begingroup
ifnestedlow
(normallow{#1})%
else
nestedlowtrue
normallow{#1}%
fi
endgroup
}
newcommand{normallow}[1]{{#1}_{l_{mathcal{A}}}}
begin{document}
[
low{Sigma} qquad low{low{Sigma}} qquad low{Sigma}
]
end{document}
Doing this in a group ensures the conditional will be false at the next call.
Thanks for the suggestion. This does, however, only check whether I have nested calls of low. It does not seem to do anything in cases where I have for examplelow{Sigma_1}
or evenlow{subs}
wheresubs
produces some output with a subscript.
– Rincewind
13 hours ago
@Rincewind The problem is underspecified, then. And very hard to solve in the general case:subs
may expand to something containing_
. If you allow whatever command that may expand to something with_
, then no, you can't do it.
– egreg
13 hours ago
add a comment |
You can use a conditional. If it is true, add parentheses, if it is false, set it to true and don't add parentheses.
documentclass{article}
usepackage{amsmath}
newififnestedlow
newcommand{low}[1]{%
begingroup
ifnestedlow
(normallow{#1})%
else
nestedlowtrue
normallow{#1}%
fi
endgroup
}
newcommand{normallow}[1]{{#1}_{l_{mathcal{A}}}}
begin{document}
[
low{Sigma} qquad low{low{Sigma}} qquad low{Sigma}
]
end{document}
Doing this in a group ensures the conditional will be false at the next call.
You can use a conditional. If it is true, add parentheses, if it is false, set it to true and don't add parentheses.
documentclass{article}
usepackage{amsmath}
newififnestedlow
newcommand{low}[1]{%
begingroup
ifnestedlow
(normallow{#1})%
else
nestedlowtrue
normallow{#1}%
fi
endgroup
}
newcommand{normallow}[1]{{#1}_{l_{mathcal{A}}}}
begin{document}
[
low{Sigma} qquad low{low{Sigma}} qquad low{Sigma}
]
end{document}
Doing this in a group ensures the conditional will be false at the next call.
answered 14 hours ago
egregegreg
726k8819193228
726k8819193228
Thanks for the suggestion. This does, however, only check whether I have nested calls of low. It does not seem to do anything in cases where I have for examplelow{Sigma_1}
or evenlow{subs}
wheresubs
produces some output with a subscript.
– Rincewind
13 hours ago
@Rincewind The problem is underspecified, then. And very hard to solve in the general case:subs
may expand to something containing_
. If you allow whatever command that may expand to something with_
, then no, you can't do it.
– egreg
13 hours ago
add a comment |
Thanks for the suggestion. This does, however, only check whether I have nested calls of low. It does not seem to do anything in cases where I have for examplelow{Sigma_1}
or evenlow{subs}
wheresubs
produces some output with a subscript.
– Rincewind
13 hours ago
@Rincewind The problem is underspecified, then. And very hard to solve in the general case:subs
may expand to something containing_
. If you allow whatever command that may expand to something with_
, then no, you can't do it.
– egreg
13 hours ago
Thanks for the suggestion. This does, however, only check whether I have nested calls of low. It does not seem to do anything in cases where I have for example
low{Sigma_1}
or even low{subs}
where subs
produces some output with a subscript.– Rincewind
13 hours ago
Thanks for the suggestion. This does, however, only check whether I have nested calls of low. It does not seem to do anything in cases where I have for example
low{Sigma_1}
or even low{subs}
where subs
produces some output with a subscript.– Rincewind
13 hours ago
@Rincewind The problem is underspecified, then. And very hard to solve in the general case:
subs
may expand to something containing _
. If you allow whatever command that may expand to something with _
, then no, you can't do it.– egreg
13 hours ago
@Rincewind The problem is underspecified, then. And very hard to solve in the general case:
subs
may expand to something containing _
. If you allow whatever command that may expand to something with _
, then no, you can't do it.– egreg
13 hours ago
add a comment |
In some cases applying protected@edef
and @onelevel@sanitize
before checking for a "stringified" _
might work out:
documentclass{article}
usepackage{amsmath}
usepackage{xifthen}
newififnownestlownownestlowfalse
makeatletter
DeclareRobustCommandlow[1]{%
begingroup
begingroup
protected@edef@tempa{#1}%
@onelevel@sanitize@tempa
expandafterexpandafterexpandafterendgroup
expandafterexpandafterexpandafterifthenelse
expandafterexpandafterexpandafter{%
expandafterexpandafterexpandafterisin
expandafterexpandafterexpandafter{%
expandafterexpandafterstring_%
expandafter}%
expandafter{%
@tempa}}%
{ifnownestlow(nownestlowfalsenormallow{(#1)})elsenownestlowfalsenormallow{(#1)}fi}%
{ifnownestlow(nownestlowtruenormallow{#1})elsenownestlowtruenormallow{#1}fi}%
endgroup
}
makeatother
newcommand{normallow}[1]{{#1}_{l_{mathcal{A}}}}
begin{document}
[
low{Sigma} qquad
low{low{Sigma}} qquad
low{low{low{Sigma}}} qquad
]
[
low{Sigma_b} qquad
low{low{Sigma_b}} qquad
low{low{low{Sigma_b}}} qquad
]
[
low{{Sigma_b}} qquad
low{b_{low{c_{low{Sigma_d}}}}} qquad
(Sigma_b)_{l_mathcal{A}}
]
end{document}
expandafter
causes that the next but one token —if expandable—gets expanded exactly once before the next token gets expanded if expandable. (La)TeX considers the work of expandafter
done when expansion of the next but one token is done. Therefore you can use chains/dequences of expandafter
to have (La)TeX "jump" over k tokens for first expanding the (k+1)-th token.
@onelevel@sanitizemacro
changes the definition of macro
so that macro
spits out a sequence of character tokens of category code 12(other) that looks like the token-sequence that would have been "spit out" by macro
before applying @onelevel@sanitize
. It is almost like redefining macro
to what you get by applying string
to each token of macro
's definition.
protected@edef
defines a macro but before doing so, it expands all expandable tokens of the definition-text except those that either are defined via DeclareRobustCommand
or are preceded by the token protect
. You might say: protected@edef
does "unroll" the definitions of the tokens contained in its definition-text before actually performing the assignment.
@tempa
is a scratch-macro which gets defined by means of protected@edef
to expand to the argument #1
with all definitions in #1
"unrolled".
The ifthenelse{isin...}
-test does not find _
that are nested in curly-braces as curly braces usually have a special function. Therefore @onelevel@sanitize
is applied for turning all tokens, and thus also the curly braces, into ordinary harmless character-tokens of category code 12(other) which do not disturb the ifthenelse{isin...}
test.
To be honest, I don't really understand what is going on here. What doprotected@edef
,tempa
,@onelevel@sanitize
,string
andexpandafter
do? As it is it does not seem to be doing what I want. I'd likelow{Sigma_b}
to have the same output as(Sigma_b)_{l_mathcal{A}}
. Because I don't really understand what's going on, I can't tell whether this can be done by slightly modifying your solution or not.
– Rincewind
11 hours ago
@Rincewind I have revised and modified my answer. I hope the code now does what you need. I also tried to add some explanation. ;-)
– Ulrich Diez
7 hours ago
add a comment |
In some cases applying protected@edef
and @onelevel@sanitize
before checking for a "stringified" _
might work out:
documentclass{article}
usepackage{amsmath}
usepackage{xifthen}
newififnownestlownownestlowfalse
makeatletter
DeclareRobustCommandlow[1]{%
begingroup
begingroup
protected@edef@tempa{#1}%
@onelevel@sanitize@tempa
expandafterexpandafterexpandafterendgroup
expandafterexpandafterexpandafterifthenelse
expandafterexpandafterexpandafter{%
expandafterexpandafterexpandafterisin
expandafterexpandafterexpandafter{%
expandafterexpandafterstring_%
expandafter}%
expandafter{%
@tempa}}%
{ifnownestlow(nownestlowfalsenormallow{(#1)})elsenownestlowfalsenormallow{(#1)}fi}%
{ifnownestlow(nownestlowtruenormallow{#1})elsenownestlowtruenormallow{#1}fi}%
endgroup
}
makeatother
newcommand{normallow}[1]{{#1}_{l_{mathcal{A}}}}
begin{document}
[
low{Sigma} qquad
low{low{Sigma}} qquad
low{low{low{Sigma}}} qquad
]
[
low{Sigma_b} qquad
low{low{Sigma_b}} qquad
low{low{low{Sigma_b}}} qquad
]
[
low{{Sigma_b}} qquad
low{b_{low{c_{low{Sigma_d}}}}} qquad
(Sigma_b)_{l_mathcal{A}}
]
end{document}
expandafter
causes that the next but one token —if expandable—gets expanded exactly once before the next token gets expanded if expandable. (La)TeX considers the work of expandafter
done when expansion of the next but one token is done. Therefore you can use chains/dequences of expandafter
to have (La)TeX "jump" over k tokens for first expanding the (k+1)-th token.
@onelevel@sanitizemacro
changes the definition of macro
so that macro
spits out a sequence of character tokens of category code 12(other) that looks like the token-sequence that would have been "spit out" by macro
before applying @onelevel@sanitize
. It is almost like redefining macro
to what you get by applying string
to each token of macro
's definition.
protected@edef
defines a macro but before doing so, it expands all expandable tokens of the definition-text except those that either are defined via DeclareRobustCommand
or are preceded by the token protect
. You might say: protected@edef
does "unroll" the definitions of the tokens contained in its definition-text before actually performing the assignment.
@tempa
is a scratch-macro which gets defined by means of protected@edef
to expand to the argument #1
with all definitions in #1
"unrolled".
The ifthenelse{isin...}
-test does not find _
that are nested in curly-braces as curly braces usually have a special function. Therefore @onelevel@sanitize
is applied for turning all tokens, and thus also the curly braces, into ordinary harmless character-tokens of category code 12(other) which do not disturb the ifthenelse{isin...}
test.
To be honest, I don't really understand what is going on here. What doprotected@edef
,tempa
,@onelevel@sanitize
,string
andexpandafter
do? As it is it does not seem to be doing what I want. I'd likelow{Sigma_b}
to have the same output as(Sigma_b)_{l_mathcal{A}}
. Because I don't really understand what's going on, I can't tell whether this can be done by slightly modifying your solution or not.
– Rincewind
11 hours ago
@Rincewind I have revised and modified my answer. I hope the code now does what you need. I also tried to add some explanation. ;-)
– Ulrich Diez
7 hours ago
add a comment |
In some cases applying protected@edef
and @onelevel@sanitize
before checking for a "stringified" _
might work out:
documentclass{article}
usepackage{amsmath}
usepackage{xifthen}
newififnownestlownownestlowfalse
makeatletter
DeclareRobustCommandlow[1]{%
begingroup
begingroup
protected@edef@tempa{#1}%
@onelevel@sanitize@tempa
expandafterexpandafterexpandafterendgroup
expandafterexpandafterexpandafterifthenelse
expandafterexpandafterexpandafter{%
expandafterexpandafterexpandafterisin
expandafterexpandafterexpandafter{%
expandafterexpandafterstring_%
expandafter}%
expandafter{%
@tempa}}%
{ifnownestlow(nownestlowfalsenormallow{(#1)})elsenownestlowfalsenormallow{(#1)}fi}%
{ifnownestlow(nownestlowtruenormallow{#1})elsenownestlowtruenormallow{#1}fi}%
endgroup
}
makeatother
newcommand{normallow}[1]{{#1}_{l_{mathcal{A}}}}
begin{document}
[
low{Sigma} qquad
low{low{Sigma}} qquad
low{low{low{Sigma}}} qquad
]
[
low{Sigma_b} qquad
low{low{Sigma_b}} qquad
low{low{low{Sigma_b}}} qquad
]
[
low{{Sigma_b}} qquad
low{b_{low{c_{low{Sigma_d}}}}} qquad
(Sigma_b)_{l_mathcal{A}}
]
end{document}
expandafter
causes that the next but one token —if expandable—gets expanded exactly once before the next token gets expanded if expandable. (La)TeX considers the work of expandafter
done when expansion of the next but one token is done. Therefore you can use chains/dequences of expandafter
to have (La)TeX "jump" over k tokens for first expanding the (k+1)-th token.
@onelevel@sanitizemacro
changes the definition of macro
so that macro
spits out a sequence of character tokens of category code 12(other) that looks like the token-sequence that would have been "spit out" by macro
before applying @onelevel@sanitize
. It is almost like redefining macro
to what you get by applying string
to each token of macro
's definition.
protected@edef
defines a macro but before doing so, it expands all expandable tokens of the definition-text except those that either are defined via DeclareRobustCommand
or are preceded by the token protect
. You might say: protected@edef
does "unroll" the definitions of the tokens contained in its definition-text before actually performing the assignment.
@tempa
is a scratch-macro which gets defined by means of protected@edef
to expand to the argument #1
with all definitions in #1
"unrolled".
The ifthenelse{isin...}
-test does not find _
that are nested in curly-braces as curly braces usually have a special function. Therefore @onelevel@sanitize
is applied for turning all tokens, and thus also the curly braces, into ordinary harmless character-tokens of category code 12(other) which do not disturb the ifthenelse{isin...}
test.
In some cases applying protected@edef
and @onelevel@sanitize
before checking for a "stringified" _
might work out:
documentclass{article}
usepackage{amsmath}
usepackage{xifthen}
newififnownestlownownestlowfalse
makeatletter
DeclareRobustCommandlow[1]{%
begingroup
begingroup
protected@edef@tempa{#1}%
@onelevel@sanitize@tempa
expandafterexpandafterexpandafterendgroup
expandafterexpandafterexpandafterifthenelse
expandafterexpandafterexpandafter{%
expandafterexpandafterexpandafterisin
expandafterexpandafterexpandafter{%
expandafterexpandafterstring_%
expandafter}%
expandafter{%
@tempa}}%
{ifnownestlow(nownestlowfalsenormallow{(#1)})elsenownestlowfalsenormallow{(#1)}fi}%
{ifnownestlow(nownestlowtruenormallow{#1})elsenownestlowtruenormallow{#1}fi}%
endgroup
}
makeatother
newcommand{normallow}[1]{{#1}_{l_{mathcal{A}}}}
begin{document}
[
low{Sigma} qquad
low{low{Sigma}} qquad
low{low{low{Sigma}}} qquad
]
[
low{Sigma_b} qquad
low{low{Sigma_b}} qquad
low{low{low{Sigma_b}}} qquad
]
[
low{{Sigma_b}} qquad
low{b_{low{c_{low{Sigma_d}}}}} qquad
(Sigma_b)_{l_mathcal{A}}
]
end{document}
expandafter
causes that the next but one token —if expandable—gets expanded exactly once before the next token gets expanded if expandable. (La)TeX considers the work of expandafter
done when expansion of the next but one token is done. Therefore you can use chains/dequences of expandafter
to have (La)TeX "jump" over k tokens for first expanding the (k+1)-th token.
@onelevel@sanitizemacro
changes the definition of macro
so that macro
spits out a sequence of character tokens of category code 12(other) that looks like the token-sequence that would have been "spit out" by macro
before applying @onelevel@sanitize
. It is almost like redefining macro
to what you get by applying string
to each token of macro
's definition.
protected@edef
defines a macro but before doing so, it expands all expandable tokens of the definition-text except those that either are defined via DeclareRobustCommand
or are preceded by the token protect
. You might say: protected@edef
does "unroll" the definitions of the tokens contained in its definition-text before actually performing the assignment.
@tempa
is a scratch-macro which gets defined by means of protected@edef
to expand to the argument #1
with all definitions in #1
"unrolled".
The ifthenelse{isin...}
-test does not find _
that are nested in curly-braces as curly braces usually have a special function. Therefore @onelevel@sanitize
is applied for turning all tokens, and thus also the curly braces, into ordinary harmless character-tokens of category code 12(other) which do not disturb the ifthenelse{isin...}
test.
edited 6 hours ago
answered 12 hours ago
Ulrich DiezUlrich Diez
5,390619
5,390619
To be honest, I don't really understand what is going on here. What doprotected@edef
,tempa
,@onelevel@sanitize
,string
andexpandafter
do? As it is it does not seem to be doing what I want. I'd likelow{Sigma_b}
to have the same output as(Sigma_b)_{l_mathcal{A}}
. Because I don't really understand what's going on, I can't tell whether this can be done by slightly modifying your solution or not.
– Rincewind
11 hours ago
@Rincewind I have revised and modified my answer. I hope the code now does what you need. I also tried to add some explanation. ;-)
– Ulrich Diez
7 hours ago
add a comment |
To be honest, I don't really understand what is going on here. What doprotected@edef
,tempa
,@onelevel@sanitize
,string
andexpandafter
do? As it is it does not seem to be doing what I want. I'd likelow{Sigma_b}
to have the same output as(Sigma_b)_{l_mathcal{A}}
. Because I don't really understand what's going on, I can't tell whether this can be done by slightly modifying your solution or not.
– Rincewind
11 hours ago
@Rincewind I have revised and modified my answer. I hope the code now does what you need. I also tried to add some explanation. ;-)
– Ulrich Diez
7 hours ago
To be honest, I don't really understand what is going on here. What do
protected@edef
, tempa
,@onelevel@sanitize
, string
and expandafter
do? As it is it does not seem to be doing what I want. I'd like low{Sigma_b}
to have the same output as (Sigma_b)_{l_mathcal{A}}
. Because I don't really understand what's going on, I can't tell whether this can be done by slightly modifying your solution or not.– Rincewind
11 hours ago
To be honest, I don't really understand what is going on here. What do
protected@edef
, tempa
,@onelevel@sanitize
, string
and expandafter
do? As it is it does not seem to be doing what I want. I'd like low{Sigma_b}
to have the same output as (Sigma_b)_{l_mathcal{A}}
. Because I don't really understand what's going on, I can't tell whether this can be done by slightly modifying your solution or not.– Rincewind
11 hours ago
@Rincewind I have revised and modified my answer. I hope the code now does what you need. I also tried to add some explanation. ;-)
– Ulrich Diez
7 hours ago
@Rincewind I have revised and modified my answer. I hope the code now does what you need. I also tried to add some explanation. ;-)
– Ulrich Diez
7 hours ago
add a comment |
An idea (not straight forward solution) is to place the argument inside a box and check its height with the height of a character you suppose is not too tall to need parenthesis but not too short to add parenthesis to your Sigma.
And guess what will be our default argument: Sigma
... P
The code (containing some tests) is this:
documentclass{article}
defDefLowArg{$Sigma$}
letoldDefLowArgDefLowArg
newsavebox{myAbox}
newsavebox{myBbox}
newcommand{low}[2][DefLowArg]{saveboxmyAbox{vbox{#1}}saveboxmyBbox{vbox{ensuremath{#2}}}
ifdimdimexprhtmyAbox+dpmyAbox<dimexprhtmyBbox+dpmyBboxrelax
left({#2}right)_{l_{mathcal{A}}}
else {#2}_{l_{mathcal{A}}}fi
}
begin{document}
[low{low{Sigma}}]
[low{Sigma}]
[
low{sum_{i=3}^5 F(x)}
]
[
low{frac{F(x)}{x+5}}
]
[low{F_x}]
[low[1/4]{F(x)}]
[low{x^2}]
[
low{G_x}
]
These commands may be should add without parentheses
[
low{g(z)}
]
[
low{F(x)}
]
{bfseries Solution 1 Add an tall optional argument in the command like: verb|low[/]{F(x)}|}
[
low[/]{g(z)}
]
[
low[/]{F(x)}
]
{bfseries Solution 2 Change the Default argument verb|DefLowArg| to something tall enough (return with verb|letDefLowArgoldDefLowArg|):}
xdefDefLowArg{/}
[
low{g(z)}
]
[
low{F(x)}
]
letDefLowArgoldDefLowArg
{bfseries And back to default}
[
low{F(X)}
]
end{document}
That produces:
PS:Of course manual solutions should be added in special cases but anyway in your command I am sure you would have exceptions for many cases.
add a comment |
An idea (not straight forward solution) is to place the argument inside a box and check its height with the height of a character you suppose is not too tall to need parenthesis but not too short to add parenthesis to your Sigma.
And guess what will be our default argument: Sigma
... P
The code (containing some tests) is this:
documentclass{article}
defDefLowArg{$Sigma$}
letoldDefLowArgDefLowArg
newsavebox{myAbox}
newsavebox{myBbox}
newcommand{low}[2][DefLowArg]{saveboxmyAbox{vbox{#1}}saveboxmyBbox{vbox{ensuremath{#2}}}
ifdimdimexprhtmyAbox+dpmyAbox<dimexprhtmyBbox+dpmyBboxrelax
left({#2}right)_{l_{mathcal{A}}}
else {#2}_{l_{mathcal{A}}}fi
}
begin{document}
[low{low{Sigma}}]
[low{Sigma}]
[
low{sum_{i=3}^5 F(x)}
]
[
low{frac{F(x)}{x+5}}
]
[low{F_x}]
[low[1/4]{F(x)}]
[low{x^2}]
[
low{G_x}
]
These commands may be should add without parentheses
[
low{g(z)}
]
[
low{F(x)}
]
{bfseries Solution 1 Add an tall optional argument in the command like: verb|low[/]{F(x)}|}
[
low[/]{g(z)}
]
[
low[/]{F(x)}
]
{bfseries Solution 2 Change the Default argument verb|DefLowArg| to something tall enough (return with verb|letDefLowArgoldDefLowArg|):}
xdefDefLowArg{/}
[
low{g(z)}
]
[
low{F(x)}
]
letDefLowArgoldDefLowArg
{bfseries And back to default}
[
low{F(X)}
]
end{document}
That produces:
PS:Of course manual solutions should be added in special cases but anyway in your command I am sure you would have exceptions for many cases.
add a comment |
An idea (not straight forward solution) is to place the argument inside a box and check its height with the height of a character you suppose is not too tall to need parenthesis but not too short to add parenthesis to your Sigma.
And guess what will be our default argument: Sigma
... P
The code (containing some tests) is this:
documentclass{article}
defDefLowArg{$Sigma$}
letoldDefLowArgDefLowArg
newsavebox{myAbox}
newsavebox{myBbox}
newcommand{low}[2][DefLowArg]{saveboxmyAbox{vbox{#1}}saveboxmyBbox{vbox{ensuremath{#2}}}
ifdimdimexprhtmyAbox+dpmyAbox<dimexprhtmyBbox+dpmyBboxrelax
left({#2}right)_{l_{mathcal{A}}}
else {#2}_{l_{mathcal{A}}}fi
}
begin{document}
[low{low{Sigma}}]
[low{Sigma}]
[
low{sum_{i=3}^5 F(x)}
]
[
low{frac{F(x)}{x+5}}
]
[low{F_x}]
[low[1/4]{F(x)}]
[low{x^2}]
[
low{G_x}
]
These commands may be should add without parentheses
[
low{g(z)}
]
[
low{F(x)}
]
{bfseries Solution 1 Add an tall optional argument in the command like: verb|low[/]{F(x)}|}
[
low[/]{g(z)}
]
[
low[/]{F(x)}
]
{bfseries Solution 2 Change the Default argument verb|DefLowArg| to something tall enough (return with verb|letDefLowArgoldDefLowArg|):}
xdefDefLowArg{/}
[
low{g(z)}
]
[
low{F(x)}
]
letDefLowArgoldDefLowArg
{bfseries And back to default}
[
low{F(X)}
]
end{document}
That produces:
PS:Of course manual solutions should be added in special cases but anyway in your command I am sure you would have exceptions for many cases.
An idea (not straight forward solution) is to place the argument inside a box and check its height with the height of a character you suppose is not too tall to need parenthesis but not too short to add parenthesis to your Sigma.
And guess what will be our default argument: Sigma
... P
The code (containing some tests) is this:
documentclass{article}
defDefLowArg{$Sigma$}
letoldDefLowArgDefLowArg
newsavebox{myAbox}
newsavebox{myBbox}
newcommand{low}[2][DefLowArg]{saveboxmyAbox{vbox{#1}}saveboxmyBbox{vbox{ensuremath{#2}}}
ifdimdimexprhtmyAbox+dpmyAbox<dimexprhtmyBbox+dpmyBboxrelax
left({#2}right)_{l_{mathcal{A}}}
else {#2}_{l_{mathcal{A}}}fi
}
begin{document}
[low{low{Sigma}}]
[low{Sigma}]
[
low{sum_{i=3}^5 F(x)}
]
[
low{frac{F(x)}{x+5}}
]
[low{F_x}]
[low[1/4]{F(x)}]
[low{x^2}]
[
low{G_x}
]
These commands may be should add without parentheses
[
low{g(z)}
]
[
low{F(x)}
]
{bfseries Solution 1 Add an tall optional argument in the command like: verb|low[/]{F(x)}|}
[
low[/]{g(z)}
]
[
low[/]{F(x)}
]
{bfseries Solution 2 Change the Default argument verb|DefLowArg| to something tall enough (return with verb|letDefLowArgoldDefLowArg|):}
xdefDefLowArg{/}
[
low{g(z)}
]
[
low{F(x)}
]
letDefLowArgoldDefLowArg
{bfseries And back to default}
[
low{F(X)}
]
end{document}
That produces:
PS:Of course manual solutions should be added in special cases but anyway in your command I am sure you would have exceptions for many cases.
answered 12 hours ago
koleygrkoleygr
12.5k11038
12.5k11038
add a comment |
add a comment |
Rincewind is a new contributor. Be nice, and check out our Code of Conduct.
Rincewind is a new contributor. Be nice, and check out our Code of Conduct.
Rincewind is a new contributor. Be nice, and check out our Code of Conduct.
Rincewind is a new contributor. Be nice, and check out our Code of Conduct.
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f479070%2fdetecting-subscript-in-command-argument%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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