In France, we usually write open or half-open intervals as
]a,b[
or [a,b[
, not (a,b)
or [a,b)
. I especially do not like (a,b)
as it can be confused with an ordered pair. I have therefore defined an \interv
command so that in \interv]a,b[
, for instance, ]
is considered as an opening delimiter and [
as a closing one. The comma between a
and b
may also be replaced by another symbol or be surrounded by more space to avoid confusion with a decimal separator, especially if the comma is declared as \mathord
.
I know I could simply define a different command for each of the four possible intervals, but it would not be fun. The main difficulty is to find the closing delimiter after the comma, as it can either be ]
or [
. I am aware of the answers to how-to-read-a-stream-of-tokens-up-to-one-of-two-different-delimiters but is does not seem to solve my problem. My solution (see below) is to test each token after the comma and see if it is ]
or [
. Delimiters and commas inside brace-delimited list of tokens are ignored.
I also allow to put \lr
between the \interv
and the opening delimiter: this inserts \left
and \right
before the left and right delimiters, respectively. Another possibility is to put one of the \big
(\Big
, etc.) commands instead of \lr
: this inserts \bigl
and \bigr
, etc. before left and right delimiters, respectively.
This works well, except in sectioning commands and the table of contents, and this only when \lr
or \big
is used. The simple \interv]a,b[
works in all cases because of the \protect
in the definition of \interv
, but what can I do to have \interv\lr]a,b[
and \inter\big]a,b[
also working in \section
and the ToC? My commands are cumbersome, so feel free to suggest entirely different solutions, but with the same syntax for the user!
Here is my code:
\documentclass{article}
\makeatletter
% Main routine.
% Examples of use:
% -- "\interv[a,b]", where "," is replaced by "\intervsep";
% -- "\interv]-a,b[", where "]" is replaced by "\mathopen]" and "[" by
% "\mathclose[";
% -- "\interv\lr]a,b]", where the left "]" is replaced by "\left]" and the
% right one by "\right]";
% -- "\interv\Bigg[a,b[", where the left "[" is replaced by "\Biggl[" and the
% right one by "\Biggr[".
% -- "\interv[a,{f[x]}]", to hide brackets inside the braces so that the closing
% delimiter is the uttermost right "]".
\def\interv{\tok@list={}%
\protect\interv@I}
% Define the symbol and the spacing between <a> and <b>.
% Note: "\mathopen{}" is put after "\intervsep" in "\interv@V", in case <b>
% begins with "+" or "-", so that the operator is considered as unary.
\def\intervsep{\mathord{;}\mkern3mu}
% Search for the opening delimiter.
\def\interv@I{%
\@ifnextchar[%
{\interv@II}% "[" found.
{\@ifnextchar]%
{\interv@II}% "]" found.
{\@ifnextchar\lr%
{\interv@III}% "\lr" found.
{\interv@IV}% "\big", "\Big", etc. found.
}}}
% Left delimiter found just after "\interv".
\def\interv@II{%
\def\first{\mathopen}%
\def\last{\mathclose}%
\interv@V}
% "\lr" found between "\interv" and the opening delimiter.
\def\interv@III#1{%
\def\first{\left}%
\def\last{\right}%
\interv@V}
% "\big", "\Big", etc. found between "\interv" and the opening delimiter.
\def\interv@IV#1{%
\def\first{\csname\expandafter\@gobble\string#1l\endcsname}%
\def\last{\csname\expandafter\@gobble\string#1r\endcsname}%
\interv@V}
% Process everything left of ",".
% Note: "\lr" and "\big", etc. have been absorbed by "\interv@III" and
% "\interv@IV", so #1 is always "[" or "]".
\def\interv@V#1#2,{\first#1#2\intervsep\mathopen{}\interv@VI}
% Search for the closing delimiter and read all tokens up to it.
\def\interv@VI{%
\@ifnextchar]%
{\interv@VII}% "]" found.
{\@ifnextchar[%
{\interv@VII}% "[" found.
{\@ifnextchar\bgroup%
{\interv@VIII}% list of tokens between braces found.
{\interv@IX}% single token found.
}}}
% Process closing delimiter. "\last" is "\mathclose" or "\right".
\def\interv@VII#1{\the\tok@list\last#1}
% Do not search for the closing delimiter within brace-delimited lists of
% tokens. Append them with enclosing braces to the main list and look for the
% next token.
\def\interv@VIII#1{\append@tok{{#1}}\tok@list\interv@VI}
% Append a single token to the main list and look for the main token.
\def\interv@IX#1{\append@tok#1\tok@list\interv@VI}
% Append a token to a list of tokens.
\newtoks\tok@list
\newtoks\next@tok
\def\append@tok#1#2{\next@tok={#1}%
\edef\do@append{\noexpand#2={\the#2\the\next@tok}}%
\do@append}
\makeatother
\begin{document}
% To check the effects of "\mathopen", "\mathclose", "\left", "\right" on
% binary and unary operators.
\thinmuskip=20mu
\medmuskip=40mu
% Works.
\verb|A \cap \interv]-a, +b[ \mathord\setminus B|:
\[A \cap \interv]-a, +b[ \mathord\setminus B\]
% Works.
\verb|A \cap \interv]-1{,}2, +3{,}4[ \mathord\setminus B|:
\[A \cap \interv]-1{,}2, +3{,}4[ \mathord\setminus B\]
% Works.
\verb|A \cap \interv\lr]-a, +\frac{b}{c}] \mathord\setminus B|:
\[A \cap \interv\lr]-a, +\frac{b}{c}] \mathord\setminus B\]
% Works.
\verb|A \cap \interv\Bigg[-a, +{b[c]}[ \mathord\setminus B|:
\[A \cap \interv\Bigg[-a, +{b[c]}[ \mathord\setminus B\]
\hrule\leavevmode
% Works.
\noindent\verb|A \cap \interv]-a, +b[ \mathord\setminus B|:
\section{$A \cap \interv]-a, +b[ \mathord\setminus B$}
% Complains that "\lr" is an undefined control sequence.
% "\left" and "\right" not used in the table of contents.
\verb|A \cap \interv\lr]-a, +\frac{b}{c}] \mathord\setminus B|:
\section{$\displaystyle A \cap \interv\lr]-a, +\frac{b}{c}] \mathord\setminus B$}
% Fails in the table of contents.
\verb|A \cap \interv\Bigg[-a, +{b[c]}[ \mathord\setminus B|:
\section{$A \cap \interv\Bigg[-a, +{b[c]}[ \mathord\setminus B$}
\tableofcontents
\end{document}