diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/generic/xstring |
Initial commit
Diffstat (limited to 'macros/generic/xstring')
-rw-r--r-- | macros/generic/xstring/README | 85 | ||||
-rw-r--r-- | macros/generic/xstring/test_etex.pdf | bin | 0 -> 99780 bytes | |||
-rw-r--r-- | macros/generic/xstring/test_etex.tex | 992 | ||||
-rw-r--r-- | macros/generic/xstring/test_latex.pdf | bin | 0 -> 150611 bytes | |||
-rw-r--r-- | macros/generic/xstring/test_latex.tex | 1078 | ||||
-rw-r--r-- | macros/generic/xstring/xstring-en.pdf | bin | 0 -> 187648 bytes | |||
-rw-r--r-- | macros/generic/xstring/xstring-en.tex | 2052 | ||||
-rw-r--r-- | macros/generic/xstring/xstring-fr.pdf | bin | 0 -> 201920 bytes | |||
-rw-r--r-- | macros/generic/xstring/xstring-fr.tex | 2037 | ||||
-rw-r--r-- | macros/generic/xstring/xstring.sty | 3 | ||||
-rw-r--r-- | macros/generic/xstring/xstring.tex | 1227 |
11 files changed, 7474 insertions, 0 deletions
diff --git a/macros/generic/xstring/README b/macros/generic/xstring/README new file mode 100644 index 0000000000..8234833cb9 --- /dev/null +++ b/macros/generic/xstring/README @@ -0,0 +1,85 @@ + _________________ + + xstring package + v 1.83 + 2019/02/06 + _________________ + +This package provides macros manipulating strings for programming use. +A "string" is made of TeX code, i.e. chars (catcodes 10, 11 and 12), controls +sequences, groups between braces, tokens with other catcodes, excepted catcodes +6 and 14 (usually chars # and %). + +Main features are: + * tests: + - does a string contains at least n times an another? + - does a string starts (or ends) with another? etc. + - is a string an integer? A decimal? + - are 2 strings equal? + - is a string equal to several cases? + * extractions of substrings: + - what is on the left (or the right) of the nth occurrence of a + substring; + - what is between the occurrences of 2 substrings; + - substring between 2 positions; + - split a string; + - find a group with its identifier, etc. + * substitution of all (or the n first) occurrences of a substring + for an other substring; + * n times expansion of the tokens of a string; + * calculation of numbers: + - length of a string; + - position of the nth occurrence of a substring; + - how many times a string contains a substring? + - comparison of strings: position of the first difference; + - identifier of the group in which a macro worked. + +For advanced programming needs, other macros allow to use other special +characters forbiden in strings (# %). + +This bundle contains 7 files: + * xstring.sty (the sty file for LaTeX) + * xstring.tex (the package itself) + * xstring_doc_en.tex and xstring_doc_en.pdf (manual in english) + * xstring_doc_fr.tex and xstring_doc_fr.pdf (manual in french)) + * README (this file) + +############################################################################## +############################################################################## + +Cette extension regroupe un ensemble de macros manipulant des chaînes à des +fins de programmation. +Une "chaîne" est du code TeX, c'est-à -dire des caractères (catcodes 10, 11 +et 12), des séquences de contrôle, des groupes entre accolades et des lexèmes +ayant d'autres catcodes excepté les catcodes 6 et 14 (habituellement les +caractères # et %). + +Les principales fonctionnalités sont : + * des tests : + - une chaîne en contient elle une autre au moins n fois ? + - une chaîne commence t-elle ou finit-elle par une autre ? etc. + - une chaîne est-elle un entier relatif ? Un décimal ? + - deux chaînes sont-elles égales ? + - une chaîne est elle égale à plusieurs cas ? + * des extractions de chaines : + - renvoi de ce qui se trouve avant (ou après) la nieme occurrence + d'une sous-chaîne; + - renvoi de ce qui se trouve entre les occurrences de 2 sous-chaînes; + - sous-chaîne comprise entre 2 positions; + - coupure d'une chaîne; + - recherche d'un groupe avec son identifiant. + * le remplacement de toutes ou des n premières occurrences d'une + sous-chaîne par une autre sous-chaîne; + * n-développement des tokens d'une chaîne; + * des calculs de nombres : + - longueur d'une chaîne; + - position de la la nieme occurrence d'une sous-chaîne; + - comptage du nombre d'occurrences d'une sous-chaîne dans une autre; + - comparaison de 2 chaînes : position de la 1ere différence; + - identifiant du groupe dans lequel les macros ont opéré. + +Pour des méthodes de programmation avancées, d'autres commandes permettent +d'utiliser les caractères spéciaux interdits dans les chaines (# %). + + Christian Tellechea + <unbonpetit@netc.fr> diff --git a/macros/generic/xstring/test_etex.pdf b/macros/generic/xstring/test_etex.pdf Binary files differnew file mode 100644 index 0000000000..4d2b8134b2 --- /dev/null +++ b/macros/generic/xstring/test_etex.pdf diff --git a/macros/generic/xstring/test_etex.tex b/macros/generic/xstring/test_etex.tex new file mode 100644 index 0000000000..e7c7cdfaad --- /dev/null +++ b/macros/generic/xstring/test_etex.tex @@ -0,0 +1,992 @@ +%##################### WARNING ##################### +% This is NOT a LaTeX file, it is a TeX file. +% It must be compiled with eTeX typing <etex test_etex> +%#################### ATTENTION #################### +% Ceci n'est PAS un fichier LaTeX, c'est un fichier TeX. +% Il doit être compilé avec eteX en tapant <etex test_etex> +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\input xstring +\def\delimiteur{-{}} +\font\hugerm=ecbx2000 +\font\hugett=ectt1750 +\font\largeboldrm=ecbx1300 +\font\largett=ectt1300 +\font\textfont=ecrm1000 +\textfont +\catcode`\@=11\relax +\gdef\exemple{\csname xs_ifstar\endcsname{\def\frontiere{\delimiteur}\csname xs_toks_toverb\endcsname}{\def\frontiere{}\csname xs_toks_toverb\endcsname}} +\expandafter\def\csname xs_assign_verb\endcsname#1{% + \noexpandarg + \tokenize\cs@resultat{#1}% + \fullexpandarg + \leavevmode\hbox to0.7\hsize{\hfil\tt#1}\quad\frontiere\cs@resultat\frontiere\hfil\par}% +\catcode`\@=12\relax +\def\chapitre#1#2{\vskip 6pt plus 2pt minus 2pt{{\largeboldrm#1} {\largett#2}}\vskip 3pt plus 1pt minus 1pt} +\def\AvecArgOptionnel{\vskip 6pt plus 2pt minus 2pt Mêmes exemples avec l'argument optionnel :\par} +\hoffset-1.54cm\hsize19cm\parindent0pt +% debut du texte +\hfil{\hugerm Ceci est le fichier de test de xstring}\hfil{} + +\hrule\vskip0.5ex + +\hrule\vskip2ex + +Attention : ce fichier {\tt test\_etex.tex} produit une sortie quasiment identique au fichier {\tt test\_latex.tex}, mais il doit se lancer avec Plain $\varepsilon$-\TeX. Pour des raison d'encodage, contrairement au fichier {\tt test\_latex.tex}, les arguments des macros présentées ici ne contiennent pas de lettres accentuées.\vskip2em + +Toutes les situations ne sont pas envisagées, mais au moins un grand nombre ! Les macros sont examinées dans l'ordre logique du code. + +Lorsque le résultat contient des espaces ou peut conduire à des doutes, il sera entouré de ''\delimiteur``, étant entendu que ''\delimiteur\delimiteur`` est une chaine vide.\vskip2em + +\hfill{\hugerm Le mode \hugett\string\fullexpandarg}\hfill{} + +\vskip-1ex\hfil\hbox to8cm{\hrulefill}\hfil{}\vskip3.5ex + +\chapitre{Le test}{IfSubStr} + +\exemple|\IfSubStr{abcdef}{cd}{vrai}{faux}| +\exemple|\IfSubStr{a b c d }{b c}{vrai}{faux}| +\exemple|\IfSubStr{a b c d }{bc}{vrai}{faux}| +\exemple|\IfSubStr{abcdef}{}{vrai}{faux}| +\exemple|\IfSubStr{a}{a}{vrai}{faux}| +\exemple|\IfSubStr{aaaa}{aa}{vrai}{faux}| +\exemple|\IfSubStr{a}{aa}{vrai}{faux}| +\exemple|\IfSubStr{a}{}{vrai}{faux}| +\exemple|\IfSubStr{}{a}{vrai}{faux}| +\exemple|\IfSubStr{}{}{vrai}{faux}| +\exemple|\IfSubStr[2]{abaca}{a}{vrai}{faux}| +\exemple|\IfSubStr[3]{abaca}{a}{vrai}{faux}| +\exemple|\IfSubStr[4]{abaca}{a}{vrai}{faux}| +\exemple|\IfSubStr[-2]{abaca}{a}{vrai}{faux}| + +\chapitre{Le test}{IfBeginWith} + +\exemple|\IfBeginWith{abcdef}{adc}{vrai}{faux}| +\exemple|\IfBeginWith{abcdef}{abcd}{vrai}{faux}| +\exemple|\IfBeginWith{ a b c }{ a}{vrai}{faux}| +\exemple|\IfBeginWith{a b c d}{ab}{vrai}{faux}| +\exemple|\IfBeginWith{a}{a}{vrai}{faux}| +\exemple|\IfBeginWith{a}{aa}{vrai}{faux}| +\exemple|\IfBeginWith{a}{}{vrai}{faux}| +\exemple|\IfBeginWith{}{a}{vrai}{faux}| +\exemple|\IfBeginWith{}{}{vrai}{faux}| + +\chapitre{Le test}{IfEndWith} + +\exemple|\IfEndWith{abcdef}{ab}{vrai}{faux}| +\exemple|\IfEndWith{abcdef}{f}{vrai}{faux}| +\exemple|\IfEndWith{ a b c }{c}{vrai}{faux}| +\exemple|\IfEndWith{ a b c }{ }{vrai}{faux}| +\exemple|\IfEndWith{a}{a}{vrai}{faux}| +\exemple|\IfEndWith{a}{aa}{vrai}{faux}| +\exemple|\IfEndWith{a}{}{vrai}{faux}| +\exemple|\IfEndWith{}{a}{vrai}{faux}| +\exemple|\IfEndWith{}{}{vrai}{faux}| + +\chapitre{Le test}{IfSubStrBefore} + +\exemple|\IfSubStrBefore{abcdef}{b}{e}{vrai}{faux}| +\exemple|\IfSubStrBefore{abcdef}{e}{c}{vrai}{faux}| +\exemple|\IfSubStrBefore{ a b c }{ }{b}{vrai}{faux}| +\exemple|\IfSubStrBefore{ a b c }{ b}{c }{vrai}{faux}| +\exemple|\IfSubStrBefore{abcdef}{z}{a}{vrai}{faux}| +\exemple|\IfSubStrBefore{abcdef}{y}{z}{vrai}{faux}| +\exemple|\IfSubStrBefore{abcdef}{a}{z}{vrai}{faux}| +\exemple|\IfSubStrBefore{aaa}{a}{aa}{vrai}{faux}| +\exemple|\IfSubStrBefore{abcdef}{a}{a}{vrai}{faux}| +\exemple|\IfSubStrBefore{a}{a}{a}{vrai}{faux}| +\exemple|\IfSubStrBefore{}{a}{b}{vrai}{faux}| +\exemple|\IfSubStrBefore{a}{}{a}{vrai}{faux}| +\exemple|\IfSubStrBefore{}{a}{a}{vrai}{faux}| +\exemple|\IfSubStrBefore{}{}{}{vrai}{faux}| +\exemple|\IfSubStrBefore[1,1]{abacada}{d}{a}{vrai}{faux}| +\exemple|\IfSubStrBefore[1,2]{abacada}{d}{a}{vrai}{faux}| +\exemple|\IfSubStrBefore[1,3]{abacada}{d}{a}{vrai}{faux}| +\exemple|\IfSubStrBefore[1,4]{abacada}{d}{a}{vrai}{faux}| +\exemple|\IfSubStrBefore[2,1]{maman papa}{a}{p}{vrai}{faux}| +\exemple|\IfSubStrBefore[2,2]{maman papa}{a}{p}{vrai}{faux}| +\exemple|\IfSubStrBefore[4,2]{maman papa}{a}{p}{vrai}{faux}| + +\chapitre{Le test}{IfStrBehind} + +\exemple|\IfSubStrBehind{abcdef}{b}{e}{vrai}{faux}| +\exemple|\IfSubStrBehind{abcdef}{e}{c}{vrai}{faux}| +\exemple|\IfSubStrBehind{ a b c }{ }{b}{vrai}{faux}| +\exemple|\IfSubStrBehind{ a b c }{ c}{ a}{vrai}{faux}| +\exemple|\IfSubStrBehind{abcdef}{z}{a}{vrai}{faux}| +\exemple|\IfSubStrBehind{abcdef}{y}{z}{vrai}{faux}| +\exemple|\IfSubStrBehind{abcdef}{a}{z}{vrai}{faux}| +\exemple|\IfSubStrBehind{aaa}{a}{aa}{vrai}{faux}| +\exemple|\IfSubStrBehind{abcdef}{a}{a}{vrai}{faux}| +\exemple|\IfSubStrBehind{a}{a}{a}{vrai}{faux}| +\exemple|\IfSubStrBehind{}{a}{b}{vrai}{faux}| +\exemple|\IfSubStrBehind{a}{}{a}{vrai}{faux}| +\exemple|\IfSubStrBehind{}{a}{a}{vrai}{faux}| +\exemple|\IfSubStrBehind{}{}{}{vrai}{faux}| +\exemple|\IfSubStrBehind[1,1]{abacada}{c}{a}{vrai}{faux}| +\exemple|\IfSubStrBehind[1,2]{abacada}{c}{a}{vrai}{faux}| +\exemple|\IfSubStrBehind[1,3]{abacada}{c}{a}{vrai}{faux}| +\exemple|\IfSubStrBehind[2,1]{maman papa}{a}{p}{vrai}{faux}| +\exemple|\IfSubStrBehind[3,1]{maman papa}{a}{p}{vrai}{faux}| +\exemple|\IfSubStrBehind[3,2]{maman papa}{a}{p}{vrai}{faux}| +\exemple|\IfSubStrBehind[4,2]{maman papa}{a}{p}{vrai}{faux}| + +\chapitre{Le test}{IfInteger} + +\exemple|\IfInteger{156}{vrai}{faux}| +\exemple|\IfInteger{1.6}{vrai}{faux}| +\exemple|\IfInteger{7a5}{vrai}{faux}| +\exemple|\IfInteger{+9}{vrai}{faux}| +\exemple|\IfInteger{-15}{vrai}{faux}| +\exemple|\IfInteger{0}{vrai}{faux}| +\exemple|\IfInteger{-1,2}{vrai}{faux}| +\exemple|\IfInteger{1.}{vrai}{faux}| +\exemple|\IfInteger{-00}{vrai}{faux}| +\exemple|\IfInteger{+}{vrai}{faux}| +\exemple|\IfInteger{-}{vrai}{faux}| +\exemple|\IfInteger{.}{vrai}{faux}| +\exemple|\IfInteger{}{vrai}{faux}| + +\chapitre{Le test}{IfDecimal} + +\exemple|\IfDecimal{6}{vrai}{faux}| +\exemple|\IfDecimal{-78}{vrai}{faux}| +\exemple|\IfDecimal{3.14}{vrai}{faux}| +\exemple|\IfDecimal{3,14}{vrai}{faux}| +\exemple|\IfDecimal{1..5}{vrai}{faux}| +\exemple|\IfDecimal{-9.8}{vrai}{faux}| +\exemple|\IfDecimal{+9.8}{vrai}{faux}| +\exemple|\IfDecimal{-9,8}{vrai}{faux}| +\exemple|\IfDecimal{+9,8}{vrai}{faux}| +\exemple|\IfDecimal{+6.7.}{vrai}{faux}| +\exemple|\IfDecimal{.5}{vrai}{faux}| +\exemple|\IfDecimal{1.}{vrai}{faux}| +\exemple|\IfDecimal{-.99}{vrai}{faux}| +\exemple|\IfDecimal{-5.}{vrai}{faux}| +\exemple|\IfDecimal{5a9.}{vrai}{faux}| +\exemple|\IfDecimal{+}{vrai}{faux}| +\exemple|\IfDecimal{-}{vrai}{faux}| +\exemple|\IfDecimal{.}{vrai}{faux}| +\exemple|\IfDecimal{}{vrai}{faux}| + +\chapitre{Le test}{IfStrEq} + +\exemple|\IfStrEq{abcdef}{abcdef}{vrai}{faux}| +\exemple|\IfStrEq{a b c}{a b c}{vrai}{faux}| +\exemple|\IfStrEq{abcd}{abc}{vrai}{faux}| +\exemple|\IfStrEq{aab}{ab}{vrai}{faux}| +\exemple|\IfStrEq{aab}{aa}{vrai}{faux}| +\exemple|\IfStrEq{1.2}{1.20}{vrai}{faux}| +\exemple|\IfStrEq{3,4}{3.4}{vrai}{faux}| +\exemple|\IfStrEq{ }{ }{vrai}{faux}| +\exemple|\IfStrEq{}{a}{vrai}{faux}| +\exemple|\IfStrEq{a}{}{vrai}{faux}| +\exemple|\IfStrEq{}{}{vrai}{faux}| + +\chapitre{Le test}{IfEq} + +\exemple|\IfEq{abcdef}{abcdef}{vrai}{faux}| +\exemple|\IfEq{a b c}{a b c}{vrai}{faux}| +\exemple|\IfEq{abcd}{abc}{vrai}{faux}| +\exemple|\IfEq{aab}{ab}{vrai}{faux}| +\exemple|\IfEq{aab}{aa}{vrai}{faux}| +\exemple|\IfEq{1.2}{1.20}{vrai}{faux}| +\exemple|\IfEq{+1.0000}{1}{vrai}{faux}| +\exemple|\IfEq{-10}{10}{vrai}{faux}| +\exemple|\IfEq{1,2}{1.2}{vrai}{faux}| +\exemple|\IfEq{.5}{0.5}{vrai}{faux}| +\exemple|\IfEq{,5}{0,5}{vrai}{faux}| +\exemple|\IfEq{10}{dix}{vrai}{faux}| +\exemple|\IfEq{123}{1a3}{vrai}{faux}| +\exemple|\IfEq{0}{}{vrai}{faux}| +\exemple|\IfEq{++10}{+10}{vrai}{faux}| +\exemple|\IfEq{--10}{+10}{vrai}{faux}| +\exemple|\IfEq{a}{}{vrai}{faux}| +\exemple|\IfEq{}{a}{vrai}{faux}| +\exemple|\IfEq{}{}{vrai}{faux}| + +\chapitre{La macro}{StrBefore} + +\exemple|\StrBefore{abcedef}{e}| +\exemple*|\StrBefore{abcdef}{a}| +\exemple*|\StrBefore{abcdef}{z}| +\exemple*|\StrBefore{a b c d}{c}| +\exemple*|\StrBefore{a b c d}{ }| +\exemple*|\StrBefore[2]{a b c d}{ }| +\exemple*|\StrBefore[3]{a b c d}{ }| +\exemple*|\StrBefore[9]{a b c d}{ }| +\exemple*|\StrBefore[-7]{a b c d}{ }| +\exemple*|\StrBefore{abcdef}{Z}| +\exemple*|\StrBefore[1]{aaaaaa}{aa}| +\exemple|\StrBefore[2]{aaaaaa}{aa}| +\exemple|\StrBefore[3]{aaaaaa}{aa}| +\exemple*|\StrBefore[4]{aaaaaa}{aa}| +\exemple*|\StrBefore{a}{}| +\exemple*|\StrBefore{}{a}| +\exemple*|\StrBefore{}{}| + +\AvecArgOptionnel +\exemple|\StrBefore{abcedef}{e}[\aa]\aa| +\exemple*|\StrBefore{abcdef}{a}[\aa]\aa| +\exemple*|\StrBefore{abcdef}{z}[\aa]\aa| +\exemple*|\StrBefore{a b c d}{c}[\aa]\aa| +\exemple*|\StrBefore{a b c d}{ }[\aa]\aa| +\exemple*|\StrBefore[2]{a b c d}{ }[\aa]\aa| +\exemple*|\StrBefore[3]{a b c d}{ }[\aa]\aa| +\exemple*|\StrBefore[9]{a b c d}{ }[\aa]\aa| +\exemple*|\StrBefore[-7]{a b c d}{ }[\aa]\aa| +\exemple*|\StrBefore{abcdef}{Z}[\aa]\aa| +\exemple*|\StrBefore[1]{aaaaaa}{aa}[\aa]\aa| +\exemple|\StrBefore[2]{aaaaaa}{aa}[\aa]\aa| +\exemple|\StrBefore[3]{aaaaaa}{aa}[\aa]\aa| +\exemple*|\StrBefore[4]{aaaaaa}{aa}[\aa]\aa| +\exemple*|\StrBefore{a}{}[\aa]\aa| +\exemple*|\StrBefore{}{a}[\aa]\aa| +\exemple*|\StrBefore{}{}[\aa]\aa| + +\chapitre{La macro}{StrBehind} + +\exemple|\StrBehind{abcedef}{e}| +\exemple*|\StrBehind{abcdef}{a}| +\exemple*|\StrBehind{abcdef}{z}| +\exemple*|\StrBehind{a b c d}{c}| +\exemple*|\StrBehind{a b c d}{ }| +\exemple*|\StrBehind[2]{a b c d}{ }| +\exemple*|\StrBehind[3]{a b c d}{ }| +\exemple*|\StrBehind[9]{a b c d}{ }| +\exemple*|\StrBehind[-7]{a b c d}{ }| +\exemple*|\StrBehind{abcdef}{Z}| +\exemple|\StrBehind[1]{aaaaaa}{aa}| +\exemple|\StrBehind[2]{aaaaaa}{aa}| +\exemple*|\StrBehind[3]{aaaaaa}{aa}| +\exemple*|\StrBehind[4]{aaaaaa}{aa}| +\exemple*|\StrBehind{a}{}| +\exemple*|\StrBehind{}{a}| +\exemple*|\StrBehind{}{}| + +\AvecArgOptionnel +\exemple|\StrBehind{abcedef}{e}[\aa]\aa| +\exemple*|\StrBehind{abcdef}{a}[\aa]\aa| +\exemple*|\StrBehind{abcdef}{z}[\aa]\aa| +\exemple*|\StrBehind{a b c d}{c}[\aa]\aa| +\exemple*|\StrBehind{a b c d}{ }[\aa]\aa| +\exemple*|\StrBehind[2]{a b c d}{ }[\aa]\aa| +\exemple*|\StrBehind[3]{a b c d}{ }[\aa]\aa| +\exemple*|\StrBehind[9]{a b c d}{ }[\aa]\aa| +\exemple*|\StrBehind[-7]{a b c d}{ }[\aa]\aa| +\exemple*|\StrBehind{abcdef}{Z}[\aa]\aa| +\exemple|\StrBehind[1]{aaaaaa}{aa}[\aa]\aa| +\exemple|\StrBehind[2]{aaaaaa}{aa}[\aa]\aa| +\exemple*|\StrBehind[3]{aaaaaa}{aa}[\aa]\aa| +\exemple*|\StrBehind[4]{aaaaaa}{aa}[\aa]\aa| +\exemple*|\StrBehind{a}{}[\aa]\aa| +\exemple*|\StrBehind{}{a}[\aa]\aa| +\exemple*|\StrBehind{}{}[\aa]\aa| + +\chapitre{La macro}{StrBetween} + +\exemple|\StrBetween{abcdef}{b}{e}| +\exemple*|\StrBetween{aZaaaaZa}{Z}{Z}| +\exemple*|\StrBetween[1,2]{aZaaaaZa}{Z}{Z}| +\exemple*|\StrBetween{a b c d}{a}{c}| +\exemple*|\StrBetween{a b c d}{a }{ d}| +\exemple*|\StrBetween{abcdef}{a}{Z}| +\exemple*|\StrBetween{abcdef}{Y}{Z}| +\exemple*|\StrBetween[2,5]{aAaBaCaDa}{a}{a}| +\exemple*|\StrBetween[4,1]{ab1ab2ab3ab4ab}{b}{a}| +\exemple*|\StrBetween[3,4]{a b c d e f}{ }{ }| +\exemple|\StrBetween[1,3]{aaaaaa}{aa}{aa}| +\exemple*|\StrBetween{abcdef}{a}{}| +\exemple*|\StrBetween{abcdef}{}{f}| +\exemple*|\StrBetween{}{a}{b}| + +\AvecArgOptionnel +\exemple|\StrBetween{abcdef}{b}{e}[\aa]\aa| +\exemple*|\StrBetween{aZaaaaZa}{Z}{Z}[\aa]\aa| +\exemple*|\StrBetween[1,2]{aZaaaaZa}{Z}{Z}[\aa]\aa| +\exemple*|\StrBetween{a b c d}{a}{c}[\aa]\aa| +\exemple*|\StrBetween{a b c d}{a }{ d}[\aa]\aa| +\exemple*|\StrBetween{abcdef}{a}{Z}[\aa]\aa| +\exemple*|\StrBetween{abcdef}{Y}{Z}[\aa]\aa| +\exemple*|\StrBetween[2,5]{aAaBaCaDa}{a}{a}[\aa]\aa| +\exemple*|\StrBetween[4,1]{ab1ab2ab3ab4ab}{b}{a}[\aa]\aa| +\exemple*|\StrBetween[3,4]{a b c d e f}{ }{ }[\aa]\aa| +\exemple|\StrBetween[1,3]{aaaaaa}{aa}{aa}[\aa]\aa| +\exemple*|\StrBetween{abcdef}{a}{}[\aa]\aa| +\exemple*|\StrBetween{abcdef}{}{f}[\aa]\aa| +\exemple*|\StrBetween{}{a}{b}[\aa]\aa| + +\chapitre{La macro}{StrSubstitute} + +\exemple|\StrSubstitute{abcdef}{c}{ZZ}| +\exemple|\StrSubstitute{aaaaaaa}{aa}{w}| +\exemple|\StrSubstitute[0]{abacada}{a}{.}| +\exemple|\StrSubstitute[1]{abacada}{a}{.}| +\exemple|\StrSubstitute[2]{abacada}{a}{.}| +\exemple|\StrSubstitute[3]{abacada}{a}{.}| +\exemple|\StrSubstitute[4]{abacada}{a}{.}| +\exemple|\StrSubstitute[5]{abacada}{a}{.}| +\exemple|\StrSubstitute{a b c d e}{ }{,}| +\exemple|\StrSubstitute{a b c d e}{ }{}| +\exemple|\StrSubstitute{abcdef}{}{A}| +\exemple|\StrSubstitute{abcdef}{}{}| +\exemple*|\StrSubstitute{}{a}{b}| +\exemple*|\StrSubstitute{}{}{}| + +\AvecArgOptionnel +\exemple|\StrSubstitute{abcdef}{c}{ZZ}[\aa]\aa| +\exemple|\StrSubstitute{aaaaaaa}{aa}{w}[\aa]\aa| +\exemple|\StrSubstitute[0]{abacada}{a}{.}[\aa]\aa| +\exemple|\StrSubstitute[1]{abacada}{a}{.}[\aa]\aa| +\exemple|\StrSubstitute[2]{abacada}{a}{.}[\aa]\aa| +\exemple|\StrSubstitute[3]{abacada}{a}{.}[\aa]\aa| +\exemple|\StrSubstitute[4]{abacada}{a}{.}[\aa]\aa| +\exemple|\StrSubstitute[5]{abacada}{a}{.}[\aa]\aa| +\exemple|\StrSubstitute{a b c d e}{ }{,}[\aa]\aa| +\exemple|\StrSubstitute{a b c d e}{ }{}[\aa]\aa| +\exemple|\StrSubstitute{abcdef}{}{A}[\aa]\aa| +\exemple|\StrSubstitute{abcdef}{}{}[\aa]\aa| +\exemple*|\StrSubstitute{}{a}{b}[\aa]\aa| +\exemple*|\StrSubstitute{}{}{}[\aa]\aa| + +\chapitre{La macro}{StrDel} + +\exemple|\StrDel{a1a2a3a4}{a}| +\exemple|\StrDel[2]{a1a2a3a4}{a}| +\exemple|\StrDel[-2]{a1a2a3a4}{a}| +\exemple|\StrDel[10]{a1a2a3a4}{a}| +\exemple|\StrDel[3]{a b c d e}{a}| + +\AvecArgOptionnel +\exemple|\StrDel{a1a2a3a4}{a}[\aa]\aa| +\exemple|\StrDel[2]{a1a2a3a4}{a}[\aa]\aa| +\exemple|\StrDel[-2]{a1a2a3a4}{a}[\aa]\aa| +\exemple|\StrDel[10]{a1a2a3a4}{a}[\aa]\aa| +\exemple|\StrDel[3]{a b c d e}{a}[\aa]\aa| + +\chapitre{La macro}{StrLen} + + +\exemple|\StrLen{abcdef}| +\exemple|\StrLen{a b c}| +\exemple|\StrLen{ a b c }| +\exemple|\StrLen{a}| +\exemple|\StrLen{}| + +\AvecArgOptionnel +\exemple|\StrLen{abcdef}[\aa]\aa| +\exemple|\StrLen{a b c}[\aa]\aa| +\exemple|\StrLen{ a b c }[\aa]\aa| +\exemple|\StrLen{a}[\aa]\aa| +\exemple|\StrLen{}[\aa]\aa| + +\chapitre{la macro}{StrMid} + +\exemple|\StrMid{abcdef}{2}{5}| +\exemple*|\StrMid{a b c d}{2}{6}| +\exemple*|\StrMid{abcdef}{4}{2}| +\exemple|\StrMid{abcdef}{-4}{3}| +\exemple*|\StrMid{abcdef}{-4}{-1}| +\exemple|\StrMid{abcdef}{-4}{20}| +\exemple*|\StrMid{abcdef}{8}{10}| +\exemple|\StrMid{abcdef}{2}{2}| +\exemple|\StrMid{aaaaaa}{3}{6}| +\exemple*|\StrMid{}{4}{5}| + +\AvecArgOptionnel +\exemple|\StrMid{abcdef}{2}{5}[\aa]\aa| +\exemple*|\StrMid{a b c d}{2}{6}[\aa]\aa| +\exemple*|\StrMid{abcdef}{4}{2}[\aa]\aa| +\exemple|\StrMid{abcdef}{-4}{3}[\aa]\aa| +\exemple*|\StrMid{abcdef}{-4}{-1}[\aa]\aa| +\exemple|\StrMid{abcdef}{-4}{20}[\aa]\aa| +\exemple*|\StrMid{abcdef}{8}{10}[\aa]\aa| +\exemple|\StrMid{abcdef}{2}{2}[\aa]\aa| +\exemple|\StrMid{aaaaaa}{3}{6}[\aa]\aa| +\exemple*|\StrMid{}{4}{5}[\aa]\aa| + +\chapitre{La macro}{StrGobbleLeft} + +\exemple|\StrGobbleLeft{abcdef}{3}| +\exemple*|\StrGobbleLeft{a b c d}{3}| +\exemple|\StrGobbleLeft{abcdef}{-3}| +\exemple*|\StrGobbleLeft{abcdef}{9}| +\exemple|\StrGobbleLeft{aaaaa}{4}| +\exemple*|\StrGobbleLeft{}{2}| + +\AvecArgOptionnel +\exemple|\StrGobbleLeft{abcdef}{3}[\aa]\aa| +\exemple*|\StrGobbleLeft{a b c d}{3}[\aa]\aa| +\exemple|\StrGobbleLeft{abcdef}{-3}[\aa]\aa| +\exemple*|\StrGobbleLeft{abcdef}{9}[\aa]\aa| +\exemple|\StrGobbleLeft{aaaaa}{4}[\aa]\aa| +\exemple*|\StrGobbleLeft{}{2}[\aa]\aa| + +\chapitre{La macro}{StrGobbleRight} + +\exemple|\StrGobbleRight{abcdef}{3}| +\exemple*|\StrGobbleRight{a b c d}{3}| +\exemple|\StrGobbleRight{abcdef}{-3}| +\exemple*|\StrGobbleRight{abcdef}{9}| +\exemple|\StrGobbleRight{aaaaa}{4}| +\exemple*|\StrGobbleRight{}{2}| + +\AvecArgOptionnel +\exemple|\StrGobbleRight{abcdef}{3}[\aa]\aa| +\exemple*|\StrGobbleRight{a b c d}{3}[\aa]\aa| +\exemple|\StrGobbleRight{abcdef}{-3}[\aa]\aa| +\exemple*|\StrGobbleRight{abcdef}{9}[\aa]\aa| +\exemple|\StrGobbleRight{aaaaa}{4}[\aa]\aa| +\exemple*|\StrGobbleRight{}{2}[\aa]\aa| + +\chapitre{La macro}{StrLeft} + +\exemple|\StrLeft{abcdef}{3}| +\exemple*|\StrLeft{a b c d}{3}| +\exemple*|\StrLeft{abcdef}{-3}| +\exemple*|\StrLeft{abcdef}{9}| +\exemple|\StrLeft{aaaaa}{4}| +\exemple*|\StrLeft{}{2}| + +\AvecArgOptionnel +\exemple|\StrLeft{abcdef}{3}[\aa]\aa| +\exemple*|\StrLeft{a b c d}{3}[\aa]\aa| +\exemple*|\StrLeft{abcdef}{-3}[\aa]\aa| +\exemple*|\StrLeft{abcdef}{9}[\aa]\aa| +\exemple|\StrLeft{aaaaa}{4}[\aa]\aa| +\exemple*|\StrLeft{}{2}[\aa]\aa| + +\chapitre{La macro}{StrRight} + +\exemple|\StrRight{abcdef}{3}| +\exemple*|\StrRight{a b c d}{3}| +\exemple*|\StrRight{abcdef}{-3}| +\exemple*|\StrRight{abcdef}{9}| +\exemple|\StrRight{aaaaa}{4}| +\exemple*|\StrRight{}{2}| + +\AvecArgOptionnel +\exemple|\StrRight{abcdef}{3}[\aa]\aa| +\exemple*|\StrRight{a b c d}{3}[\aa]\aa| +\exemple*|\StrRight{abcdef}{-3}[\aa]\aa| +\exemple*|\StrRight{abcdef}{9}[\aa]\aa| +\exemple|\StrRight{aaaaa}{4}[\aa]\aa| +\exemple*|\StrRight{}{2}[\aa]\aa| + +\chapitre{la macro}{StrChar} + +\exemple|\StrChar{abcdef}{5}| +\exemple*|\StrChar{a b c d}{4}| +\exemple|\StrChar{a b c d}{7}| +\exemple*|\StrChar{abcdef}{10}| +\exemple*|\StrChar{abcdef}{-5}| +\exemple*|\StrChar{}{3}| + +\AvecArgOptionnel +\exemple|\StrChar{abcdef}{5}[\aa]\aa| +\exemple*|\StrChar{a b c d}{4}[\aa]\aa| +\exemple|\StrChar{a b c d}{7}[\aa]\aa| +\exemple*|\StrChar{abcdef}{10}[\aa]\aa| +\exemple*|\StrChar{abcdef}{-5}[\aa]\aa| +\exemple*|\StrChar{}{3}[\aa]\aa| + +\chapitre{La macro}{StrCount} + +\exemple|\StrCount{abcdef}{d}| +\exemple|\StrCount{a b c d}{ }| +\exemple|\StrCount{aaaaaa}{aa}| +\exemple|\StrCount{abcdef}{Z}| +\exemple|\StrCount{abcdef}{}| +\exemple|\StrCount{}{a}| +\exemple|\StrCount{}{}| + +\AvecArgOptionnel +\exemple|\StrCount{abcdef}{d}[\aa]\aa| +\exemple|\StrCount{a b c d}{ }[\aa]\aa| +\exemple|\StrCount{aaaaaa}{aa}[\aa]\aa| +\exemple|\StrCount{abcdef}{Z}[\aa]\aa| +\exemple|\StrCount{abcdef}{}[\aa]\aa| +\exemple|\StrCount{}{a}[\aa]\aa| +\exemple|\StrCount{}{}[\aa]\aa| + +\chapitre{La macro}{StrPosition} + +\exemple|\StrPosition{abcdef}{c}| +\exemple|\StrPosition{abcdef}{Z}| +\exemple|\StrPosition{a b c d}{ }| +\exemple|\StrPosition[3]{a b c d}{ }| +\exemple|\StrPosition[8]{a b c d}{ }| +\exemple|\StrPosition{aaaaaa}{aa}| +\exemple|\StrPosition[2]{aaaaaa}{aa}| +\exemple|\StrPosition[3]{aaaaaa}{aa}| +\exemple|\StrPosition{abcdef}{}| +\exemple|\StrPosition{}{a}| +\exemple|\StrPosition{}{}| + +\AvecArgOptionnel +\exemple|\StrPosition{abcdef}{c}[\aa]\aa| +\exemple|\StrPosition{abcdef}{Z}[\aa]\aa| +\exemple|\StrPosition{a b c d}{ }[\aa]\aa| +\exemple|\StrPosition[3]{a b c d}{ }[\aa]\aa| +\exemple|\StrPosition[8]{a b c d}{ }[\aa]\aa| +\exemple|\StrPosition{aaaaaa}{aa}[\aa]\aa| +\exemple|\StrPosition[2]{aaaaaa}{aa}[\aa]\aa| +\exemple|\StrPosition[3]{aaaaaa}{aa}[\aa]\aa| +\exemple|\StrPosition{abcdef}{}[\aa]\aa| +\exemple|\StrPosition{}{a}[\aa]\aa| +\exemple|\StrPosition{}{}[\aa]\aa| + +\chapitre{La macro}{StrCompare} + +La tolérance normale :\par +\exemple|\StrCompare{abcdefghij}{abc}| +\exemple|\StrCompare{A}{A}| +\exemple|\StrCompare{abcdef}{a bd}| +\exemple|\StrCompare{ }{ }| +\exemple|\StrCompare{}{abcd}| +\exemple|\StrCompare{abcd}{}| +\exemple|\StrCompare{123456}{1234}| +\exemple|\StrCompare{a b c d}{a bcd}| +\exemple|\StrCompare{}{}| +\exemple|\StrCompare{eee}{eeee}| +\exemple|\StrCompare{eeee}{eee}| +\exemple|\StrCompare{totutu}{tututu}| +\exemple|\StrCompare{abcd}{abyz}| + +\AvecArgOptionnel +\exemple|\StrCompare{abcdefghij}{abc}[\aa]\aa| +\exemple|\StrCompare{A}{A}[\aa]\aa| +\exemple|\StrCompare{abcdef}{a bd}[\aa]\aa| +\exemple|\StrCompare{ }{ }[\aa]\aa| +\exemple|\StrCompare{}{abcd}[\aa]\aa| +\exemple|\StrCompare{abcd}{}[\aa]\aa| +\exemple|\StrCompare{123456}{1234}[\aa]\aa| +\exemple|\StrCompare{a b c d}{a bcd}[\aa]\aa| +\exemple|\StrCompare{}{}[\aa]\aa| +\exemple|\StrCompare{eee}{eeee}[\aa]\aa| +\exemple|\StrCompare{eeee}{eee}[\aa]\aa| +\exemple|\StrCompare{totutu}{tututu}[\aa]\aa| +\exemple|\StrCompare{abcd}{abyz}[\aa]\aa| + +La tolérance stricte :\par\comparestrict +\exemple|\StrCompare{abcdefghij}{abc}| +\exemple|\StrCompare{A}{A}| +\exemple|\StrCompare{abcdef}{a bd}| +\exemple|\StrCompare{ }{ }| +\exemple|\StrCompare{}{abcd}| +\exemple|\StrCompare{abcd}{}| +\exemple|\StrCompare{123456}{1234}| +\exemple|\StrCompare{a b c d}{a bcd}| +\exemple|\StrCompare{}{}| +\exemple|\StrCompare{eee}{eeee}| +\exemple|\StrCompare{eeee}{eee}| +\exemple|\StrCompare{totutu}{tututu}| +\exemple|\StrCompare{abcd}{abyz}| + +\AvecArgOptionnel +\exemple|\StrCompare{abcdefghij}{abc}[\aa]\aa| +\exemple|\StrCompare{A}{A}[\aa]\aa| +\exemple|\StrCompare{abcdef}{a bd}[\aa]\aa| +\exemple|\StrCompare{ }{ }[\aa]\aa| +\exemple|\StrCompare{}{abcd}[\aa]\aa| +\exemple|\StrCompare{abcd}{}[\aa]\aa| +\exemple|\StrCompare{123456}{1234}[\aa]\aa| +\exemple|\StrCompare{a b c d}{a bcd}[\aa]\aa| +\exemple|\StrCompare{}{}[\aa]\aa| +\exemple|\StrCompare{eee}{eeee}[\aa]\aa| +\exemple|\StrCompare{eeee}{eee}[\aa]\aa| +\exemple|\StrCompare{totutu}{tututu}[\aa]\aa| +\exemple|\StrCompare{abcd}{abyz}[\aa]\aa| +\vskip5em + +\hfill{\hugerm Le mode \hugett\string\noexpandarg}\hfill{} + +\vskip-1ex\hfil\hbox to8cm{\hrulefill}\hfil{}\vskip3.5ex + +Dans toute la suite sauf si c'est précisé, la commande {\tt\string\noexpandarg} est activée.\vskip1.5ex + +\catcode`\@=11\relax +\expandafter\long\expandafter\def\csname xs_assign_verb\endcsname#1{% + \tokenize\cs@resultat{#1}% + \leavevmode\hbox to0.7\hsize{\hfil\tt#1}\quad\frontiere\cs@resultat\frontiere\hfil\par}% +\catcode`\@=12\relax +\noexpandarg + +\chapitre{Le test}{IfSubStr} + +\exemple|\noexploregroups| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{2}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{34}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{{34}}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{\b}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{\bc}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{\bc5}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{\bc{5}}{vrai}{faux}| +\exemple|\IfSubStr[1]{\a1{\a1{\a1}\a2}\a3}{\a}{vrai}{faux}| +\exemple|\IfSubStr[2]{\a1{\a1{\a1}\a2}\a3}{\a}{vrai}{faux}| +\exemple|\IfSubStr[3]{\a1{\a1{\a1}\a2}\a3}{\a}{vrai}{faux}| +\exemple|\IfSubStr[4]{\a1{\a1{\a1}\a2}\a3}{\a}{vrai}{faux}| +\exemple|\exploregroups| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{2}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{34}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{{34}}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{\b}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{\bc}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{\bc5}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{\bc{5}}{vrai}{faux}| +\exemple|\IfSubStr[1]{\a1{\a1{\a1}\a2}\a3}{\a}{vrai}{faux}| +\exemple|\IfSubStr[2]{\a1{\a1{\a1}\a2}\a3}{\a}{vrai}{faux}| +\exemple|\IfSubStr[3]{\a1{\a1{\a1}\a2}\a3}{\a}{vrai}{faux}| +\exemple|\IfSubStr[4]{\a1{\a1{\a1}\a2}\a3}{\a}{vrai}{faux}| + +\chapitre{Le test}{IfBeginWith} + +Les tests doivent donner des résultats identiques ci-dessous puisque {\tt\string\IfBeginWith} est indifférent au mode d'exploration des groupes !\vskip0.7ex + +\exemple|\noexploregroups| +\exemple|\IfBeginWith{{\a}123\b456}{\a}{vrai}{faux}| +\exemple|\IfBeginWith{{\a}123\b456}{{\a}}{vrai}{faux}| +\exemple|\IfBeginWith{{\a1}\b\c\d}{\a}{vrai}{faux}| +\exemple|\IfBeginWith{{1}23456}{12}{vrai}{faux}| +\exemple|\IfBeginWith{{1}23456}{1}{vrai}{faux}| +\exemple|\IfBeginWith{{1}23456}{{1}2}{vrai}{faux}| +\exemple|\exploregroups| +\exemple|\IfBeginWith{{\a}123\b456}{\a}{vrai}{faux}| +\exemple|\IfBeginWith{{\a}123\b456}{{\a}}{vrai}{faux}| +\exemple|\IfBeginWith{{\a1}\b\c\d}{\a}{vrai}{faux}| +\exemple|\IfBeginWith{{1}23456}{12}{vrai}{faux}| +\exemple|\IfBeginWith{{1}23456}{1}{vrai}{faux}| +\exemple|\IfBeginWith{{1}23456}{{1}2}{vrai}{faux}| + +\chapitre{Le test}{IfEndWith} + +Les tests doivent donner des résultats identiques ci-dessous puisque {\tt\string\IfEndWith} est indifférent au mode d'exploration des groupes !\vskip0.7ex + +\exemple|\noexploregroups| +\exemple|\IfEndWith{\a1\b2{\c3}}{\c3}{vrai}{faux}| +\exemple|\IfEndWith{\a1\b2{\c3}}{{\c3}}{vrai}{faux}| +\exemple|\IfEndWith{\a1\b2{\c3}}{3}{vrai}{faux}| +\exemple|\IfEndWith{12345{6}}{56}{vrai}{faux}| +\exemple|\IfEndWith{12345{6}}{6}{vrai}{faux}| +\exemple|\IfEndWith{12345{6}}{5{6}}{vrai}{faux}| +\exemple|\exploregroups| +\exemple|\IfEndWith{\a1\b2{\c3}}{\c3}{vrai}{faux}| +\exemple|\IfEndWith{\a1\b2{\c3}}{{\c3}}{vrai}{faux}| +\exemple|\IfEndWith{\a1\b2{\c3}}{3}{vrai}{faux}| +\exemple|\IfEndWith{12345{6}}{56}{vrai}{faux}| +\exemple|\IfEndWith{12345{6}}{6}{vrai}{faux}| +\exemple|\IfEndWith{12345{6}}{5{6}}{vrai}{faux}| + +\chapitre{Le test}{IfSubStrBefore} + +\exemple|\noexploregroups| +\exemple|\IfSubStrBefore[1,1]{\a1\a2\a3\b1\b2\b3}{2}{\b}{vrai}{faux}| +\exemple|\IfSubStrBefore[2,1]{\a1\a2\a3\b1\b2\b3}{2}{\b}{vrai}{faux}| +\exemple|\IfSubStrBefore[2,3]{\a1\a2\a3\b1\b2\b3}{\a}{\b}{vrai}{faux}| +\exemple|\IfSubStrBefore[1,1]{\a1{\a2\a3\b1}\b2\b3}{2}{\b}{vrai}{faux}| +\exemple|\IfSubStrBefore[1,2]{\a1{\a2\a3\b1}\b2\b3}{3}{\b}{vrai}{faux}| +\exemple|\exploregroups| +\exemple|\IfSubStrBefore[1,1]{\a1\a2\a3\b1\b2\b3}{2}{\b}{vrai}{faux}| +\exemple|\IfSubStrBefore[2,1]{\a1\a2\a3\b1\b2\b3}{2}{\b}{vrai}{faux}| +\exemple|\IfSubStrBefore[2,3]{\a1\a2\a3\b1\b2\b3}{\a}{\b}{vrai}{faux}| +\exemple|\IfSubStrBefore[1,1]{\a1{\a2\a3\b1}\b2\b3}{2}{\b}{vrai}{faux}| +\exemple|\IfSubStrBefore[1,2]{\a1{\a2\a3\b1}\b2\b3}{3}{\b}{vrai}{faux}| + +\chapitre{Le test}{IfStrBehind} + +\exemple|\noexploregroups| +\exemple|\IfSubStrBehind[2,1]{\a1\a2\a3\b1\b2\b3}{2}{\b}{vrai}{faux}| +\exemple|\IfSubStrBehind[3,1]{\a1\a2\a3\b1\b2\b3}{\a}{\b}{vrai}{faux}| +\exemple|\IfSubStrBehind[1,1]{\a1\a2\a3\b1\b2\b3}{\b}{3}{vrai}{faux}| +\exemple|\IfSubStrBehind[2,1]{\a1{\a2\a3\b1}\b2\b3}{\b}{3}{vrai}{faux}| +\exemple|\IfSubStrBehind[1,1]{\a1{\a2\a3\b1}\b2\b3}{3}{\b}{vrai}{faux}| +\exemple|\exploregroups| +\exemple|\IfSubStrBehind[2,1]{\a1\a2\a3\b1\b2\b3}{2}{\b}{vrai}{faux}| +\exemple|\IfSubStrBehind[3,1]{\a1\a2\a3\b1\b2\b3}{\a}{\b}{vrai}{faux}| +\exemple|\IfSubStrBehind[1,1]{\a1\a2\a3\b1\b2\b3}{\b}{3}{vrai}{faux}| +\exemple|\IfSubStrBehind[2,1]{\a1{\a2\a3\b1}\b2\b3}{\b}{3}{vrai}{faux}| +\exemple|\IfSubStrBehind[1,1]{\a1{\a2\a3\b1}\b2\b3}{3}{\b}{vrai}{faux}| + +\chapitre{Le test}{IfInteger} + +Dans les exemples ci-dessous, on examine la différence de comportement de la macro {\tt\string\IfInteger} selon les modes de développement des arguments.\vskip0.7ex + +\exemple|\def\nbA{-12}\def\nbB{498}| +\exemple|\def\nbAA{\nbA}\def\nbBB{\nbB}|\vskip0.7ex +\exemple|\fullexpandarg| +\exemple|\IfInteger{\nbA}{vrai}{faux}| +\exemple|\IfInteger{\nbA5\nbA}{vrai}{faux}| +\exemple|\IfInteger{\nbA6\nbB}{vrai}{faux}| +\exemple|\IfInteger{\nbAA7\nbBB}{vrai}{faux}|\vskip0.7ex +\exemple|\expandarg| +\exemple|\IfInteger{\nbA}{vrai}{faux}| +\exemple|\IfInteger{\nbA5\nbA}{vrai}{faux}| +\exemple|\IfInteger{\nbA6\nbB}{vrai}{faux}| +\exemple|\IfInteger{\nbAA7\nbBB}{vrai}{faux}|\vskip0.7ex +\exemple|\noexpandarg| +\exemple|\IfInteger{\nbA}{vrai}{faux}| +\exemple|\IfInteger{\nbA5\nbA}{vrai}{faux}| +\exemple|\IfInteger{\nbA6\nbB}{vrai}{faux}| +\exemple|\IfInteger{\nbAA7\nbBB}{vrai}{faux}| + +\chapitre{Le test}{IfDecimal} + +Dans les exemples ci-dessous, on examine la différence de comportement de la macro {\tt\string\IfDecimal} selon les modes de développement des arguments.\vskip0.7ex + +\exemple|\def\nbA{-12}\def\nbB{498}| +\exemple|\def\nbAA{\nbA}\def\nbBB{\nbB}|\vskip0.7ex +\exemple|\fullexpandarg| +\exemple|\IfDecimal{\nbA,\nbB}{vrai}{faux}| +\exemple|\IfDecimal{\nbAA.\nbB}{vrai}{faux}| +\exemple|\IfDecimal{\nbB,777}{vrai}{faux}| +\exemple|\IfDecimal{3\nbB,777}{vrai}{faux}| +\exemple|\IfDecimal{\nbB,\nbB}{vrai}{faux}|\vskip0.7ex +\exemple|\expandarg| +\exemple|\IfDecimal{\nbA,\nbB}{vrai}{faux}| +\exemple|\IfDecimal{\nbAA.\nbB}{vrai}{faux}| +\exemple|\IfDecimal{\nbB,777}{vrai}{faux}| +\exemple|\IfDecimal{3\nbB,777}{vrai}{faux}| +\exemple|\IfDecimal{\nbB,\nbB}{vrai}{faux}|\vskip0.7ex +\exemple|\noexpandarg| +\exemple|\IfDecimal{\nbA,\nbB}{vrai}{faux}| +\exemple|\IfDecimal{\nbAA.\nbB}{vrai}{faux}| +\exemple|\IfDecimal{\nbB,777}{vrai}{faux}| +\exemple|\IfDecimal{3\nbB,777}{vrai}{faux}| +\exemple|\IfDecimal{\nbB,\nbB}{vrai}{faux}| + +\chapitre{La macro}{StrBefore} + +\exemple|\noexploregroups| +\exemple|\StrBefore[2]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrBefore[3]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrBefore[4]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrBefore[5]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrBefore[6]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\exploregroups| +\exemple|\StrBefore[2]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrBefore[3]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrBefore[4]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrBefore[5]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrBefore[6]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}| + +\chapitre{La macro}{StrBehind} + +\exemple|\noexploregroups| +\exemple|\StrBehind[2]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrBehind[3]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrBehind[4]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrBehind[5]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrBehind[6]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\exploregroups| +\exemple|\StrBehind[2]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrBehind[3]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrBehind[4]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrBehind[5]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrBehind[6]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}| + +\chapitre{La macro}{StrBetween} + +La commande {\tt\string\StrBetween} opère en mode {\tt\string\noexploregroups}, quelque soit le mode d'exploration en cours.\vskip0.7ex + +\exemple|\StrBetween[1,3]{\a1\a2{3\a4}5\a6{7\a8}9\a0}{2}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrBetween[2,3]{\a1\a2{3\a4}5\a6{7\a8}9\a0}{\a}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrBetween[1,3]{\a1\a2{3\a4}5\a6{7\a8}9\a0}{3}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrBetween[2,4]{\a1\a2{3\a4}5\a6{7\a8}9\a0}{\a}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex + +\chapitre{La macro}{StrSubstitute} + +\exemple|\noexploregroups| +\exemple|\StrSubstitute{\a1{2\a{3\a}4\a}\a5\a}{\a}{\X}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrSubstitute[2]{\a1{2\a{3\a}4\a}\a5\a}{\a}{\X}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrSubstitute{\a1{2\a{3\a}4\a}\a5\a}{2}{X}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrSubstitute{\a1{2\a{3\a}4\a}\a5\a}{{3\a}}{XXX}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrSubstitute{\a1{2\a{3\a}4\a}\a5\a}{3\a}{XXX}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrSubstitute{a1{b1\bgroup c1}\egroup d1}{1}{X}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\exploregroups| +\exemple|\StrSubstitute{\a1{2\a{3\a}4\a}\a5\a}{\a}{\X}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrSubstitute[2]{\a1{2\a{3\a}4\a}\a5\a}{\a}{\X}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrSubstitute{\a1{2\a{3\a}4\a}\a5\a}{2}{X}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrSubstitute{\a1{2\a{3\a}4\a}\a5\a}{{3\a}}{XXX}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrSubstitute{\a1{2\a{3\a}4\a}\a5\a}{3\a}{XXX}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}| +\exemple|\StrSubstitute{a1{b1\bgroup c1}\egroup d1}{1}{X}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip + +\chapitre{La macro}{StrDel} + +\exemple|\noexploregroups| +\exemple|\StrDel{\a1{2\a{3\a}4\a}\a5\a}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrDel[2]{\a1{2\a{3\a}4\a}\a5\a}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrDel{\a1{2\a{3\a}4\a}\a5\a}{2}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrDel{\a1{2\a{3\a}4\a}\a5\a}{{3\a}}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrDel{\a1{2\a{3\a}4\a}\a5\a}{3\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\exploregroups| +\exemple|\StrDel{\a1{2\a{3\a}4\a}\a5\a}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrDel[2]{\a1{2\a{3\a}4\a}\a5\a}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrDel{\a1{2\a{3\a}4\a}\a5\a}{2}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrDel{\a1{2\a{3\a}4\a}\a5\a}{{3\a}}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrDel{\a1{2\a{3\a}4\a}\a5\a}{3\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex + +\chapitre{La macro}{StrLen} + +\exemple|\noexploregroups| +\exemple|\StrLen{a1{a2}{\a\b}{a3}a4}| +\exemple|\exploregroups| +\exemple|\StrLen{a1{a2}{\a\b}{a3}a4}| + +\chapitre{la macro}{StrSplit} + +\exemple|\noexploregroups| +\exemple|\StrSplit{\a{\b{\c\d}\e}\f\g}{2}\xx\yy| +\exemple|\#\detokenize\expandafter{\xx}\#\quad\#\detokenize\expandafter{\yy}\#| +\exemple|\StrSplit{\a{\b{\c\d}\e}\f\g}{3}\xx\yy| +\exemple|\#\detokenize\expandafter{\xx}\#\quad\#\detokenize\expandafter{\yy}\#| +\exemple|\exploregroups| +\exemple|\StrSplit{\a{\b{\c\d}\e}\f\g}{2}\xx\yy| +\exemple|\#\detokenize\expandafter{\xx}\#\quad\#\detokenize\expandafter{\yy}\#| +\exemple|\StrSplit{\a{\b{\c\d}\e}\f\g}{3}\xx\yy| +\exemple|\#\detokenize\expandafter{\xx}\#\quad\#\detokenize\expandafter{\yy}\#| + +\chapitre{la macro}{StrMid} + +La commande {\tt\string\StrMid} opère en mode {\tt\string\noexploregroups}, quelque soit le mode d'exploration en cours.\vskip0.7ex + +\exemple|\StrMid{\a\b{\c\d}\e\f\g\h}{2}{6}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\StrMid{\a\b{\c\d}\e\f\g\h}{3}{4}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex + +\chapitre{La macro}{StrGobbleLeft} + +\exemple|\noexploregroups| +\exemple|\StrGobbleLeft{\a\b{\c\d\e}\f}{3}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\exploregroups| +\exemple|\StrGobbleLeft{\a\b{\c\d\e}\f}{3}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}| + +\chapitre{La macro}{StrGobbleRight} + +\exemple|\noexploregroups| +\exemple|\StrGobbleRight{\a\b{\c\d\e}\f}{3}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\exploregroups| +\exemple|\StrGobbleRight{\a\b{\c\d\e}\f}{3}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex + +\chapitre{La macro}{StrLeft} + +\exemple|\noexploregroups| +\exemple|\StrLeft{\a\b{\c\d\e}\f}{3}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\exploregroups| +\exemple|\StrLeft{\a\b{\c\d\e}\f}{3}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}| + +\chapitre{La macro}{StrRight} + +\exemple|\noexploregroups| +\exemple|\StrRight{\a\b{\c\d\e}\f}{3}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\exploregroups| +\exemple|\StrRight{\a\b{\c\d\e}\f}{3}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex + +\chapitre{la macro}{StrChar} + +\exemple|\noexploregroups| +\exemple|\StrChar{\a\b{\c\d\e}\f}{3}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\exploregroups| +\exemple|\StrChar{\a\b{\c\d\e}\f}{3}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex + +\chapitre{La macro}{StrCount} + +\exemple|\noexploregroups| +\exemple|\StrCount{\a1{\a2{\a3\a4}\a5}\a6\a7}{\a}| +\exemple|\StrCount{\a1{\a2{\a3\a4}\a5}\a6\a7}{2}| +\exemple|\exploregroups| +\exemple|\StrCount{\a1{\a2{\a3\a4}\a5}\a6\a7}{\a}| +\exemple|\StrCount{\a1{\a2{\a3\a4}\a5}\a6\a7}{2}| + +\chapitre{La macro}{StrPosition} + +\exemple|\noexploregroups| +\exemple|\StrPosition[3]{\a0\a1{\a{2\a3}4}\a5\a6}{\a}| +\exemple|\StrPosition[4]{\a0\a1{\a{3\a4}5}\a6\a7}{\a}| +\exemple|\StrPosition[1]{\a0\a1{\a{2\a3}4}\a5\a6}{2}| +\exemple|\exploregroups| +\exemple|\StrPosition[3]{\a0\a1{\a{2\a3}4}\a5\a6}{\a}| +\exemple|\StrPosition[4]{\a0\a1{\a{2\a3}4}\a5\a6}{\a}| +\exemple|\StrPosition[1]{\a0\a1{\a{2\a3}4}\a5\a6}{2}| + +\chapitre{La macro}{StrCompare} + +La commande {\tt\string\StrCompare} n'est pas affectée par le mode d'exploration.\vskip0.7ex + +\exemple|\comparenormal| +\exemple|\StrCompare{\a{\b1}\c2}{\a\b1\c2}| +\exemple|\StrCompare{{1\a2}3}{{1\a2}3}| +\exemple|\StrCompare{{1\a2}3}{1\a23}| +\exemple|\StrCompare{\a{\b\c}}{\a{\b\c}\d}| +\exemple|\StrCompare{{\a}\b}{\a\b}| +\exemple|\comparestrict| +\exemple|\StrCompare{\a{\b1}\c2}{\a\b1\c2}| +\exemple|\StrCompare{{1\a2}3}{{1\a2}3}| +\exemple|\StrCompare{{1\a2}3}{1\a23}| +\exemple|\StrCompare{\a{\b\c}}{\a{\b\c}\d}| +\exemple|\StrCompare{{\a}\b}{\a\b}| + +\chapitre{La macro}{StrRemoveBraces} + +\exemple|\noexploregroups| +\exemple|\StrRemoveBraces{\a1{\b2{\c3{\d4}}}\e5}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\exemple|\exploregroups| +\exemple|\StrRemoveBraces{\a1{\b2{\c3{\d4}}}\e5}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\vskip0.7ex +\end
\ No newline at end of file diff --git a/macros/generic/xstring/test_latex.pdf b/macros/generic/xstring/test_latex.pdf Binary files differnew file mode 100644 index 0000000000..2642a17751 --- /dev/null +++ b/macros/generic/xstring/test_latex.pdf diff --git a/macros/generic/xstring/test_latex.tex b/macros/generic/xstring/test_latex.tex new file mode 100644 index 0000000000..ca5d54f022 --- /dev/null +++ b/macros/generic/xstring/test_latex.tex @@ -0,0 +1,1078 @@ +% Ceci est test_latex.tex, le fichier de test de xstring à compiler avec LaTeX +\documentclass[a4paper,10pt]{article} +\usepackage[utf8]{inputenc} +\usepackage[T1]{fontenc} +\usepackage{lmodern} +\usepackage[margin=1cm,noheadfoot]{geometry} +\pagestyle{empty} +\usepackage{xstring} + +\makeatletter + +\newcommand*\exemple{\@ifstar{\def\frontiere{|}\csname xs_toks_toverb\endcsname}{\def\frontiere{}\csname xs_toks_toverb\endcsname}} +\expandafter\def\csname xs_assign_verb\endcsname#1{% + \noexpandarg + \tokenize\cs@resultat{#1}% + \fullexpandarg + \leavevmode\hbox to0.7\linewidth{\hfil\tt#1}\quad\frontiere\cs@resultat\frontiere\hfil\par}% +\makeatother + +\newcommand\chapitre[2]{\bigskip{\large\textbf{#1} \texttt{\textbackslash#2}}\smallskip} +\def\delimiteur{|} + +\begin{document} +\parindent0pt + +\begin{center}\Large{Ceci est le fichier de test de xstring}.\end{center} +\vspace{-1.8ex}\hrule\smallskip + +\hrule + +\bigskip +Toutes les situations ne sont pas envisagées, mais au moins un grand nombre ! Les macros sont examinées dans l'ordre logique du code. + +Lorsque le résultat contient des espaces ou peut conduire à des doutes, il sera entouré de ''\delimiteur``, étant entendu que ''\delimiteur\delimiteur`` est une chaîne vide.\bigskip + +\hfill{\Large Le mode \tt\textbackslash fullexpandarg}\hfill{} + +\vspace{-1.5ex}\hspace{6cm}\hrulefill\hspace{6cm} + +\bigskip +\chapitre{Le test}{IfSubStr} + +\exemple|\IfSubStr{abcdef}{cd}{vrai}{faux}| +\exemple|\IfSubStr{a b c d }{b c}{vrai}{faux}| +\exemple|\IfSubStr{a b c d }{bc}{vrai}{faux}| +\exemple|\IfSubStr{abcdef}{}{vrai}{faux}| +\exemple|\IfSubStr{a}{a}{vrai}{faux}| +\exemple|\IfSubStr{aaaa}{aa}{vrai}{faux}| +\exemple|\IfSubStr{a}{aa}{vrai}{faux}| +\exemple|\IfSubStr{éà èï}{à }{vrai}{faux}| +\exemple|\IfSubStr{éà èï}{ù}{vrai}{faux}| +\exemple|\IfSubStr{ÉÀÇ}{Ç}{vrai}{faux}| +\exemple|\IfSubStr{a}{}{vrai}{faux}| +\exemple|\IfSubStr{}{a}{vrai}{faux}| +\exemple|\IfSubStr{}{}{vrai}{faux}| +\exemple|\IfSubStr[2]{abaca}{a}{vrai}{faux}| +\exemple|\IfSubStr[3]{abaca}{a}{vrai}{faux}| +\exemple|\IfSubStr[4]{abaca}{a}{vrai}{faux}| +\exemple|\IfSubStr[-2]{abaca}{a}{vrai}{faux}| + +\chapitre{Le test}{IfBeginWith} + +\exemple|\IfBeginWith{abcdef}{adc}{vrai}{faux}| +\exemple|\IfBeginWith{abcdef}{abcd}{vrai}{faux}| +\exemple|\IfBeginWith{ a b c }{ a}{vrai}{faux}| +\exemple|\IfBeginWith{a b c d}{ab}{vrai}{faux}| +\exemple|\IfBeginWith{a}{a}{vrai}{faux}| +\exemple|\IfBeginWith{a}{aa}{vrai}{faux}| +\exemple|\IfBeginWith{éà èï}{è}{vrai}{faux}| +\exemple|\IfBeginWith{éà èï}{éà }{vrai}{faux}| +\exemple|\IfBeginWith{ÉÀÇ}{É}{vrai}{faux}| +\exemple|\IfBeginWith{a}{}{vrai}{faux}| +\exemple|\IfBeginWith{}{a}{vrai}{faux}| +\exemple|\IfBeginWith{}{}{vrai}{faux}| + +\chapitre{Le test}{IfEndWith} + +\exemple|\IfEndWith{abcdef}{ab}{vrai}{faux}| +\exemple|\IfEndWith{abcdef}{f}{vrai}{faux}| +\exemple|\IfEndWith{ a b c }{c}{vrai}{faux}| +\exemple|\IfEndWith{ a b c }{ }{vrai}{faux}| +\exemple|\IfEndWith{a}{a}{vrai}{faux}| +\exemple|\IfEndWith{a}{aa}{vrai}{faux}| +\exemple|\IfEndWith{éà èï}{è}{vrai}{faux}| +\exemple|\IfEndWith{éà èï}{ï}{vrai}{faux}| +\exemple|\IfEndWith{ÉÀÇ}{Ç}{vrai}{faux}| +\exemple|\IfEndWith{a}{}{vrai}{faux}| +\exemple|\IfEndWith{}{a}{vrai}{faux}| +\exemple|\IfEndWith{}{}{vrai}{faux}| + +\chapitre{Le test}{IfSubStrBefore} + +\exemple|\IfSubStrBefore{abcdef}{b}{e}{vrai}{faux}| +\exemple|\IfSubStrBefore{abcdef}{e}{c}{vrai}{faux}| +\exemple|\IfSubStrBefore{ a b c }{ }{b}{vrai}{faux}| +\exemple|\IfSubStrBefore{ a b c }{ b}{c }{vrai}{faux}| +\exemple|\IfSubStrBefore{abcdef}{z}{a}{vrai}{faux}| +\exemple|\IfSubStrBefore{abcdef}{y}{z}{vrai}{faux}| +\exemple|\IfSubStrBefore{abcdef}{a}{z}{vrai}{faux}| +\exemple|\IfSubStrBefore{aaa}{a}{aa}{vrai}{faux}| +\exemple|\IfSubStrBefore{abcdef}{a}{a}{vrai}{faux}| +\exemple|\IfSubStrBefore{éà èï}{à }{ï}{vrai}{faux}| +\exemple|\IfSubStrBefore{éà èï}{é}{à }{vrai}{faux}| +\exemple|\IfSubStrBefore{ÉÀÇ}{Ç}{É}{vrai}{faux}| +\exemple|\IfSubStrBefore{a}{a}{a}{vrai}{faux}| +\exemple|\IfSubStrBefore{}{a}{b}{vrai}{faux}| +\exemple|\IfSubStrBefore{a}{}{a}{vrai}{faux}| +\exemple|\IfSubStrBefore{}{a}{a}{vrai}{faux}| +\exemple|\IfSubStrBefore{}{}{}{vrai}{faux}| +\exemple|\IfSubStrBefore[1,1]{abacada}{d}{a}{vrai}{faux}| +\exemple|\IfSubStrBefore[1,2]{abacada}{d}{a}{vrai}{faux}| +\exemple|\IfSubStrBefore[1,3]{abacada}{d}{a}{vrai}{faux}| +\exemple|\IfSubStrBefore[1,4]{abacada}{d}{a}{vrai}{faux}| +\exemple|\IfSubStrBefore[2,1]{maman papa}{a}{p}{vrai}{faux}| +\exemple|\IfSubStrBefore[2,2]{maman papa}{a}{p}{vrai}{faux}| +\exemple|\IfSubStrBefore[4,2]{maman papa}{a}{p}{vrai}{faux}| + +\chapitre{Le test}{IfStrBehind} + +\exemple|\IfSubStrBehind{abcdef}{b}{e}{vrai}{faux}| +\exemple|\IfSubStrBehind{abcdef}{e}{c}{vrai}{faux}| +\exemple|\IfSubStrBehind{ a b c }{ }{b}{vrai}{faux}| +\exemple|\IfSubStrBehind{ a b c }{ c}{ a}{vrai}{faux}| +\exemple|\IfSubStrBehind{abcdef}{z}{a}{vrai}{faux}| +\exemple|\IfSubStrBehind{abcdef}{y}{z}{vrai}{faux}| +\exemple|\IfSubStrBehind{abcdef}{a}{z}{vrai}{faux}| +\exemple|\IfSubStrBehind{aaa}{a}{aa}{vrai}{faux}| +\exemple|\IfSubStrBehind{abcdef}{a}{a}{vrai}{faux}| +\exemple|\IfSubStrBehind{éà èï}{ï}{à }{vrai}{faux}| +\exemple|\IfSubStrBehind{éà èï}{à }{é}{vrai}{faux}| +\exemple|\IfSubStrBehind{ÉÀÇ}{À}{Ç}{vrai}{faux}| +\exemple|\IfSubStrBehind{a}{a}{a}{vrai}{faux}| +\exemple|\IfSubStrBehind{}{a}{b}{vrai}{faux}| +\exemple|\IfSubStrBehind{a}{}{a}{vrai}{faux}| +\exemple|\IfSubStrBehind{}{a}{a}{vrai}{faux}| +\exemple|\IfSubStrBehind{}{}{}{vrai}{faux}| +\exemple|\IfSubStrBehind[1,1]{abacada}{c}{a}{vrai}{faux}| +\exemple|\IfSubStrBehind[1,2]{abacada}{c}{a}{vrai}{faux}| +\exemple|\IfSubStrBehind[1,3]{abacada}{c}{a}{vrai}{faux}| +\exemple|\IfSubStrBehind[2,1]{maman papa}{a}{p}{vrai}{faux}| +\exemple|\IfSubStrBehind[3,1]{maman papa}{a}{p}{vrai}{faux}| +\exemple|\IfSubStrBehind[3,2]{maman papa}{a}{p}{vrai}{faux}| +\exemple|\IfSubStrBehind[4,2]{maman papa}{a}{p}{vrai}{faux}| + +\chapitre{Le test}{IfInteger} + +\exemple|\IfInteger{156}{vrai}{faux}| +\exemple|\IfInteger{1.6}{vrai}{faux}| +\exemple|\IfInteger{7a5}{vrai}{faux}| +\exemple|\IfInteger{+9}{vrai}{faux}| +\exemple|\IfInteger{-15}{vrai}{faux}| +\exemple|\IfInteger{0}{vrai}{faux}| +\exemple|\IfInteger{-1,2}{vrai}{faux}| +\exemple|\IfInteger{1.}{vrai}{faux}| +\exemple|\IfInteger{-00}{vrai}{faux}| +\exemple|\IfInteger{+}{vrai}{faux}| +\exemple|\IfInteger{-}{vrai}{faux}| +\exemple|\IfInteger{.}{vrai}{faux}| +\exemple|\IfInteger{}{vrai}{faux}| + +\chapitre{Le test}{IfDecimal} + +\exemple|\IfDecimal{6}{vrai}{faux}| +\exemple|\IfDecimal{-78}{vrai}{faux}| +\exemple|\IfDecimal{3.14}{vrai}{faux}| +\exemple|\IfDecimal{3,14}{vrai}{faux}| +\exemple|\IfDecimal{1..5}{vrai}{faux}| +\exemple|\IfDecimal{-9.8}{vrai}{faux}| +\exemple|\IfDecimal{+9.8}{vrai}{faux}| +\exemple|\IfDecimal{-9,8}{vrai}{faux}| +\exemple|\IfDecimal{+9,8}{vrai}{faux}| +\exemple|\IfDecimal{+6.7.}{vrai}{faux}| +\exemple|\IfDecimal{.5}{vrai}{faux}| +\exemple|\IfDecimal{1.}{vrai}{faux}| +\exemple|\IfDecimal{-.99}{vrai}{faux}| +\exemple|\IfDecimal{-5.}{vrai}{faux}| +\exemple|\IfDecimal{5a9.}{vrai}{faux}| +\exemple|\IfDecimal{+}{vrai}{faux}| +\exemple|\IfDecimal{-}{vrai}{faux}| +\exemple|\IfDecimal{.}{vrai}{faux}| +\exemple|\IfDecimal{}{vrai}{faux}| + +\chapitre{Le test}{IfStrEq} + +\exemple|\IfStrEq{abcdef}{abcdef}{vrai}{faux}| +\exemple|\IfStrEq{a b c}{a b c}{vrai}{faux}| +\exemple|\IfStrEq{abcd}{abc}{vrai}{faux}| +\exemple|\IfStrEq{aab}{ab}{vrai}{faux}| +\exemple|\IfStrEq{aab}{aa}{vrai}{faux}| +\exemple|\IfStrEq{1.2}{1.20}{vrai}{faux}| +\exemple|\IfStrEq{3,4}{3.4}{vrai}{faux}| +\exemple|\IfStrEq{ }{ }{vrai}{faux}| +\exemple|\IfStrEq{}{a}{vrai}{faux}| +\exemple|\IfStrEq{a}{}{vrai}{faux}| +\exemple|\IfStrEq{}{}{vrai}{faux}| + +\chapitre{Le test}{IfEq} + +\exemple|\IfEq{abcdef}{abcdef}{vrai}{faux}| +\exemple|\IfEq{a b c}{a b c}{vrai}{faux}| +\exemple|\IfEq{abcd}{abc}{vrai}{faux}| +\exemple|\IfEq{aab}{ab}{vrai}{faux}| +\exemple|\IfEq{aab}{aa}{vrai}{faux}| +\exemple|\IfEq{1.2}{1.20}{vrai}{faux}| +\exemple|\IfEq{+1.0000}{1}{vrai}{faux}| +\exemple|\IfEq{-10}{10}{vrai}{faux}| +\exemple|\IfEq{1,2}{1.2}{vrai}{faux}| +\exemple|\IfEq{.5}{0.5}{vrai}{faux}| +\exemple|\IfEq{,5}{0,5}{vrai}{faux}| +\exemple|\IfEq{10}{dix}{vrai}{faux}| +\exemple|\IfEq{123}{1a3}{vrai}{faux}| +\exemple|\IfEq{0}{}{vrai}{faux}| +\exemple|\IfEq{++10}{+10}{vrai}{faux}| +\exemple|\IfEq{--10}{+10}{vrai}{faux}| +\exemple|\IfEq{a}{}{vrai}{faux}| +\exemple|\IfEq{}{a}{vrai}{faux}| +\exemple|\IfEq{}{}{vrai}{faux}| + +\chapitre{La macro}{StrBefore} + +\exemple|\StrBefore{abcedef}{e}| +\exemple*|\StrBefore{abcdef}{a}| +\exemple*|\StrBefore{abcdef}{z}| +\exemple*|\StrBefore{a b c d}{c}| +\exemple*|\StrBefore{a b c d}{ }| +\exemple*|\StrBefore[2]{a b c d}{ }| +\exemple*|\StrBefore[3]{a b c d}{ }| +\exemple*|\StrBefore[9]{a b c d}{ }| +\exemple*|\StrBefore[-7]{a b c d}{ }| +\exemple*|\StrBefore{abcdef}{Z}| +\exemple|\StrBefore{éà èï}{è}| +\exemple|\StrBefore[2]{étété}{é}| +\exemple|\StrBefore{ÉÀÇ}{À}| +\exemple*|\StrBefore[1]{aaaaaa}{aa}| +\exemple|\StrBefore[2]{aaaaaa}{aa}| +\exemple|\StrBefore[3]{aaaaaa}{aa}| +\exemple*|\StrBefore[4]{aaaaaa}{aa}| +\exemple*|\StrBefore{a}{}| +\exemple*|\StrBefore{}{a}| +\exemple*|\StrBefore{}{}| +\par\bigskip Mêmes exemples avec l'argument optionnel : + +\exemple|\StrBefore{abcedef}{e}[\aa]\aa| +\exemple*|\StrBefore{abcdef}{a}[\aa]\aa| +\exemple*|\StrBefore{abcdef}{z}[\aa]\aa| +\exemple*|\StrBefore{a b c d}{c}[\aa]\aa| +\exemple*|\StrBefore{a b c d}{ }[\aa]\aa| +\exemple*|\StrBefore[2]{a b c d}{ }[\aa]\aa| +\exemple*|\StrBefore[3]{a b c d}{ }[\aa]\aa| +\exemple*|\StrBefore[9]{a b c d}{ }[\aa]\aa| +\exemple*|\StrBefore[-7]{a b c d}{ }[\aa]\aa| +\exemple*|\StrBefore{abcdef}{Z}[\aa]\aa| +\exemple|\StrBefore{éà èï}{è}[\aa]\aa| +\exemple|\StrBefore[2]{étété}{é}[\aa]\aa| +\exemple|\StrBefore{ÉÀÇ}{À}[\aa]\aa| +\exemple*|\StrBefore[1]{aaaaaa}{aa}[\aa]\aa| +\exemple|\StrBefore[2]{aaaaaa}{aa}[\aa]\aa| +\exemple|\StrBefore[3]{aaaaaa}{aa}[\aa]\aa| +\exemple*|\StrBefore[4]{aaaaaa}{aa}[\aa]\aa| +\exemple*|\StrBefore{a}{}[\aa]\aa| +\exemple*|\StrBefore{}{a}[\aa]\aa| +\exemple*|\StrBefore{}{}[\aa]\aa| + +\chapitre{La macro}{StrBehind} + +\exemple|\StrBehind{abcedef}{e}| +\exemple*|\StrBehind{abcdef}{a}| +\exemple*|\StrBehind{abcdef}{z}| +\exemple*|\StrBehind{a b c d}{c}| +\exemple*|\StrBehind{a b c d}{ }| +\exemple*|\StrBehind[2]{a b c d}{ }| +\exemple*|\StrBehind[3]{a b c d}{ }| +\exemple*|\StrBehind[9]{a b c d}{ }| +\exemple*|\StrBehind[-7]{a b c d}{ }| +\exemple*|\StrBehind{abcdef}{Z}| +\exemple|\StrBehind{éà èï}{è}| +\exemple|\StrBehind{ÉÀÇ}{À}| +\exemple|\StrBehind[1]{aaaaaa}{aa}| +\exemple|\StrBehind[2]{aaaaaa}{aa}| +\exemple*|\StrBehind[3]{aaaaaa}{aa}| +\exemple*|\StrBehind[4]{aaaaaa}{aa}| +\exemple*|\StrBehind{a}{}| +\exemple*|\StrBehind{}{a}| +\exemple*|\StrBehind{}{}| +\par\bigskip Mêmes exemples avec l'argument optionnel : + +\exemple|\StrBehind{abcedef}{e}[\aa]\aa| +\exemple*|\StrBehind{abcdef}{a}[\aa]\aa| +\exemple*|\StrBehind{abcdef}{z}[\aa]\aa| +\exemple*|\StrBehind{a b c d}{c}[\aa]\aa| +\exemple*|\StrBehind{a b c d}{ }[\aa]\aa| +\exemple*|\StrBehind[2]{a b c d}{ }[\aa]\aa| +\exemple*|\StrBehind[3]{a b c d}{ }[\aa]\aa| +\exemple*|\StrBehind[9]{a b c d}{ }[\aa]\aa| +\exemple*|\StrBehind[-7]{a b c d}{ }[\aa]\aa| +\exemple*|\StrBehind{abcdef}{Z}[\aa]\aa| +\exemple|\StrBehind{éà èï}{è}[\aa]\aa| +\exemple|\StrBehind{ÉÀÇ}{À}[\aa]\aa| +\exemple|\StrBehind[1]{aaaaaa}{aa}[\aa]\aa| +\exemple|\StrBehind[2]{aaaaaa}{aa}[\aa]\aa| +\exemple*|\StrBehind[3]{aaaaaa}{aa}[\aa]\aa| +\exemple*|\StrBehind[4]{aaaaaa}{aa}[\aa]\aa| +\exemple*|\StrBehind{a}{}[\aa]\aa| +\exemple*|\StrBehind{}{a}[\aa]\aa| +\exemple*|\StrBehind{}{}[\aa]\aa| + +\chapitre{La macro}{StrBetween} + +\exemple|\StrBetween{abcdef}{b}{e}| +\exemple*|\StrBetween{aZaaaaZa}{Z}{Z}| +\exemple*|\StrBetween[1,2]{aZaaaaZa}{Z}{Z}| +\exemple*|\StrBetween{a b c d}{a}{c}| +\exemple*|\StrBetween{a b c d}{a }{ d}| +\exemple*|\StrBetween{abcdef}{a}{Z}| +\exemple*|\StrBetween{abcdef}{Y}{Z}| +\exemple*|\StrBetween[2,5]{aAaBaCaDa}{a}{a}| +\exemple*|\StrBetween[4,1]{ab1ab2ab3ab4ab}{b}{a}| +\exemple*|\StrBetween[3,4]{a b c d e f}{ }{ }| +\exemple|\StrBetween[1,3]{aaaaaa}{aa}{aa}| +\exemple|\StrBetween{éà èï}{é}{ï}| +\exemple|\StrBetween{ÉÀÇ}{É}{Ç}| +\exemple*|\StrBetween{abcdef}{a}{}| +\exemple*|\StrBetween{abcdef}{}{f}| +\exemple*|\StrBetween{}{a}{b}| +\par\bigskip Mêmes exemples avec l'argument optionnel : + +\exemple|\StrBetween{abcdef}{b}{e}[\aa]\aa| +\exemple*|\StrBetween{aZaaaaZa}{Z}{Z}[\aa]\aa| +\exemple*|\StrBetween[1,2]{aZaaaaZa}{Z}{Z}[\aa]\aa| +\exemple*|\StrBetween{a b c d}{a}{c}[\aa]\aa| +\exemple*|\StrBetween{a b c d}{a }{ d}[\aa]\aa| +\exemple*|\StrBetween{abcdef}{a}{Z}[\aa]\aa| +\exemple*|\StrBetween{abcdef}{Y}{Z}[\aa]\aa| +\exemple*|\StrBetween[2,5]{aAaBaCaDa}{a}{a}[\aa]\aa| +\exemple*|\StrBetween[4,1]{ab1ab2ab3ab4ab}{b}{a}[\aa]\aa| +\exemple*|\StrBetween[3,4]{a b c d e f}{ }{ }[\aa]\aa| +\exemple|\StrBetween[1,3]{aaaaaa}{aa}{aa}[\aa]\aa| +\exemple|\StrBetween{éà èï}{é}{ï}[\aa]\aa| +\exemple|\StrBetween{ÉÀÇ}{É}{Ç}[\aa]\aa| +\exemple*|\StrBetween{abcdef}{a}{}[\aa]\aa| +\exemple*|\StrBetween{abcdef}{}{f}[\aa]\aa| +\exemple*|\StrBetween{}{a}{b}[\aa]\aa| + +\chapitre{La macro}{StrSubstitute} + +\exemple|\StrSubstitute{abcdef}{c}{ZZ}| +\exemple|\StrSubstitute{aaaaaaa}{aa}{w}| +\exemple|\StrSubstitute[0]{abacada}{a}{.}| +\exemple|\StrSubstitute[1]{abacada}{a}{.}| +\exemple|\StrSubstitute[2]{abacada}{a}{.}| +\exemple|\StrSubstitute[3]{abacada}{a}{.}| +\exemple|\StrSubstitute[4]{abacada}{a}{.}| +\exemple|\StrSubstitute[5]{abacada}{a}{.}| +\exemple|\StrSubstitute{a b c d e}{ }{,}| +\exemple|\StrSubstitute{a b c d e}{ }{}| +\exemple|\StrSubstitute{éà èï}{è}{Z}| +\exemple|\StrSubstitute{ÉÀÇ}{Ç}{c}| +\exemple|\StrSubstitute{abcdef}{}{A}| +\exemple|\StrSubstitute{abcdef}{}{}| +\exemple*|\StrSubstitute{}{a}{b}| +\exemple*|\StrSubstitute{}{}{}| +\par\bigskip Mêmes exemples avec l'argument optionnel : + +\exemple|\StrSubstitute{abcdef}{c}{ZZ}[\aa]\aa| +\exemple|\StrSubstitute{aaaaaaa}{aa}{w}[\aa]\aa| +\exemple|\StrSubstitute[0]{abacada}{a}{.}[\aa]\aa| +\exemple|\StrSubstitute[1]{abacada}{a}{.}[\aa]\aa| +\exemple|\StrSubstitute[2]{abacada}{a}{.}[\aa]\aa| +\exemple|\StrSubstitute[3]{abacada}{a}{.}[\aa]\aa| +\exemple|\StrSubstitute[4]{abacada}{a}{.}[\aa]\aa| +\exemple|\StrSubstitute[5]{abacada}{a}{.}[\aa]\aa| +\exemple|\StrSubstitute{a b c d e}{ }{,}[\aa]\aa| +\exemple|\StrSubstitute{a b c d e}{ }{}[\aa]\aa| +\exemple|\StrSubstitute{éà èï}{è}{Z}[\aa]\aa| +\exemple|\StrSubstitute{ÉÀÇ}{Ç}{c}[\aa]\aa| +\exemple|\StrSubstitute{abcdef}{}{A}[\aa]\aa| +\exemple|\StrSubstitute{abcdef}{}{}[\aa]\aa| +\exemple*|\StrSubstitute{}{a}{b}[\aa]\aa| +\exemple*|\StrSubstitute{}{}{}[\aa]\aa| + +\chapitre{La macro}{StrDel} + +\exemple|\StrDel{a1a2a3a4}{a}| +\exemple|\StrDel[2]{a1a2a3a4}{a}| +\exemple|\StrDel[-2]{a1a2a3a4}{a}| +\exemple|\StrDel[10]{a1a2a3a4}{a}| +\exemple|\StrDel[3]{a b c d e}{a}| +\par\bigskip Mêmes exemples avec l'argument optionnel : + +\exemple|\StrDel{a1a2a3a4}{a}[\aa]\aa| +\exemple|\StrDel[2]{a1a2a3a4}{a}[\aa]\aa| +\exemple|\StrDel[-2]{a1a2a3a4}{a}[\aa]\aa| +\exemple|\StrDel[10]{a1a2a3a4}{a}[\aa]\aa| +\exemple|\StrDel[3]{a b c d e}{a}[\aa]\aa| + +\chapitre{La macro}{StrLen} + +\exemple|\StrLen{abcdef}| +\exemple|\StrLen{a b c}| +\exemple|\StrLen{ a b c }| +\exemple|\StrLen{a}| +\exemple|\StrLen{éà èï}|% fonctionne mal en utf8 : donne 8 au lieu de 4 +\exemple|\StrLen{ÉÀÇ}|% idem +\exemple|\StrLen{}| +\par\bigskip Mêmes exemples avec l'argument optionnel : + +\exemple|\StrLen{abcdef}[\aa]\aa| +\exemple|\StrLen{a b c}[\aa]\aa| +\exemple|\StrLen{ a b c }[\aa]\aa| +\exemple|\StrLen{a}[\aa]\aa| +\exemple|\StrLen{éà èï}[\aa]\aa|% fonctionne mal en utf8 : donne 8 au lieu de 4 +\exemple|\StrLen{ÉÀÇ}[\aa]\aa|% idem +\exemple|\StrLen{}[\aa]\aa| + +\chapitre{la macro}{StrSplit} + +\exemple|\StrSplit{abcde}{3}{\xx}{\yy}\#\xx\#\quad\#\yy\#| +\exemple|\StrSplit{abcde}{1}{\xx}{\yy}\#\xx\#\quad\#\yy\#| +\exemple|\StrSplit{abcde}{0}{\xx}{\yy}\#\xx\#\quad\#\yy\#| +\exemple|\StrSplit{abcde}{-5}{\xx}{\yy}\#\xx\#\quad\#\yy\#| +\exemple|\StrSplit{abcde}{20}{\xx}{\yy}\#\xx\#\quad\#\yy\#| +\exemple|\StrSplit{a b c}{4}{\xx}{\yy}\#\xx\#\quad\#\yy\#| +\exemple|\StrSplit{éà çù}{2}{\xx}{\yy}\#\xx\#\quad\#\yy\#| +\exemple|\StrSplit{}{3}{\xx}{\yy}\#\xx\#\quad\#\yy\#| + +\chapitre{la macro}{StrMid} + +\exemple|\StrMid{abcdef}{2}{5}| +\exemple*|\StrMid{a b c d}{2}{6}| +\exemple*|\StrMid{abcdef}{4}{2}| +\exemple|\StrMid{abcdef}{-4}{3}| +\exemple*|\StrMid{abcdef}{-4}{-1}| +\exemple|\StrMid{abcdef}{-4}{20}| +\exemple*|\StrMid{abcdef}{8}{10}| +\exemple|\StrMid{abcdef}{2}{2}| +\exemple|\StrMid{éà èï}{2}{3}| +\exemple|\StrMid{ÉÀÇ}{2}{3}| +\exemple|\StrMid{aaaaaa}{3}{6}| +\exemple*|\StrMid{}{4}{5}| +\par\bigskip Mêmes exemples avec l'argument optionnel : + +\exemple|\StrMid{abcdef}{2}{5}[\aa]\aa| +\exemple*|\StrMid{a b c d}{2}{6}[\aa]\aa| +\exemple*|\StrMid{abcdef}{4}{2}[\aa]\aa| +\exemple|\StrMid{abcdef}{-4}{3}[\aa]\aa| +\exemple*|\StrMid{abcdef}{-4}{-1}[\aa]\aa| +\exemple|\StrMid{abcdef}{-4}{20}[\aa]\aa| +\exemple*|\StrMid{abcdef}{8}{10}[\aa]\aa| +\exemple|\StrMid{abcdef}{2}{2}[\aa]\aa| +\exemple|\StrMid{éà èï}{2}{3}[\aa]\aa| +\exemple|\StrMid{ÉÀÇ}{2}{3}[\aa]\aa| +\exemple|\StrMid{aaaaaa}{3}{6}[\aa]\aa| +\exemple*|\StrMid{}{4}{5}[\aa]\aa| + +\chapitre{La macro}{StrGobbleLeft} + +\exemple|\StrGobbleLeft{abcdef}{3}| +\exemple*|\StrGobbleLeft{a b c d}{3}| +\exemple|\StrGobbleLeft{abcdef}{-3}| +\exemple*|\StrGobbleLeft{abcdef}{9}| +\exemple|\StrGobbleLeft{éà èï}{2}| +\exemple|\StrGobbleLeft{ÉÀÇ}{1}| +\exemple|\StrGobbleLeft{aaaaa}{4}| +\exemple*|\StrGobbleLeft{}{2}| +\par\bigskip Mêmes exemples avec l'argument optionnel : + +\exemple|\StrGobbleLeft{abcdef}{3}[\aa]\aa| +\exemple*|\StrGobbleLeft{a b c d}{3}[\aa]\aa| +\exemple|\StrGobbleLeft{abcdef}{-3}[\aa]\aa| +\exemple*|\StrGobbleLeft{abcdef}{9}[\aa]\aa| +\exemple|\StrGobbleLeft{éà èï}{2}[\aa]\aa| +\exemple|\StrGobbleLeft{ÉÀÇ}{1}[\aa]\aa| +\exemple|\StrGobbleLeft{aaaaa}{4}[\aa]\aa| +\exemple*|\StrGobbleLeft{}{2}[\aa]\aa| + +\chapitre{La macro}{StrGobbleRight} + +\exemple|\StrGobbleRight{abcdef}{3}| +\exemple*|\StrGobbleRight{a b c d}{3}| +\exemple|\StrGobbleRight{abcdef}{-3}| +\exemple*|\StrGobbleRight{abcdef}{9}| +\exemple|\StrGobbleRight{éà èï}{2}| +\exemple|\StrGobbleRight{ÉÀÇ}{1}| +\exemple|\StrGobbleRight{aaaaa}{4}| +\exemple*|\StrGobbleRight{}{2}| +\par\bigskip Mêmes exemples avec l'argument optionnel : + +\exemple|\StrGobbleRight{abcdef}{3}[\aa]\aa| +\exemple*|\StrGobbleRight{a b c d}{3}[\aa]\aa| +\exemple|\StrGobbleRight{abcdef}{-3}[\aa]\aa| +\exemple*|\StrGobbleRight{abcdef}{9}[\aa]\aa| +\exemple|\StrGobbleRight{éà èï}{2}[\aa]\aa| +\exemple|\StrGobbleRight{ÉÀÇ}{1}[\aa]\aa| +\exemple|\StrGobbleRight{aaaaa}{4}[\aa]\aa| +\exemple*|\StrGobbleRight{}{2}[\aa]\aa| + +\chapitre{La macro}{StrLeft} + +\exemple|\StrLeft{abcdef}{3}| +\exemple*|\StrLeft{a b c d}{3}| +\exemple*|\StrLeft{abcdef}{-3}| +\exemple*|\StrLeft{abcdef}{9}| +\exemple|\StrLeft{éà èï}{2}| +\exemple|\StrLeft{ÉÀÇ}{1}| +\exemple|\StrLeft{aaaaa}{4}| +\exemple*|\StrLeft{}{2}| +\par\bigskip Mêmes exemples avec l'argument optionnel : + +\exemple|\StrLeft{abcdef}{3}[\aa]\aa| +\exemple*|\StrLeft{a b c d}{3}[\aa]\aa| +\exemple*|\StrLeft{abcdef}{-3}[\aa]\aa| +\exemple*|\StrLeft{abcdef}{9}[\aa]\aa| +\exemple|\StrLeft{éà èï}{2}[\aa]\aa| +\exemple|\StrLeft{ÉÀÇ}{1}[\aa]\aa| +\exemple|\StrLeft{aaaaa}{4}[\aa]\aa| +\exemple*|\StrLeft{}{2}[\aa]\aa| + +\chapitre{La macro}{StrRight} + +\exemple|\StrRight{abcdef}{3}| +\exemple*|\StrRight{a b c d}{3}| +\exemple*|\StrRight{abcdef}{-3}| +\exemple*|\StrRight{abcdef}{9}| +\exemple|\StrRight{éà èï}{2}| +\exemple|\StrRight{ÉÀÇ}{1}| +\exemple|\StrRight{aaaaa}{4}| +\exemple*|\StrRight{}{2}| +\par\bigskip Mêmes exemples avec l'argument optionnel : + +\exemple|\StrRight{abcdef}{3}[\aa]\aa| +\exemple*|\StrRight{a b c d}{3}[\aa]\aa| +\exemple*|\StrRight{abcdef}{-3}[\aa]\aa| +\exemple*|\StrRight{abcdef}{9}[\aa]\aa| +\exemple|\StrRight{éà èï}{2}[\aa]\aa| +\exemple|\StrRight{ÉÀÇ}{1}[\aa]\aa| +\exemple|\StrRight{aaaaa}{4}[\aa]\aa| +\exemple*|\StrRight{}{2}[\aa]\aa| + +\chapitre{la macro}{StrChar} + +\exemple|\StrChar{abcdef}{5}| +\exemple*|\StrChar{a b c d}{4}| +\exemple|\StrChar{a b c d}{7}| +\exemple*|\StrChar{abcdef}{10}| +\exemple*|\StrChar{abcdef}{-5}| +\exemple*|\StrChar{}{3}| +\par\bigskip Mêmes exemples avec l'argument optionnel : + +\exemple|\StrChar{abcdef}{5}[\aa]\aa| +\exemple*|\StrChar{a b c d}{4}[\aa]\aa| +\exemple|\StrChar{a b c d}{7}[\aa]\aa| +\exemple*|\StrChar{abcdef}{10}[\aa]\aa| +\exemple*|\StrChar{abcdef}{-5}[\aa]\aa| +\exemple*|\StrChar{}{3}[\aa]\aa| + +\chapitre{La macro}{StrCount} + +\exemple|\StrCount{abcdef}{d}| +\exemple|\StrCount{a b c d}{ }| +\exemple|\StrCount{aaaaaa}{aa}| +\exemple|\StrCount{étété}{é}| +\exemple|\StrCount{abcdef}{Z}| +\exemple|\StrCount{éà èï}{é}| +\exemple|\StrCount{ÉÀÇ}{Ç}| +\exemple|\StrCount{abcdef}{}| +\exemple|\StrCount{}{a}| +\exemple|\StrCount{}{}| +\par\bigskip Mêmes exemples avec l'argument optionnel : + +\exemple|\StrCount{abcdef}{d}[\aa]\aa| +\exemple|\StrCount{a b c d}{ }[\aa]\aa| +\exemple|\StrCount{aaaaaa}{aa}[\aa]\aa| +\exemple|\StrCount{étété}{é}[\aa]\aa| +\exemple|\StrCount{abcdef}{Z}[\aa]\aa| +\exemple|\StrCount{éà èï}{é}[\aa]\aa| +\exemple|\StrCount{ÉÀÇ}{Ç}[\aa]\aa| +\exemple|\StrCount{abcdef}{}[\aa]\aa| +\exemple|\StrCount{}{a}[\aa]\aa| +\exemple|\StrCount{}{}[\aa]\aa| + +\chapitre{La macro}{StrPosition} + +\exemple|\StrPosition{abcdef}{c}| +\exemple|\StrPosition{abcdef}{Z}| +\exemple|\StrPosition{a b c d}{ }| +\exemple|\StrPosition[3]{a b c d}{ }| +\exemple|\StrPosition[8]{a b c d}{ }| +\exemple|\StrPosition{étété}{é}| +\exemple|\StrPosition[3]{étété}{é}| +\exemple|\StrPosition[5]{étété}{é}| +\exemple|\StrPosition{aaaaaa}{aa}| +\exemple|\StrPosition[2]{aaaaaa}{aa}| +\exemple|\StrPosition[3]{aaaaaa}{aa}| +\exemple|\StrPosition{éà èï}{è}| +\exemple|\StrPosition{ÉÀÇ}{À}| +\exemple|\StrPosition{abcdef}{}| +\exemple|\StrPosition{}{a}| +\exemple|\StrPosition{}{}| +\par\bigskip Mêmes exemples avec l'argument optionnel : + +\exemple|\StrPosition{abcdef}{c}[\aa]\aa| +\exemple|\StrPosition{abcdef}{Z}[\aa]\aa| +\exemple|\StrPosition{a b c d}{ }[\aa]\aa| +\exemple|\StrPosition[3]{a b c d}{ }[\aa]\aa| +\exemple|\StrPosition[8]{a b c d}{ }[\aa]\aa| +\exemple|\StrPosition{étété}{é}[\aa]\aa| +\exemple|\StrPosition[3]{étété}{é}[\aa]\aa| +\exemple|\StrPosition[5]{étété}{é}[\aa]\aa| +\exemple|\StrPosition{aaaaaa}{aa}[\aa]\aa| +\exemple|\StrPosition[2]{aaaaaa}{aa}[\aa]\aa| +\exemple|\StrPosition[3]{aaaaaa}{aa}[\aa]\aa| +\exemple|\StrPosition{éà èï}{è}[\aa]\aa| +\exemple|\StrPosition{ÉÀÇ}{À}[\aa]\aa| +\exemple|\StrPosition{abcdef}{}[\aa]\aa| +\exemple|\StrPosition{}{a}[\aa]\aa| +\exemple|\StrPosition{}{}[\aa]\aa| + +\chapitre{La macro}{StrCompare} + +La tolérance normale :\par\comparenormal +\exemple|\StrCompare{abcdefghij}{abc}| +\exemple|\StrCompare{A}{A}| +\exemple|\StrCompare{éçà }{éçà }| +\exemple|\StrCompare{abcdef}{a bd}| +\exemple|\StrCompare{ }{ }| +\exemple|\StrCompare{}{abcd}| +\exemple|\StrCompare{abcd}{}| +\exemple|\StrCompare{123456}{1234}| +\exemple|\StrCompare{a b c d}{a bcd}| +\exemple|\StrCompare{}{}| +\exemple|\StrCompare{eee}{eeee}| +\exemple|\StrCompare{eeee}{eee}| +\exemple|\StrCompare{totutu}{tututu}| +\exemple|\StrCompare{abcd}{abyz}| +\par\bigskip Mêmes exemples avec l'argument optionnel : + +\exemple|\StrCompare{abcdefghij}{abc}[\aa]\aa| +\exemple|\StrCompare{A}{A}[\aa]\aa| +\exemple|\StrCompare{éçà }{éçà }[\aa]\aa| +\exemple|\StrCompare{abcdef}{a bd}[\aa]\aa| +\exemple|\StrCompare{ }{ }[\aa]\aa| +\exemple|\StrCompare{}{abcd}[\aa]\aa| +\exemple|\StrCompare{abcd}{}[\aa]\aa| +\exemple|\StrCompare{123456}{1234}[\aa]\aa| +\exemple|\StrCompare{a b c d}{a bcd}[\aa]\aa| +\exemple|\StrCompare{}{}[\aa]\aa| +\exemple|\StrCompare{eee}{eeee}[\aa]\aa| +\exemple|\StrCompare{eeee}{eee}[\aa]\aa| +\exemple|\StrCompare{totutu}{tututu}[\aa]\aa| +\exemple|\StrCompare{abcd}{abyz}[\aa]\aa| + +La tolérance stricte :\comparestrict\par +\exemple|\StrCompare{abcdefghij}{abc}| +\exemple|\StrCompare{A}{A}| +\exemple|\StrCompare{éçà }{éçà }| +\exemple|\StrCompare{abcdef}{a bd}| +\exemple|\StrCompare{ }{ }| +\exemple|\StrCompare{}{abcd}| +\exemple|\StrCompare{abcd}{}| +\exemple|\StrCompare{123456}{1234}| +\exemple|\StrCompare{a b c d}{a bcd}| +\exemple|\StrCompare{}{}| +\exemple|\StrCompare{eee}{eeee}| +\exemple|\StrCompare{eeee}{eee}| +\exemple|\StrCompare{totutu}{tututu}| +\exemple|\StrCompare{abcd}{abyz}| +\par\bigskip Mêmes exemples avec l'argument optionnel : + +\exemple|\StrCompare{abcdefghij}{abc}[\aa]\aa| +\exemple|\StrCompare{A}{A}[\aa]\aa| +\exemple|\StrCompare{éçà }{éçà }[\aa]\aa| +\exemple|\StrCompare{abcdef}{a bd}[\aa]\aa| +\exemple|\StrCompare{ }{ }[\aa]\aa| +\exemple|\StrCompare{}{abcd}[\aa]\aa| +\exemple|\StrCompare{abcd}{}[\aa]\aa| +\exemple|\StrCompare{123456}{1234}[\aa]\aa| +\exemple|\StrCompare{a b c d}{a bcd}[\aa]\aa| +\exemple|\StrCompare{}{}[\aa]\aa| +\exemple|\StrCompare{eee}{eeee}[\aa]\aa| +\exemple|\StrCompare{eeee}{eee}[\aa]\aa| +\exemple|\StrCompare{totutu}{tututu}[\aa]\aa| +\exemple|\StrCompare{abcd}{abyz}[\aa]\aa| +\vspace{10ex} + +\hfill{\Large Le mode \tt\textbackslash noexpandarg}\hfill{} + +\vspace{-1.5ex}\hspace{6cm}\hrulefill\hspace{6cm} + +\bigskip +Dans toute la suite sauf si c'est précisé, la commande \verb|\noexpandarg| est activée.\bigskip +\makeatletter + +\expandafter\long\expandafter\def\csname xs_assign_verb\endcsname#1{% + \tokenize\cs@resultat{#1}% + \leavevmode\hbox to0.7\linewidth{\hfil\tt#1}\quad\frontiere\cs@resultat\frontiere\hfil\par}% +\makeatother +\noexpandarg + +\bigskip +\chapitre{Le test}{IfSubStr} + +\exemple|\noexploregroups| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{2}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{34}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{{34}}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{\b}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{\bc}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{\bc5}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{\bc{5}}{vrai}{faux}| +\exemple|\IfSubStr[1]{\a1{\a1{\a1}\a2}\a3}{\a}{vrai}{faux}| +\exemple|\IfSubStr[2]{\a1{\a1{\a1}\a2}\a3}{\a}{vrai}{faux}| +\exemple|\IfSubStr[3]{\a1{\a1{\a1}\a2}\a3}{\a}{vrai}{faux}| +\exemple|\IfSubStr[4]{\a1{\a1{\a1}\a2}\a3}{\a}{vrai}{faux}| +\exemple|\exploregroups| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{2}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{34}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{{34}}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{\b}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{\bc}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{\bc5}{vrai}{faux}| +\exemple|\IfSubStr{1$2$\a{34}\bc5}{\bc{5}}{vrai}{faux}| +\exemple|\IfSubStr[1]{\a1{\a1{\a1}\a2}\a3}{\a}{vrai}{faux}| +\exemple|\IfSubStr[2]{\a1{\a1{\a1}\a2}\a3}{\a}{vrai}{faux}| +\exemple|\IfSubStr[3]{\a1{\a1{\a1}\a2}\a3}{\a}{vrai}{faux}| +\exemple|\IfSubStr[4]{\a1{\a1{\a1}\a2}\a3}{\a}{vrai}{faux}| + +\chapitre{Le test}{IfBeginWith} + +Les tests doivent donner des résultats identiques ci-dessous puisque \verb|\IfBeginWith| est indifférent au mode d'exploration des groupes !\smallskip + +\exemple|\noexploregroups| +\exemple|\IfBeginWith{{\a}123\b456}{\a}{vrai}{faux}| +\exemple|\IfBeginWith{{\a}123\b456}{{\a}}{vrai}{faux}| +\exemple|\IfBeginWith{{\a1}\b\c\d}{\a}{vrai}{faux}| +\exemple|\IfBeginWith{{1}23456}{12}{vrai}{faux}| +\exemple|\IfBeginWith{{1}23456}{1}{vrai}{faux}| +\exemple|\IfBeginWith{{1}23456}{{1}2}{vrai}{faux}| +\exemple|\exploregroups| +\exemple|\IfBeginWith{{\a}123\b456}{\a}{vrai}{faux}| +\exemple|\IfBeginWith{{\a}123\b456}{{\a}}{vrai}{faux}| +\exemple|\IfBeginWith{{\a1}\b\c\d}{\a}{vrai}{faux}| +\exemple|\IfBeginWith{{1}23456}{12}{vrai}{faux}| +\exemple|\IfBeginWith{{1}23456}{1}{vrai}{faux}| +\exemple|\IfBeginWith{{1}23456}{{1}2}{vrai}{faux}| + +\chapitre{Le test}{IfEndWith} + +Les tests doivent donner des résultats identiques ci-dessous puisque \verb|\IfEndWith| est indifférent au mode d'exploration des groupes !\smallskip + +\exemple|\noexploregroups| +\exemple|\IfEndWith{\a1\b2{\c3}}{\c3}{vrai}{faux}| +\exemple|\IfEndWith{\a1\b2{\c3}}{{\c3}}{vrai}{faux}| +\exemple|\IfEndWith{\a1\b2{\c3}}{3}{vrai}{faux}| +\exemple|\IfEndWith{12345{6}}{56}{vrai}{faux}| +\exemple|\IfEndWith{12345{6}}{6}{vrai}{faux}| +\exemple|\IfEndWith{12345{6}}{5{6}}{vrai}{faux}| +\exemple|\exploregroups| +\exemple|\IfEndWith{\a1\b2{\c3}}{\c3}{vrai}{faux}| +\exemple|\IfEndWith{\a1\b2{\c3}}{{\c3}}{vrai}{faux}| +\exemple|\IfEndWith{\a1\b2{\c3}}{3}{vrai}{faux}| +\exemple|\IfEndWith{12345{6}}{56}{vrai}{faux}| +\exemple|\IfEndWith{12345{6}}{6}{vrai}{faux}| +\exemple|\IfEndWith{12345{6}}{5{6}}{vrai}{faux}| + +\chapitre{Le test}{IfSubStrBefore} + +\exemple|\noexploregroups| +\exemple|\IfSubStrBefore[1,1]{\a1\a2\a3\b1\b2\b3}{2}{\b}{vrai}{faux}| +\exemple|\IfSubStrBefore[2,1]{\a1\a2\a3\b1\b2\b3}{2}{\b}{vrai}{faux}| +\exemple|\IfSubStrBefore[2,3]{\a1\a2\a3\b1\b2\b3}{\a}{\b}{vrai}{faux}| +\exemple|\IfSubStrBefore[1,1]{\a1{\a2\a3\b1}\b2\b3}{2}{\b}{vrai}{faux}| +\exemple|\IfSubStrBefore[1,2]{\a1{\a2\a3\b1}\b2\b3}{3}{\b}{vrai}{faux}| +\exemple|\exploregroups| +\exemple|\IfSubStrBefore[1,1]{\a1\a2\a3\b1\b2\b3}{2}{\b}{vrai}{faux}| +\exemple|\IfSubStrBefore[2,1]{\a1\a2\a3\b1\b2\b3}{2}{\b}{vrai}{faux}| +\exemple|\IfSubStrBefore[2,3]{\a1\a2\a3\b1\b2\b3}{\a}{\b}{vrai}{faux}| +\exemple|\IfSubStrBefore[1,1]{\a1{\a2\a3\b1}\b2\b3}{2}{\b}{vrai}{faux}| +\exemple|\IfSubStrBefore[1,2]{\a1{\a2\a3\b1}\b2\b3}{3}{\b}{vrai}{faux}| + +\chapitre{Le test}{IfStrBehind} + +\exemple|\noexploregroups| +\exemple|\IfSubStrBehind[2,1]{\a1\a2\a3\b1\b2\b3}{2}{\b}{vrai}{faux}| +\exemple|\IfSubStrBehind[3,1]{\a1\a2\a3\b1\b2\b3}{\a}{\b}{vrai}{faux}| +\exemple|\IfSubStrBehind[1,1]{\a1\a2\a3\b1\b2\b3}{\b}{3}{vrai}{faux}| +\exemple|\IfSubStrBehind[2,1]{\a1{\a2\a3\b1}\b2\b3}{\b}{3}{vrai}{faux}| +\exemple|\IfSubStrBehind[1,1]{\a1{\a2\a3\b1}\b2\b3}{3}{\b}{vrai}{faux}| +\exemple|\exploregroups| +\exemple|\IfSubStrBehind[2,1]{\a1\a2\a3\b1\b2\b3}{2}{\b}{vrai}{faux}| +\exemple|\IfSubStrBehind[3,1]{\a1\a2\a3\b1\b2\b3}{\a}{\b}{vrai}{faux}| +\exemple|\IfSubStrBehind[1,1]{\a1\a2\a3\b1\b2\b3}{\b}{3}{vrai}{faux}| +\exemple|\IfSubStrBehind[2,1]{\a1{\a2\a3\b1}\b2\b3}{\b}{3}{vrai}{faux}| +\exemple|\IfSubStrBehind[1,1]{\a1{\a2\a3\b1}\b2\b3}{3}{\b}{vrai}{faux}| + +\chapitre{Le test}{IfInteger} + +Dans les exemples ci-dessous, on examine la différence de comportement de la macro \verb|\IfInteger| selon les modes de développement des arguments.\smallskip + +\exemple|\def\nbA{-12}\def\nbB{498}| +\exemple|\def\nbAA{\nbA}\def\nbBB{\nbB}|\smallskip +\exemple|\fullexpandarg| +\exemple|\IfInteger{\nbA}{vrai}{faux}| +\exemple|\IfInteger{\nbA5\nbA}{vrai}{faux}| +\exemple|\IfInteger{\nbA6\nbB}{vrai}{faux}| +\exemple|\IfInteger{\nbAA7\nbBB}{vrai}{faux}|\smallskip +\exemple|\expandarg| +\exemple|\IfInteger{\nbA}{vrai}{faux}| +\exemple|\IfInteger{\nbA5\nbA}{vrai}{faux}| +\exemple|\IfInteger{\nbA6\nbB}{vrai}{faux}| +\exemple|\IfInteger{\nbAA7\nbBB}{vrai}{faux}|\smallskip +\exemple|\noexpandarg| +\exemple|\IfInteger{\nbA}{vrai}{faux}| +\exemple|\IfInteger{\nbA5\nbA}{vrai}{faux}| +\exemple|\IfInteger{\nbA6\nbB}{vrai}{faux}| +\exemple|\IfInteger{\nbAA7\nbBB}{vrai}{faux}| + +\chapitre{Le test}{IfDecimal} + +Dans les exemples ci-dessous, on examine la différence de comportement de la macro \verb|\IfDecimal| selon les modes de développement des arguments.\smallskip + +\exemple|\def\nbA{-12}\def\nbB{498}| +\exemple|\def\nbAA{\nbA}\def\nbBB{\nbB}|\smallskip +\exemple|\fullexpandarg| +\exemple|\IfDecimal{\nbA,\nbB}{vrai}{faux}| +\exemple|\IfDecimal{\nbAA.\nbB}{vrai}{faux}| +\exemple|\IfDecimal{\nbB,777}{vrai}{faux}| +\exemple|\IfDecimal{3\nbB,777}{vrai}{faux}| +\exemple|\IfDecimal{\nbB,\nbB}{vrai}{faux}|\smallskip +\exemple|\expandarg| +\exemple|\IfDecimal{\nbA,\nbB}{vrai}{faux}| +\exemple|\IfDecimal{\nbAA.\nbB}{vrai}{faux}| +\exemple|\IfDecimal{\nbB,777}{vrai}{faux}| +\exemple|\IfDecimal{3\nbB,777}{vrai}{faux}| +\exemple|\IfDecimal{\nbB,\nbB}{vrai}{faux}|\smallskip +\exemple|\noexpandarg| +\exemple|\IfDecimal{\nbA,\nbB}{vrai}{faux}| +\exemple|\IfDecimal{\nbAA.\nbB}{vrai}{faux}| +\exemple|\IfDecimal{\nbB,777}{vrai}{faux}| +\exemple|\IfDecimal{3\nbB,777}{vrai}{faux}| +\exemple|\IfDecimal{\nbB,\nbB}{vrai}{faux}| + +\chapitre{La macro}{StrBefore} + +\exemple|\noexploregroups| +\exemple|\StrBefore[2]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrBefore[3]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrBefore[4]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrBefore[5]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrBefore[6]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\exploregroups| +\exemple|\StrBefore[2]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrBefore[3]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrBefore[4]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrBefore[5]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrBefore[6]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}| + +\chapitre{La macro}{StrBehind} + +\exemple|\noexploregroups| +\exemple|\StrBehind[2]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrBehind[3]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrBehind[4]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrBehind[5]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrBehind[6]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\exploregroups| +\exemple|\StrBehind[2]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrBehind[3]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrBehind[4]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrBehind[5]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrBehind[6]{1\a2\a3{4\a5{6\a7}8\a}9\a0}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}| + +\chapitre{La macro}{StrBetween} + +La commande \verb|\StrBetween| opère en mode \verb|\noexploregroups|, quelque soit le mode d'exploration en cours.\smallskip + +\exemple|\StrBetween[1,3]{\a1\a2{3\a4}5\a6{7\a8}9\a0}{2}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrBetween[2,3]{\a1\a2{3\a4}5\a6{7\a8}9\a0}{\a}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrBetween[1,3]{\a1\a2{3\a4}5\a6{7\a8}9\a0}{3}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrBetween[2,4]{\a1\a2{3\a4}5\a6{7\a8}9\a0}{\a}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip + +\chapitre{La macro}{StrSubstitute} + +\exemple|\noexploregroups| +\exemple|\StrSubstitute{\a1{2\a{3\a}4\a}\a5\a}{\a}{\X}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrSubstitute[2]{\a1{2\a{3\a}4\a}\a5\a}{\a}{\X}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrSubstitute{\a1{2\a{3\a}4\a}\a5\a}{2}{X}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrSubstitute{\a1{2\a{3\a}4\a}\a5\a}{{3\a}}{XXX}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrSubstitute{\a1{2\a{3\a}4\a}\a5\a}{3\a}{XXX}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrSubstitute{a1{b1\bgroup c1}\egroup d1}{1}{X}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\exploregroups| +\exemple|\StrSubstitute{\a1{2\a{3\a}4\a}\a5\a}{\a}{\X}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrSubstitute[2]{\a1{2\a{3\a}4\a}\a5\a}{\a}{\X}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrSubstitute{\a1{2\a{3\a}4\a}\a5\a}{2}{X}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrSubstitute{\a1{2\a{3\a}4\a}\a5\a}{{3\a}}{XXX}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrSubstitute{\a1{2\a{3\a}4\a}\a5\a}{3\a}{XXX}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}| +\exemple|\StrSubstitute{a1{b1\bgroup c1}\egroup d1}{1}{X}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}| + +\chapitre{La macro}{StrDel} + +\exemple|\noexploregroups| +\exemple|\StrDel{\a1{2\a{3\a}4\a}\a5\a}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrDel[2]{\a1{2\a{3\a}4\a}\a5\a}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrDel{\a1{2\a{3\a}4\a}\a5\a}{2}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrDel{\a1{2\a{3\a}4\a}\a5\a}{{3\a}}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrDel{\a1{2\a{3\a}4\a}\a5\a}{3\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\exploregroups| +\exemple|\StrDel{\a1{2\a{3\a}4\a}\a5\a}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrDel[2]{\a1{2\a{3\a}4\a}\a5\a}{\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrDel{\a1{2\a{3\a}4\a}\a5\a}{2}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrDel{\a1{2\a{3\a}4\a}\a5\a}{{3\a}}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrDel{\a1{2\a{3\a}4\a}\a5\a}{3\a}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip + +\chapitre{La macro}{StrLen} + +\exemple|\noexploregroups| +\exemple|\StrLen{a1{a2}{\a\b}{a3}a4}| +\exemple|\exploregroups| +\exemple|\StrLen{a1{a2}{\a\b}{a3}a4}| + +\chapitre{la macro}{StrSplit} + +\exemple|\noexploregroups| +\exemple|\StrSplit{\a{\b{\c\d}\e}\f\g}{2}\xx\yy| +\exemple|\#\detokenize\expandafter{\xx}\#\quad\#\detokenize\expandafter{\yy}\#| +\exemple|\StrSplit{\a{\b{\c\d}\e}\f\g}{3}\xx\yy| +\exemple|\#\detokenize\expandafter{\xx}\#\quad\#\detokenize\expandafter{\yy}\#| +\exemple|\exploregroups| +\exemple|\StrSplit{\a{\b{\c\d}\e}\f\g}{2}\xx\yy| +\exemple|\#\detokenize\expandafter{\xx}\#\quad\#\detokenize\expandafter{\yy}\#| +\exemple|\StrSplit{\a{\b{\c\d}\e}\f\g}{3}\xx\yy| +\exemple|\#\detokenize\expandafter{\xx}\#\quad\#\detokenize\expandafter{\yy}\#| + +\chapitre{la macro}{StrMid} + +La commande \verb|\StrMid| opère en mode \verb|\noexploregroups|, quelque soit le mode d'exploration en cours.\smallskip + +\exemple|\StrMid{\a\b{\c\d}\e\f\g\h}{2}{6}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\StrMid{\a\b{\c\d}\e\f\g\h}{3}{4}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip + +\chapitre{La macro}{StrGobbleLeft} + +\exemple|\noexploregroups| +\exemple|\StrGobbleLeft{\a\b{\c\d\e}\f}{3}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\exploregroups| +\exemple|\StrGobbleLeft{\a\b{\c\d\e}\f}{3}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}| + +\chapitre{La macro}{StrGobbleRight} + +\exemple|\noexploregroups| +\exemple|\StrGobbleRight{\a\b{\c\d\e}\f}{3}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\exploregroups| +\exemple|\StrGobbleRight{\a\b{\c\d\e}\f}{3}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip + +\chapitre{La macro}{StrLeft} + +\exemple|\noexploregroups| +\exemple|\StrLeft{\a\b{\c\d\e}\f}{3}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\exploregroups| +\exemple|\StrLeft{\a\b{\c\d\e}\f}{3}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}| + +\chapitre{La macro}{StrRight} + +\exemple|\noexploregroups| +\exemple|\StrRight{\a\b{\c\d\e}\f}{3}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\exploregroups| +\exemple|\StrRight{\a\b{\c\d\e}\f}{3}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip + +\chapitre{la macro}{StrChar} + +\exemple|\noexploregroups| +\exemple|\StrChar{\a\b{\c\d\e}\f}{3}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\exploregroups| +\exemple|\StrChar{\a\b{\c\d\e}\f}{3}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip + +\chapitre{La macro}{StrCount} + +\exemple|\noexploregroups| +\exemple|\StrCount{\a1{\a2{\a3\a4}\a5}\a6\a7}{\a}| +\exemple|\StrCount{\a1{\a2{\a3\a4}\a5}\a6\a7}{2}| +\exemple|\exploregroups| +\exemple|\StrCount{\a1{\a2{\a3\a4}\a5}\a6\a7}{\a}| +\exemple|\StrCount{\a1{\a2{\a3\a4}\a5}\a6\a7}{2}| + +\chapitre{La macro}{StrPosition} + +\exemple|\noexploregroups| +\exemple|\StrPosition[3]{\a0\a1{\a{2\a3}4}\a5\a6}{\a}| +\exemple|\StrPosition[4]{\a0\a1{\a{3\a4}5}\a6\a7}{\a}| +\exemple|\StrPosition[1]{\a0\a1{\a{2\a3}4}\a5\a6}{2}| +\exemple|\exploregroups| +\exemple|\StrPosition[3]{\a0\a1{\a{2\a3}4}\a5\a6}{\a}| +\exemple|\StrPosition[4]{\a0\a1{\a{2\a3}4}\a5\a6}{\a}| +\exemple|\StrPosition[1]{\a0\a1{\a{2\a3}4}\a5\a6}{2}| + +\chapitre{La macro}{StrCompare} + +La commande \verb|\StrCompare| n'est pas affectée par le mode d'exploration.\smallskip + +\exemple|\comparenormal| +\exemple|\StrCompare{\a{\b1}\c2}{\a\b1\c2}| +\exemple|\StrCompare{{1\a2}3}{{1\a2}3}| +\exemple|\StrCompare{{1\a2}3}{1\a23}| +\exemple|\StrCompare{\a{\b\c}}{\a{\b\c}\d}| +\exemple|\StrCompare{{\a}\b}{\a\b}| +\exemple|\comparestrict| +\exemple|\StrCompare{\a{\b1}\c2}{\a\b1\c2}| +\exemple|\StrCompare{{1\a2}3}{{1\a2}3}| +\exemple|\StrCompare{{1\a2}3}{1\a23}| +\exemple|\StrCompare{\a{\b\c}}{\a{\b\c}\d}| +\exemple|\StrCompare{{\a}\b}{\a\b}| + +\chapitre{La macro}{StrRemoveBraces} + +\exemple|\noexploregroups| +\exemple|\StrRemoveBraces{\a1{\b2{\c3{\d4}}}\e5}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\exemple|\exploregroups| +\exemple|\StrRemoveBraces{\a1{\b2{\c3{\d4}}}\e5}[\cmd]| +\exemple|\detokenize\expandafter{\cmd}|\smallskip +\end{document}
\ No newline at end of file diff --git a/macros/generic/xstring/xstring-en.pdf b/macros/generic/xstring/xstring-en.pdf Binary files differnew file mode 100644 index 0000000000..d7581cd5e1 --- /dev/null +++ b/macros/generic/xstring/xstring-en.pdf diff --git a/macros/generic/xstring/xstring-en.tex b/macros/generic/xstring/xstring-en.tex new file mode 100644 index 0000000000..94c46f9d3f --- /dev/null +++ b/macros/generic/xstring/xstring-en.tex @@ -0,0 +1,2052 @@ +\documentclass[english,a4paper,10pt]{article} +\usepackage{fontspec} +\usepackage[bookmarks=true,bookmarksopen=true,colorlinks=true,hyperfootnotes=false,filecolor=black,linkcolor=blue,urlcolor=blue,pdfauthor={Christian Tellechea},pdftitle={xstring},pdfsubject={package for strings of tokens},pdfkeywords={xstring,latex,string},pdfcreator={LaTeX}]{hyperref} +\usepackage[margin=1.9cm]{geometry} +\usepackage{libertine} +\usepackage[scale=0.85]{noto-mono} +\usepackage[bottom]{footmisc} +\usepackage{amsmath,amssymb,amsfonts,color,eurosym,xspace,xstring,babel,listings} +\makeatletter +\definecolor{@xs@bckgcolor}{rgb}{0.9,1,1} +\definecolor{@xs@keywordsxstring}{rgb}{0,0,0.9} +\definecolor{@xs@keywordslatex}{rgb}{1,0,0} +\definecolor{@xs@arguments}{rgb}{0,0,0} +\definecolor{@xs@comments}{rgb}{0.5,0.5,0.5} +\definecolor{violet}{rgb}{0.66,0,0.66} +\lstset{% + language=[AlLaTeX]TeX,% + morekeywords={numexpr,detokenize},% + float=hbp,% + basicstyle=\small\ttfamily,% + identifierstyle=\color{@xs@arguments},% + keywordstyle=\color{@xs@keywordslatex},% + commentstyle=\itshape\color{@xs@comments},% + columns=fixed,% + tabsize=4,% + frame=single,% + extendedchars=true,% + showspaces=false,% + showstringspaces=false,% + numbers=left,% + numberstyle=\tiny\ttfamily,% + breaklines=true,% + breakindent=3em,% + backgroundcolor=\color{@xs@bckgcolor},% + breakautoindent=true,% + captionpos=t,% + xleftmargin=1em,% + xrightmargin=1em,% + lineskip=0pt,% + numbersep=1em,% + classoffset=1,% + morekeywords={% les macros et commandes de xstring + IfSubStr,IfSubStrBefore,IfSubStrBehind,% + IfBeginWith,IfEndWith,% + IfInteger,IfDecimal,integerpart,decimalpart,% + IfStrEq,IfEq,IfStrEqCase,IfEqCase,% + StrBefore,StrBehind,StrCut,StrBetween,% + StrSubstitute,StrDel,% + StrGobbleLeft,StrGobbleRight,StrRight,StrLeft,StrMid,StrChar,% + StrSplit,% + StrLen,StrCount,StrPosition,StrCompare,% + StrFindGroup,groupID,verbtocs,tokenize,scancs,StrExpand,StrRemoveBraces,% + exploregroups,noexploregroups,saveexploremode,restoreexploremode,% + comparenormal,comparestrict,savecomparemode,restorecomparemode,% + expandarg,noexpandarg,normalexpandarg,fullexpandarg,saveexpandmode,restoreexpandmode,% + expandingroups,noexpandingroups,% + setverbdelim},% + keywordstyle=\color{@xs@keywordsxstring},% + classoffset=0} +\makeatother + +\newcommand\guill[1]{"#1"} +\newcommand\argu[1]{$\langle$\textit{#1}$\rangle$} +\newcommand\ARGU[1]{\texttt{\{}\argu{#1}\texttt{\}}} +\newcommand\arguC[1]{\texttt{[}\argu{#1}\texttt{]}} +\newcommand\arguCC[2]{\texttt{[}\argu{#1}{,}\argu{#2}\texttt{]}} +\newcommand\texte[1]{\texttt{text}${}_{#1}$} +\newcommand\etoile{$\langle$\texttt{[*]}$\rangle$} +\newenvironment{Conditions}[1][1cm]% +{\begin{list}% + {$\vartriangleright$}% + {\setlength{\leftmargin}{#1} + \setlength{\itemsep}{0pt} + \setlength{\parsep}{0pt} + \setlength{\topsep}{2ptplus3ptminus2pt} + }}% +{\end{list}} +\renewcommand\th{${}^\text{th}$\xspace} +\newcommand\US{syntax unit\xspace} +\newcommand\USs{syntax units\xspace} +\newcommand\Xstring{\textsf{xstring}\xspace} +\newcommand\styleexemple{\small\baselineskip1.03\baselineskip\vskip\baselineskip\relax} +\newcommand\styleexercice{\footnotesize} +\newcommand\verbinline{\lstinline[basicstyle=\normalsize\ttfamily]} +\newcommand\colorise{\color{violet}} +\def\xstringenglishdateaux#1/#2/#3\nil{\number#3\relax\space \ifcase #2 \or January\or February\or March\or April\or May\or June\or July\or August\or September\or October\or November\or December\fi\space#1} +\edef\xstringenglishdate{\expandafter\xstringenglishdateaux\xstringdate\nil} +\begin{document} +\setlength{\parindent}{0pt} +\begin{titlepage} + \null\par\vfill + \begin{center} + \begin{minipage}{0.75\linewidth} + \begin{center} + \Huge\bfseries xstring\par\vspace{5pt} + \small v\xstringversion\par\vspace{25pt} + \normalsize User's manual + \end{center} + \end{minipage} + \end{center} + \vspace{1cm} + \begin{center} + Christian {\sc Tellechea}\par\small + \href{mailto:unbonpetit@netc.fr}{\nolinkurl{unbonpetit@netc.fr}}\par\vspace{5pt} + \xstringenglishdate + \end{center} + \vfill\hrulefill + \begin{center} + \begin{minipage}{0.85\linewidth} + \noindent + \hfill\textbf{\textit{Abstract}}\hfill{}\medskip\par + This package which requires $\varepsilon$-\TeX{}, provides macros manipulating strings of tokens. For a basic use, tokens can be alphanumeric chars, but the macros can also be useful for manipulating tokens, i.e. \TeX{} code. Main features are:\smallskip + + \parindent1.5em + \begin{itemize} + \item[$\triangleright$] tests: + \begin{itemize} + \item does a string contains at least $n$ times an another? + \item does a string starts (or ends) with another? etc. + \item is a string an integer? A decimal? + \item are 2 strings equal? + \end{itemize} + \item[$\triangleright$] extractions of substrings: + \begin{itemize} + \item what is on the left (or the right) of the $n$\th occurrence of a substring; + \item what is between the occurrences of 2 substrings; + \item substring between 2 positions; + \item serach of a group with its identifier. + \end{itemize} + \item[$\triangleright$] substitution of all, or the $n$ first occurrences of a substring for an other substring; + \item[$\triangleright$] calculation of numbers: + \begin{itemize} + \item length of a string; + \item position of the $n$\th occurrence of a substring; + \item how many times a string contains a substring? + \item comparison of 2 strings: position of the first difference; + \item identifier of the group in which a macro made a cut or a search. + \end{itemize} + \end{itemize} + \parindent0pt + \medskip + Other macros allow to use special characters forbiden in arguments (\verb|#| and \verb|%|) and manage differences between catcodes for advanced programming purposes. + \end{minipage} + \end{center} + \hrulefill\vfill{} +\end{titlepage} + +\tableofcontents + +This manual is a translation of the french manual. I apologize for my poor english but I did my best\footnote{Any email to tell me errors would be appreciated!}, and I hope that the following is comprehensible! +\section{Presentation} +\subsection{Description} +This extension\footnote{This extension does not require \LaTeX{} and can be compiled with Plain $\varepsilon$-\TeX{}.} provides macros and tests operating on "strings of tokens", as other programmation languages have. They provides the usual strings operations, such as: test if a string contains another, begins or ends with another, extractions of strings, calculation of the position of a substring, of the number of occurrences, etc.\medskip + +A "string of tokens" is a list of tokens of any nature, except that braces must be balanced and tokens catcode 6 and 14 (usualy \verb|%| et \verb|#|) are not allowed. Apart from this, any token is allowed (including \verbinline|\par|), in any order in the list, whatever be the resulting code.\medskip + +\Xstring reads the arguments of the macros \US by \US\footnote{In the \TeX{} code, a \US is a control sequence, a group between brace or a single char. See also page~\pageref{developpementarguments}.} : when \USs are \guill{simple} chars (catcode 10, 11 and 12), \Xstring logically read the argument char by char. \Xstring can also be used for programming purpose, including in arguments other tokens such as control sequences, braces and tokens with other catcodes. See chapter on reading mode and arguments expansion (page~\pageref{developpementarguments}), the command \verbinline|\verbtocs| (page~\pageref{verbtocs}) and the command \verbinline|\scancs| (page~\pageref{scancs}).\medskip + +As the arguments may contain any token, advanced users could have problems with catcodes leading to unexpected behaviours. These behaviours can be controlled: read page~\pageref{macrosetoilees}.\medskip + +Certainly, other packages exist (for example \href{http://mirror.ctan.org/tex-archive/macros/latex/contrib/substr/}{\nolinkurl{substr}} and \href{http://mirror.ctan.org/tex-archive/macros/latex/contrib/stringstrings/}{\nolinkurl{stringstrings}}), but as well as differences on features, they do not take into account occurrences so I found them too limited and difficult to use for programming. + +\subsection{Motivation} +I decided to write this package of macros because I have never really found tools in \LaTeX{} suiting my needs for strings. So, over the last few months, I wrote a few macros that I occasionally or regularly used. Their numbers have increased and become a little too dispersed in directories in my computer, so I have grouped them together in this package. + +Thus, writing a coherent set of macros forces more discipline and leads to necessary improvements, which took most of the time I spent writing this package. This package is my first one as I recently discoverd \LaTeX{}\footnote{In november 2007, I will be a noob for a long time\ldots}, so my main motivation was to make progress in programming with \TeX, and to tackle its specific methods. + +\section{The macros} +For a better understanding, let's see first the macros with the simpler arguments possible. No special catcode, no exotic token, no control sequence neither: only alphanumeric chars will be contained in the arguments.\medskip + +In the following chapters, all the macros will be presented this plan: +\begin{itemize} + \item the syntax\footnote{The optional star, the optional argument in last position will be explained later. See page~\pageref{macrosetoilees} for starred macros and page~\pageref{argumentoptionnel} for the optional argument.} and the value of optional arguments + \item a short description of the operation; + \item the operation under special conditions. For each conditions considered, the operation described has priority on that (those) below; + \item finally, several examples\footnote{For much more examples, see the test file.} are given. I tried to find them most easily comprehensible and most representative of the situations met in normal use. If a doubt is possible with spaces in the result, this one will be delimited by \guill{|}, given that an empty string is represented by \guill{||}. +\end{itemize}\smallskip + +\textbf{Important}: in the following, a \argu{number} can be an integer written with numeric chars, a counter, or the result of an arithmetic operation made with the command \verbinline|\numexpr|.\smallskip + +All the macros of \Xstring are displayed in {\makeatletter\color{@xs@keywordsxstring}red}. + +\subsection{The tests} +\subsubsection{\ttfamily\textbackslash IfSubStr} +\verbinline|\IfSubStr|\etoile\arguC{number}\ARGU{string}\ARGU{stringA}\ARGU{true}\ARGU{false} +\smallskip + +The value of the optional argument \argu{number} is 1 by default.\par\smallskip + +Tests if \argu{string} contains at least \argu{number} times \argu{stringA} and runs \argu{true} if so, and \argu{false} otherwise.\medskip + +\begin{Conditions} +\item If \argu{number}${}\leqslant0$, runs \argu{false}; +\item If \argu{string} or \argu{stringA} is empty, runs \argu{false}. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\IfSubStr{xstring}{tri}{true}{false} +\IfSubStr{xstring}{a}{true}{false} +\IfSubStr{a bc def }{c d}{true}{false} +\IfSubStr{a bc def }{cd}{true}{false} +\IfSubStr[2]{1a2a3a}{a}{true}{false} +\IfSubStr[3]{1a2a3a}{a}{true}{false} +\IfSubStr[4]{1a2a3a}{a}{true}{false} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \IfSubStr{xstring}{tri}{true}{false}\par + \IfSubStr{xstring}{a}{true}{false}\par + \IfSubStr{a bc def }{c d}{true}{false}\par + \IfSubStr{a bc def }{cd}{true}{false}\par + \IfSubStr[2]{1a2a3a}{a}{true}{false}\par + \IfSubStr[3]{1a2a3a}{a}{true}{false}\par + \IfSubStr[4]{1a2a3a}{a}{true}{false} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash IfSubStrBefore} +\verbinline|\IfSubStrBefore|\etoile\arguCC{number1}{number2}\ARGU{string}\ARGU{stringA}\ARGU{stringB}\ARGU{true}\ARGU{false} +\smallskip + +The values of the optional arguments \argu{number1} and \argu{number2} are 1 by default.\par\smallskip + +In \argu{string}, tests if the \argu{number1}\th occurrence of \argu{stringA} is on the left of the \argu{number2}\th occurrence of \argu{stringB}. Runs \argu{true} if so, and \argu{false} otherwise.\medskip + +\begin{Conditions} +\item If one of the occurrences is not found, it runs \argu{false}; +\item If one of the arguments \argu{string}, \argu{stringA} or \argu{stringB} is empty, runs \argu{false}; +\item If one of the optional arguments is negative or zero, runs \argu{false}. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\IfSubStrBefore{xstring}{st}{in}{true}{false} +\IfSubStrBefore{xstring}{ri}{s}{true}{false} +\IfSubStrBefore{LaTeX}{LaT}{TeX}{true}{false} +\IfSubStrBefore{a bc def }{ b}{ef}{true}{false} +\IfSubStrBefore{a bc def }{ab}{ef}{true}{false} +\IfSubStrBefore[2,1]{b1b2b3}{b}{2}{true}{false} +\IfSubStrBefore[3,1]{b1b2b3}{b}{2}{true}{false} +\IfSubStrBefore[2,2]{baobab}{a}{b}{true}{false} +\IfSubStrBefore[2,3]{baobab}{a}{b}{true}{false} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \IfSubStrBefore{xstring}{st}{in}{true}{false}\par + \IfSubStrBefore{xstring}{ri}{s}{true}{false}\par + \IfSubStrBefore{LaTeX}{LaT}{TeX}{true}{false}\par + \IfSubStrBefore{a bc def }{ b}{ef}{true}{false}\par + \IfSubStrBefore{a bc def }{ab}{ef}{true}{false}\par + \IfSubStrBefore[2,1]{b1b2b3}{b}{2}{true}{false}\par + \IfSubStrBefore[3,1]{b1b2b3}{b}{2}{true}{false}\par + \IfSubStrBefore[2,2]{baobab}{a}{b}{true}{false}\par + \IfSubStrBefore[2,3]{baobab}{a}{b}{true}{false} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash IfSubStrBehind} + +\verbinline|\IfSubStrBehind|\etoile\arguCC{number1}{number2}\ARGU{string}\ARGU{stringA}\ARGU{stringB}\ARGU{true}\ARGU{false} +\smallskip + +The values of the optional arguments \argu{number1} and \argu{number2} are 1 by default.\par\smallskip + +In \argu{string}, tests if the \argu{number1}\th occurrence of \argu{stringA} is on the right of the \argu{number2}\th occurrence of \argu{stringB}. Runs \argu{true} if so, and \argu{false} otherwise.\medskip + +\begin{Conditions} +\item If one of the occurrences is not found, it runs \argu{false}; +\item If one of the arguments \argu{string}, \argu{stringA} or \argu{stringB} is empty, runs \argu{false}; +\item If one of the optional arguments is negative or zero, runs \argu{false}. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\IfSubStrBehind{xstring}{ri}{xs}{true}{false} +\IfSubStrBehind{xstring}{s}{i}{true}{false} +\IfSubStrBehind{LaTeX}{TeX}{LaT}{true}{false} +\IfSubStrBehind{a bc def }{ d}{a}{true}{false} +\IfSubStrBehind{a bc def }{cd}{a b}{true}{false} +\IfSubStrBehind[2,1]{b1b2b3}{b}{2}{true}{false} +\IfSubStrBehind[3,1]{b1b2b3}{b}{2}{true}{false} +\IfSubStrBehind[2,2]{baobab}{b}{a}{true}{false} +\IfSubStrBehind[2,3]{baobab}{b}{a}{true}{false} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \IfSubStrBehind{xstring}{ri}{xs}{true}{false}\par + \IfSubStrBehind{xstring}{s}{i}{true}{false}\par + \IfSubStrBehind{LaTeX}{TeX}{LaT}{true}{false}\par + \IfSubStrBehind{a bc def }{ d}{a}{true}{false}\par + \IfSubStrBehind{a bc def }{cd}{a b}{true}{false}\par + \IfSubStrBehind[2,1]{b1b2b3}{b}{2}{true}{false}\par + \IfSubStrBehind[3,1]{b1b2b3}{b}{2}{true}{false}\par + \IfSubStrBehind[2,2]{baobab}{b}{a}{true}{false}\par + \IfSubStrBehind[2,3]{baobab}{b}{a}{true}{false} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash IfBeginWith} + +\verbinline|\IfBeginWith|\etoile\ARGU{string}\ARGU{stringA}\ARGU{true}\ARGU{false} +\smallskip + +Tests if \argu{string} begins with \argu{stringA}, and runs \argu{true} if so, and \argu{false} otherwise.\medskip + +\begin{Conditions} +\item If \argu{string} or \argu{stringA} is empty, runs \argu{false}. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\IfBeginWith{xstring}{xst}{true}{false} +\IfBeginWith{LaTeX}{a}{true}{false} +\IfBeginWith{a bc def }{a b}{true}{false} +\IfBeginWith{a bc def }{ab}{true}{false} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \IfBeginWith{xstring}{xst}{true}{false}\par + \IfBeginWith{LaTeX}{a}{true}{false}\par + \IfBeginWith{a bc def }{a b}{true}{false}\par + \IfBeginWith{a bc def }{ab}{true}{false} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash IfEndWith} + +\verbinline|\IfEndWith|\etoile\ARGU{string}\ARGU{stringA}\ARGU{Behind}\ARGU{false} +\smallskip + +Tests if \argu{string} ends with \argu{stringA}, and runs \argu{true} if so, and \argu{false} otherwise.\medskip + +\begin{Conditions} +\item If \argu{string} or \argu{stringA} is empty, runs \argu{false}. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\IfEndWith{xstring}{ring}{true}{false} +\IfEndWith{LaTeX}{a}{true}{false} +\IfEndWith{a bc def }{ef }{true}{false} +\IfEndWith{a bc def }{ef}{true}{false} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \IfEndWith{xstring}{ring}{true}{false}\par + \IfEndWith{LaTeX}{a}{true}{false}\par + \IfEndWith{a bc def }{ef }{true}{false}\par + \IfEndWith{a bc def }{ef}{true}{false} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash IfInteger} + +\verbinline|\IfInteger|\ARGU{number}\ARGU{true}\ARGU{false} +\smallskip + +Tests if \argu{number} is an integer (i.e whose decimal part is empty or 0), and runs \argu{true} if so, and \argu{false} otherwise.\smallskip + +If test is false because unexpected characters, the control sequence \verbinline|\@xs@afterinteger| and \verbinline|\afterinteger| both contain the illegal part of \argu{number}.\medskip + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\IfInteger{13}{true}{false} +\IfInteger{-219}{true}{false} +\IfInteger{+9}{true}{false} +\IfInteger{3.14}{true}{false} +\IfInteger{8.0}{true}{false} +\IfInteger{0}{true}{false} +\IfInteger{49a}{true}{false} +\IfInteger{+}{true}{false} +\IfInteger{-}{true}{false} +\IfInteger{0000}{true}{false} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \IfInteger{13}{true}{false}\par + \IfInteger{-219}{true}{false}\par + \IfInteger{+9}{true}{false}\par + \IfInteger{3.14}{true}{false}\par + \IfInteger{8.0}{true}{false}\par + \IfInteger{0}{true}{false}\par + \IfInteger{49a}{true}{false}\par + \IfInteger{+}{true}{false}\par + \IfInteger{-}{true}{false}\par + \IfInteger{0000}{true}{false} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash IfDecimal}\label{ifdecimal} + +\verbinline|\IfDecimal|\ARGU{number}\ARGU{true}\ARGU{false} +\smallskip + +Tests if \argu{number} is a decimal, and runs \argu{true} if so, and \argu{false} otherwise.\smallskip + +Counters \verbinline|\integerpart| and \verbinline|\decimalpart| contain the integer part and decimal part of \argu{number}. + +If test is false because unexpected characters, the control sequence \verbinline|\@xs@afterdecimal| and \verb|\afterdecimal| both contain the illegal part of \argu{number}, whereas if test is false because decimal part is empty after decimal separator, they contain "X".\medskip + +\begin{Conditions} + \item Decimal separator can be a dot or a comma; + \item If what is on the right of decimal separator (if it exists) is empty, the test is false; + \item If what is on the left of decimal separator (if it exists) is empty, the integer part is assumed to be 0; +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\IfDecimal{3.14}{true}{false} +\IfDecimal{3,14}{true}{false} +\IfDecimal{-0.5}{true}{false} +\IfDecimal{.7}{true}{false} +\IfDecimal{,9}{true}{false} +\IfDecimal{1..2}{true}{false} +\IfDecimal{+6}{true}{false} +\IfDecimal{-15}{true}{false} +\IfDecimal{1.}{true}{false} +\IfDecimal{2,}{true}{false} +\IfDecimal{.}{true}{false} +\IfDecimal{,}{true}{false} +\IfDecimal{+}{true}{false} +\IfDecimal{-}{true}{false} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \IfDecimal{3.14}{true}{false}\par + \IfDecimal{3,14}{true}{false}\par + \IfDecimal{-0.5}{true}{false}\par + \IfDecimal{.7}{true}{false}\par + \IfDecimal{,9}{true}{false}\par + \IfDecimal{1..2}{true}{false}\par + \IfDecimal{+6}{true}{false}\par + \IfDecimal{-15}{true}{false}\par + \IfDecimal{1.}{true}{false}\par + \IfDecimal{2,}{true}{false}\par + \IfDecimal{.}{true}{false}\par + \IfDecimal{,}{true}{false}\par + \IfDecimal{+}{true}{false}\par + \IfDecimal{-}{true}{false} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash IfStrEq} + +\verbinline|\IfStrEq|\etoile\ARGU{stringA}\ARGU{stringB}\ARGU{true}\ARGU{false} +\smallskip + +Tests if the strings \argu{stringA} and \argu{stringB} are equal, i.e. if they contain successively the same \USs in the same order. Runs \argu{true} if so, and \argu{false} otherwise.\smallskip + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\IfStrEq{a1b2c3}{a1b2c3}{true}{false} +\IfStrEq{abcdef}{abcd}{true}{false} +\IfStrEq{abc}{abcdef}{true}{false} +\IfStrEq{3,14}{3,14}{true}{false} +\IfStrEq{12.34}{12.340}{true}{false} +\IfStrEq{abc}{}{true}{false} +\IfStrEq{}{abc}{true}{false} +\IfStrEq{}{}{true}{false} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \IfStrEq{a1b2c3}{a1b2c3}{true}{false}\par + \IfStrEq{abcdef}{abcd}{true}{false}\par + \IfStrEq{abc}{abcdef}{true}{false}\par + \IfStrEq{3,14}{3,14}{true}{false}\par + \IfStrEq{12.34}{12.340}{true}{false}\par + \IfStrEq{abc}{}{true}{false}\par + \IfStrEq{}{abc}{true}{false}\par + \IfStrEq{}{}{true}{false} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash IfEq} + +\verbinline|\IfEq|\ARGU{stringA}\ARGU{stringB}\ARGU{true}\ARGU{false} +\smallskip + +Tests if the strings \argu{stringA} and \argu{stringB} are equal, \emph{except} if both \argu{stringA} and \argu{stringB} contain numbers in which case the macro tests if these numbers are equal. Runs \argu{true} if so, and \argu{false} otherwise.\smallskip + +\begin{Conditions} + \item The definition of \emph{number} is given with the macro \verbinline|\IfDecimal| (see page~\pageref{ifdecimal}), and thus : + \item \guill{+} signs are optional; + \item Decimal separator can be a dot or a comma. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\IfEq{a1b2c3}{a1b2c3}{true}{false} +\IfEq{abcdef}{ab}{true}{false} +\IfEq{ab}{abcdef}{true}{false} +\IfEq{12.34}{12,34}{true}{false} +\IfEq{+12.34}{12.340}{true}{false} +\IfEq{10}{+10}{true}{false} +\IfEq{-10}{10}{true}{false} +\IfEq{+0,5}{,5}{true}{false} +\IfEq{1.001}{1.01}{true}{false} +\IfEq{3*4+2}{14}{true}{false} +\IfEq{\number\numexpr3*4+2}{14}{true}{false} +\IfEq{0}{-0.0}{true}{false} +\IfEq{}{}{true}{false} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \IfEq{a1b2c3}{a1b2c3}{true}{false}\par + \IfEq{abcdef}{ab}{true}{false}\par + \IfEq{ab}{abcdef}{true}{false}\par + \IfEq{12.34}{12,34}{true}{false}\par + \IfEq{+12.34}{12.340}{true}{false}\par + \IfEq{10}{+10}{true}{false}\par + \IfEq{-10}{10}{true}{false}\par + \IfEq{+0,5}{,5}{true}{false}\par + \IfEq{1.001}{1.01}{true}{false}\par + \IfEq{3*4+2}{14}{true}{false}\par + \IfEq{\number\numexpr3*4+2}{14}{true}{false}\par + \IfEq{0}{-0.0}{true}{false}\par + \IfEq{}{}{true}{false} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash IfStrEqCase} + +\begin{minipage}{\textwidth} + \verbinline|\IfStrEqCase|\etoile\ARGU{string}\verb|{%|\par + \qquad\qquad\ARGU{string1}\ARGU{code1}\verb|%|\par + \qquad\qquad\ARGU{string2}\ARGU{code2}\verb|%|\par + \qquad\qquad\verb|etc...|\par + \qquad\qquad\ARGU{stringN}\ARGU{codeN}\verb|}|\arguC{other cases code} +\end{minipage} +\smallskip + +Tests successively if \argu{string} is equal to \argu{string1}, \argu{string2}, etc. Comparison is made with \verbinline|\IfStrEq| (see above). If the test number $i$ is positive (the \argu{string} matches \argu{string\;$i$}), the macro runs \argu{code\;$i$} and ends. If all tests fail, the macro runs the optional \argu{other cases code}, if present.\smallskip + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\IfStrEqCase{b}{{a}{AA}{b}{BB}{c}{CC}} +|\IfStrEqCase{abc}{{a}{AA}{b}{BB}{c}{CC}}| +\IfStrEqCase{c}{{a}{AA}{b}{BB}{c}{CC}}[other] +\IfStrEqCase{d}{{a}{AA}{b}{BB}{c}{CC}}[other] +\IfStrEqCase{+3}{{1}{one}{2}{two}{3}{three}}[other] +\IfStrEqCase{0.5}{{0}{zero}{.5}{half}{1}{one}}[other] +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \IfStrEqCase{b}{{a}{AA}{b}{BB}{c}{CC}}\par + |\IfStrEqCase{abc}{{a}{AA}{b}{BB}{c}{CC}}|\par + \IfStrEqCase{c}{{a}{AA}{b}{BB}{c}{CC}}[other]\par + \IfStrEqCase{d}{{a}{AA}{b}{BB}{c}{CC}}[other]\par + \IfStrEqCase{+3}{{1}{one}{2}{two}{3}{three}}[other]\par + \IfStrEqCase{0.5}{{0}{zero}{.5}{half}{1}{one}}[other] +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash IfEqCase} + +\begin{minipage}{\textwidth} + \verbinline|\IfEqCase|\etoile\ARGU{string}\verb|{%|\par + \qquad\qquad\ARGU{string1}\ARGU{code1}\verb|%|\par + \qquad\qquad\ARGU{string2}\ARGU{code2}\verb|%|\par + \qquad\qquad\verb|etc...|\par + \qquad\qquad\ARGU{stringN}\ARGU{codeN}\verb|}|\arguC{other cases code} +\end{minipage} +\smallskip + +Tests successively if \argu{string} is equal to \argu{string1}, \argu{string2}, etc. Comparison is made with \verbinline|\IEq| (see above). If the test number $i$ is positive (the \argu{string} matches \argu{string\;$i$}), the macro runs \argu{code\;$i$} and ends. If all tests fail, the macro runs the optional \argu{other cases code}, if present.\smallskip + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\IfEqCase{b}{{a}{AA}{b}{BB}{c}{CC}} +|\IfEqCase{abc}{{a}{AA}{b}{BB}{c}{CC}}| +\IfEqCase{c}{{a}{AA}{b}{BB}{c}{CC}}[other] +\IfEqCase{d}{{a}{AA}{b}{BB}{c}{CC}}[other] +\IfEqCase{+3}{{1}{one}{2}{two}{3}{three}}[other] +\IfEqCase{0.5}{{0}{zero}{.5}{half}{1}{one}}[other] +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \IfEqCase{b}{{a}{AA}{b}{BB}{c}{CC}}\par + |\IfEqCase{abc}{{a}{AA}{b}{BB}{c}{CC}}|\par + \IfEqCase{c}{{a}{AA}{b}{BB}{c}{CC}}[other]\par + \IfEqCase{d}{{a}{AA}{b}{BB}{c}{CC}}[other]\par + \IfEqCase{+3}{{1}{one}{2}{two}{3}{three}}[other]\par + \IfEqCase{0.5}{{0}{zero}{.5}{half}{1}{one}}[other] +\end{minipage}% + +\subsection{Extraction of substrings} +\subsubsection{\ttfamily\textbackslash StrBefore} + +\verbinline|\StrBefore|\etoile\arguC{number}\ARGU{string}\ARGU{stringA}\arguC{name} +\smallskip + +The value of the optional argument \argu{number} is 1 by default.\par\smallskip + +In \argu{string}, returns what is leftwards the \argu{number}\th occurrence of \argu{stringA}.\medskip + +\begin{Conditions} +\item If \argu{string} or \argu{stringA} is empty, an empty string is returned; +\item If \argu{number}${}<1$ then the macro behaves as if \argu{number}${}=1$; +\item If the occurrence is not found, an empty string is returned. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrBefore{xstring}{tri} +\StrBefore{LaTeX}{e} +|\StrBefore{LaTeX}{p}| +|\StrBefore{LaTeX}{L}| +|\StrBefore{a bc def }{def}| +|\StrBefore{a bc def }{cd}| +\StrBefore[1]{1b2b3}{b} +\StrBefore[2]{1b2b3}{b} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrBefore{xstring}{tri}\par + \StrBefore{LaTeX}{e}\par + |\StrBefore{LaTeX}{p}|\par + |\StrBefore{LaTeX}{L}|\par + |\StrBefore{a bc def }{def}|\par + |\StrBefore{a bc def }{cd}|\par + \StrBefore[1]{1b2b3}{b}\par + \StrBefore[2]{1b2b3}{b} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrBehind} + +\verbinline|\StrBehind|\etoile\arguC{number}\ARGU{string}\ARGU{stringA}\arguC{name} +\smallskip + +The value of the optional argument \argu{number} is 1 by default.\par\smallskip + +In \argu{string}, returns what is rightwards the \argu{number}\th occurrence of \argu{stringA}.\medskip + +\begin{Conditions} +\item If \argu{string} or \argu{stringA} is empty, an empty string is returned; +\item If \argu{number}${}<1$ then the macro behaves as if \argu{number}${}=1$; +\item If the occurrence is not found, an empty string is returned. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrBehind{xstring}{tri} +\StrBehind{LaTeX}{e} +|\StrBehind{LaTeX}{p}| +|\StrBehind{LaTeX}{X}| +|\StrBehind{a bc def }{bc}| +|\StrBehind{a bc def }{cd}| +\StrBehind[1]{1b2b3}{b} +\StrBehind[2]{1b2b3}{b} +|\StrBehind[3]{1b2b3}{b}| +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrBehind{xstring}{tri}\par + \StrBehind{LaTeX}{e}\par + |\StrBehind{LaTeX}{p}|\par + |\StrBehind{LaTeX}{X}|\par + |\StrBehind{a bc def }{bc}|\par + |\StrBehind{a bc def }{cd}|\par + \StrBehind[1]{1b2b3}{b}\par + \StrBehind[2]{1b2b3}{b}\par + |\StrBehind[3]{1b2b3}{b}| +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrCut} +Here is the syntax of this macro:\par\nobreak\smallskip +\verbinline|\StrCut|\etoile\arguC{nunber}\ARGU{string}\ARGU{stringA}\ARGU{macroA}\ARGU{macroB} +\smallskip + +The optional argument \argu{number} is 1 by default.\par\nobreak\smallskip +The \argu{string} is cut in two parts at the occurrence \arguC{number} of \ARGU{stringA}. The left part is stored in the control sequence \argu{macroA} and the right part in \argu{macroB}. + +Since this macro returns \emph{two strings}, it does \emph{not} display anything. Consequently, it does not provide the optional argument in last position.\medskip + +\begin{Conditions} + \item If \argu{string} or \argu{stringA} is empty, \argu{macroA} and \argu{macroB} are empty; + \item If \argu{number}${}<1$, the macro behaves as if \argu{number}${}=1$; + \item If the occurrence is not found, \argu{macroA} receives the whole \argu{string} while \argu{macroB} is empty. +\end{Conditions} +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrCut{abracadabra}{a}\csA\csB |\csA|\csB|\par +\StrCut[2]{abracadabra}{a}\csA\csB |\csA|\csB|\par +\StrCut[3]{abracadabra}{a}\csA\csB |\csA|\csB|\par +\StrCut[4]{abracadabra}{a}\csA\csB |\csA|\csB|\par +\StrCut[5]{abracadabra}{a}\csA\csB |\csA|\csB|\par +\StrCut[6]{abracadabra}{a}\csA\csB |\csA|\csB|\par +\StrCut[-4]{abracadabra}{a}\csA\csB |\csA|\csB|\par +\StrCut{abracadabra}{brac}\csA\csB |\csA|\csB|\par +\StrCut{abracadabra}{foo}\csA\csB |\csA|\csB|\par +\StrCut{abracadabra}{}\csA\csB |\csA|\csB| +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \def\seprouge{{\color{red}|}} + \styleexemple + \StrCut{abracadabra}{a}\csA\csB |\csA\seprouge\csB|\par + \StrCut[2]{abracadabra}{a}\csA\csB |\csA\seprouge\csB|\par + \StrCut[3]{abracadabra}{a}\csA\csB |\csA\seprouge\csB|\par + \StrCut[4]{abracadabra}{a}\csA\csB |\csA\seprouge\csB|\par + \StrCut[5]{abracadabra}{a}\csA\csB |\csA\seprouge\csB|\par + \StrCut[6]{abracadabra}{a}\csA\csB |\csA\seprouge\csB|\par + \StrCut[-4]{abracadabra}{a}\csA\csB |\csA\seprouge\csB|\par + \StrCut{abracadabra}{brac}\csA\csB |\csA\seprouge\csB|\par + \StrCut{abracadabra}{foo}\csA\csB |\csA\seprouge\csB|\par + \StrCut{abracadabra}{}\csA\csB |\csA\seprouge\csB| +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrBetween} + +\verbinline|\StrBetween|\etoile\arguCC{number1}{number2}\ARGU{string}\ARGU{stringA}\ARGU{stringB}\arguC{name} +\smallskip + +The values of the optional arguments \argu{number1} and \argu{number2} are 1 by default.\par\smallskip + +In \argu{string}, returns the substring between\footnote{In a strict sense, i.e. \emph{without} the strings \argu{stringA} and \argu{stringB}} the \argu{number1}\th occurrence of \argu{stringA} and \argu{number2}\th occurrence of \argu{stringB}.\medskip + +\begin{Conditions} +\item If the occurrences are not in this order ---~\argu{stringA} \emph{followed by} \argu{stringB}~--- in \argu{string}, an empty string is returned; +\item If one of the 2 occurrences doesn't exist in \argu{string}, an empty string is returned; +\item If one of the optional arguments \argu{number1} ou \argu{number2} is negative or zero, an empty string is returned. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrBetween{xstring}{xs}{ng} +|\StrBetween{xstring}{i}{n}| +|\StrBetween{xstring}{a}{tring}| +|\StrBetween{a bc def }{a}{d}| +|\StrBetween{a bc def }{a }{f}| +\StrBetween{a1b1a2b2a3b3}{a}{b} +\StrBetween[2,3]{a1b1a2b2a3b3}{a}{b} +\StrBetween[1,3]{a1b1a2b2a3b3}{a}{b} +|\StrBetween[3,1]{a1b1a2b2a3b3}{a}{b}| +\StrBetween[3,2]{abracadabra}{a}{bra} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrBetween{xstring}{xs}{ng}\par + |\StrBetween{xstring}{i}{n}|\par + |\StrBetween{xstring}{a}{tring}|\par + |\StrBetween{a bc def }{a}{d}|\par + |\StrBetween{a bc def }{a }{f}|\par + \StrBetween{a1b1a2b2a3b3}{a}{b}\par + \StrBetween[2,3]{a1b1a2b2a3b3}{a}{b}\par + \StrBetween[1,3]{a1b1a2b2a3b3}{a}{b}\par + |\StrBetween[3,1]{a1b1a2b2a3b3}{a}{b}|\par + \StrBetween[3,2]{abracadabra}{a}{bra}\par +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrSubstitute} + +\verbinline|\StrSubstitute|\arguC{number}\ARGU{string}\ARGU{stringA}\ARGU{stringB}\arguC{name} +\smallskip + +The value of the optional argument \argu{number} is 0 by default.\par\smallskip + +In \argu{string}, substitute the \argu{number} first occurrences of \argu{stringA} for \argu{stringB}, except if \argu{number}${}=0$ in which case \emph{all} the occurrences are substituted. + +\begin{Conditions} +\item If \argu{string} is empty, an empty string is returned; +\item If \argu{stringA} is empty or doesn't exist in \argu{string}, the macro is ineffective; +\item If \argu{number} is greater than the number of occurrences of \argu{stringA}, then all the occurrences are substituted; +\item If \argu{number}${}<0$ the macro behaves as if \argu{number}${}=0$; +\item If \argu{stringB} is empty, the occurrences of \argu{stringA}, if they exist, are deleted. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrSubstitute{xstring}{i}{a} +\StrSubstitute{abracadabra}{a}{o} +\StrSubstitute{abracadabra}{br}{TeX} +\StrSubstitute{LaTeX}{m}{n} +\StrSubstitute{a bc def }{ }{M} +\StrSubstitute{a bc def }{ab}{AB} +\StrSubstitute[1]{a1a2a3}{a}{B} +\StrSubstitute[2]{a1a2a3}{a}{B} +\StrSubstitute[3]{a1a2a3}{a}{B} +\StrSubstitute[4]{a1a2a3}{a}{B} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrSubstitute{xstring}{i}{a}\par + \StrSubstitute{abracadabra}{a}{o}\par + \StrSubstitute{abracadabra}{br}{TeX}\par + \StrSubstitute{LaTeX}{m}{n}\par + \StrSubstitute{a bc def }{ }{M}\par + \StrSubstitute{a bc def }{ab}{AB}\par + \StrSubstitute[1]{a1a2a3}{a}{B}\par + \StrSubstitute[2]{a1a2a3}{a}{B}\par + \StrSubstitute[3]{a1a2a3}{a}{B}\par + \StrSubstitute[4]{a1a2a3}{a}{B} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrDel} + +\verbinline|\StrDel|\etoile\arguC{number}\ARGU{string}\ARGU{stringA}\arguC{name} +\smallskip + +The value of the optional argument \argu{number} is 0 by default.\par\smallskip + +Delete the \argu{number} first occurrences of \argu{stringA} in \argu{string}, except if \argu{number}${}=0$ in which case \emph{all} the occurrences are deleted.\medskip + +\begin{Conditions} +\item If \argu{string} is empty, an empty string is returned; +\item If \argu{stringA} is empty or doesn't exist in \argu{string}, the macro is ineffective; +\item If \argu{number} greater then the number of occurrences of \argu{stringA}, then all the occurrences are deleted; +\item If \argu{number}${}<0$ the macro behaves as if \argu{number}${}=0$; +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrDel{abracadabra}{a} +\StrDel[1]{abracadabra}{a} +\StrDel[4]{abracadabra}{a} +\StrDel[9]{abracadabra}{a} +\StrDel{a bc def }{ } +|\StrDel{a bc def }{def}| +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrDel{abracadabra}{a}\par + \StrDel[1]{abracadabra}{a}\par + \StrDel[4]{abracadabra}{a}\par + \StrDel[9]{abracadabra}{a}\par + \StrDel{a bc def }{ }\par + |\StrDel{a bc def }{def}| +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrGobbleLeft} +\verbinline|\StrGobbleLeft|\ARGU{string}\ARGU{number}\arguC{name} +\smallskip + +In \argu{string}, delete the \argu{number} first characters on the left.\medskip + +\begin{Conditions} +\item If \argu{string} is empty, an empty string is returned; +\item If \argu{number}${}\leqslant0$, no character is deleted; +\item If \argu{number}${}\geqslant{}$\argu{lengthString}, all the characters are deleted. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrGobbleLeft{xstring}{2} +|\StrGobbleLeft{xstring}{9}| +\StrGobbleLeft{LaTeX}{4} +\StrGobbleLeft{LaTeX}{-2} +|\StrGobbleLeft{a bc def }{4}| +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrGobbleLeft{xstring}{2}\par + |\StrGobbleLeft{xstring}{9}|\par + \StrGobbleLeft{LaTeX}{4}\par + \StrGobbleLeft{LaTeX}{-2}\par + |\StrGobbleLeft{a bc def }{4}| +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrLeft} + +\verbinline|\StrLeft|\ARGU{string}\ARGU{number}\arguC{name} +\smallskip + +In \argu{string}, returns the \argu{number} first characters on the left.\medskip + +\begin{Conditions} +\item If \argu{string} is empty, an empty string is returned; +\item If \argu{number}${}\leqslant0$, no character is returned; +\item If \argu{number}${}\geqslant{}$\argu{lengthString}, all the characters are returned. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrLeft{xstring}{2} +\StrLeft{xstring}{9} +\StrLeft{LaTeX}{4} +|\StrLeft{LaTeX}{-2}| +|\StrLeft{a bc def }{5}| +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrLeft{xstring}{2}\par + \StrLeft{xstring}{9}\par + \StrLeft{LaTeX}{4}\par + |\StrLeft{LaTeX}{-2}|\par + |\StrLeft{a bc def }{5}| +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrGobbleRight} + +\verbinline|\StrGobbleRight|\ARGU{string}\ARGU{number}\arguC{name} +\smallskip + +In \argu{string}, delete the \argu{number} last characters on the right.\medskip + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrGobbleRight{xstring}{2} +|\StrGobbleRight{xstring}{9}| +\StrGobbleRight{LaTeX}{4} +|\StrGobbleRight{LaTeX}{-2}| +|\StrGobbleRight{a bc def }{4}| +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrGobbleRight{xstring}{2}\par + |\StrGobbleRight{xstring}{9}|\par + \StrGobbleRight{LaTeX}{4}\par + |\StrGobbleRight{LaTeX}{-2}|\par + |\StrGobbleRight{a bc def }{4}| +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrRight} + +\verbinline|\StrRight|\ARGU{string}\ARGU{number}\arguC{name} +\smallskip + +In \argu{string}, returns the \argu{number} last characters on the right.\medskip + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrRight{xstring}{2} +\StrRight{xstring}{9} +\StrRight{LaTeX}{4} +|\StrRight{LaTeX}{-2}| +\StrRight{a bc def }{5} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrRight{xstring}{2}\par + \StrRight{xstring}{9}\par + \StrRight{LaTeX}{4}\par + |\StrRight{LaTeX}{-2}|\par + \StrRight{a bc def }{5} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrChar} + +\verbinline|\StrChar|\etoile\ARGU{string}\ARGU{number}\arguC{name} +\smallskip + +Returns the \US at the position \argu{number} in \argu{string}.\medskip + +\begin{Conditions} +\item If \argu{string} is empty, no caracter is returned; +\item If \argu{number}${}\leqslant0$ or if \argu{number}${}>{}$\argu{lengthString}, no character is returned. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrChar{xstring}{4} +|\StrChar{xstring}{9}| +|\StrChar{xstring}{-5}| +\StrChar{a bc def }{6} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrChar{xstring}{4}\par + |\StrChar{xstring}{9}|\par + |\StrChar{xstring}{-5}|\par + \StrChar{a bc def }{6} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrMid} + +\verbinline|\StrMid|\ARGU{string}\ARGU{numberA}\ARGU{numberB}\arguC{name} +\smallskip + +In \argu{string}, returns the substring between\footnote{In the broad sense, i.e. that the strings characters of the \guill{border} are returned.} the positions \argu{numberA} and \argu{numberB}.\medskip + +\begin{Conditions} +\item If \argu{string} is empty, an empty string is returned; +\item If \argu{numberA}${}>{}$\argu{numberB}, an empty string is returned; +\item If \argu{numberA}${}<1$ and \argu{numberB}${}<1$ an empty string is returned; +\item If \argu{numberA}${}>{}$\argu{lengthString} et \argu{numberB}${}>{}$\argu{lengthString}, an empty string is returned; +\item If \argu{numberA}${}<1$, the macro behaves as if \argu{numberA}${}=1$; +\item If \argu{numberB}${}>{}$\argu{lengthString}, the macro behaves as if \argu{numberB}${}={}$\argu{lengthString}. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrMid{xstring}{2}{5} +\StrMid{xstring}{-4}{2} +|\StrMid{xstring}{5}{1}| +\StrMid{xstring}{6}{15} +\StrMid{xstring}{3}{3} +|\StrMid{a bc def }{2}{7}| +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrMid{xstring}{2}{5}\par + \StrMid{xstring}{-4}{2}\par + |\StrMid{xstring}{5}{1}|\par + \StrMid{xstring}{6}{15}\par + \StrMid{xstring}{3}{3}\par + |\StrMid{a bc def }{2}{7}| +\end{minipage}% + +\subsection{Macros returning a number} +\subsubsection{\ttfamily\textbackslash StrLen} + +\verbinline|\StrLen|\ARGU{string}\arguC{name} +\smallskip + +Return the length of \argu{string}. + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrLen{xstring} +\StrLen{A} +\StrLen{a bc def } +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrLen{xstring}\par + \StrLen{A}\par + \StrLen{a bc def } +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrCount} + +\verbinline|\StrCount|\ARGU{string}\ARGU{stringA}\arguC{name} +\smallskip + +Counts how many times \argu{stringA} is contained in \argu{string}.\par\medskip + +\begin{Conditions} +\item If one at least of the arguments \argu{string} or \argu{stringA} is empty, the macro return 0. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrCount{abracadabra}{a} +\StrCount{abracadabra}{bra} +\StrCount{abracadabra}{tic} +\StrCount{aaaaaa}{aa} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrCount{abracadabra}{a}\par + \StrCount{abracadabra}{bra}\par + \StrCount{abracadabra}{tic}\par + \StrCount{aaaaaa}{aa} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrPosition} + +\verbinline|\StrPosition|\arguC{number}\ARGU{string}\ARGU{stringA}\arguC{name} +\smallskip + +The value of the optional argument \argu{number} is 1 by default.\par\smallskip + +In \argu{string}, returns the position of the \argu{number}\th occurrence of \argu{stringA}.\medskip + +\begin{Conditions} +\item If \argu{number} is greater than the number of occurrences of \argu{stringA}, then the macro returns 0; +\item If \argu{string} doesn't contain \argu{stringA}, then the macro returns 0. +\end{Conditions} +\medskip + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrPosition{xstring}{ring} +\StrPosition[4]{abracadabra}{a} +\StrPosition[2]{abracadabra}{bra} +\StrPosition[9]{abracadabra}{a} +\StrPosition{abracadabra}{z} +\StrPosition{a bc def }{d} +\StrPosition[3]{aaaaaa}{aa} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrPosition{xstring}{ring}\par + \StrPosition[4]{abracadabra}{a}\par + \StrPosition[2]{abracadabra}{bra}\par + \StrPosition[9]{abracadabra}{a}\par + \StrPosition{abracadabra}{z}\par + \StrPosition{a bc def }{d}\par + \StrPosition[3]{aaaaaa}{aa} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrCompare} +\verbinline|\StrCompare|\etoile\ARGU{stringA}\ARGU{stringB}\arguC{name} +\smallskip + +This macro has 2 tolerances: the "normal" tolerance, used by default, and the "strict" tolerance. +\begin{itemize} + \item The normal tolerance is activated with \verbinline|\comparenormal|.\par + The macro compares characters from left to right in \argu{stringA} and \argu{stringB} until a difference appears or the end of the shortest string is reached. The position of the first difference is returned and if no difference is found, the macro return 0. + \item The strict tolerance is activated with \verbinline|\comparestrict|.\par + The macro compares the 2 strings. If they are equal, it returns 0. If not, the position of the first difference is returned. +\end{itemize} +\medskip + +It is possible to save the comparison mode with \verbinline|\savecomparemode|, then modify this comparison mode and come back to the situation when it was saved with \verbinline|\restorecomparemode|.\medskip + +Examples with the normal tolerance:\par\nobreak +\begin{minipage}[t]{0.65\linewidth} +\comparenormal +\begin{lstlisting} +\StrCompare{abcd}{abcd} +\StrCompare{abcd}{abc} +\StrCompare{abc}{abcd} +\StrCompare{a b c}{abc} +\StrCompare{aaa}{baaa} +\StrCompare{abc}{xyz} +\StrCompare{123456}{123457} +\StrCompare{abc}{} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \comparenormal + \StrCompare{abcd}{abcd}\par + \StrCompare{abcd}{abc}\par + \StrCompare{abc}{abcd}\par + \StrCompare{a b c}{abc}\par + \StrCompare{aaa}{baaa}\par + \StrCompare{abc}{xyz}\par + \StrCompare{123456}{123457}\par + \StrCompare{abc}{} +\end{minipage}% +\medskip + +Examples with the strict tolerance:\par\nobreak +\begin{minipage}[t]{0.65\linewidth} +\comparestrict +\begin{lstlisting} +\StrCompare{abcd}{abcd} +\StrCompare{abcd}{abc} +\StrCompare{abc}{abcd} +\StrCompare{a b c}{abc} +\StrCompare{aaa}{baaa} +\StrCompare{abc}{xyz} +\StrCompare{123456}{123457} +\StrCompare{abc}{} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \comparestrict + \StrCompare{abcd}{abcd}\par + \StrCompare{abcd}{abc}\par + \StrCompare{abc}{abcd}\par + \StrCompare{a b c}{abc}\par + \StrCompare{aaa}{baaa}\par + \StrCompare{abc}{xyz}\par + \StrCompare{123456}{123457}\par + \StrCompare{abc}{} +\end{minipage}% + +\section{Operating modes} +\subsection{Expansion of arguments} +\label{devarg} +\subsubsection{The commands {\ttfamily \textbackslash fullexpandarg}, {\ttfamily \textbackslash expandarg} and {\ttfamily \textbackslash noexpandarg}} +The command \verbinline|\fullexpandarg| is called by default, so all the arguments are fully expanded (an \verbinline|\edef| is used) before the the macro works on them. In most of the cases, this expansion mode avoids chains of \verbinline|\expandafter| and allows lighter code. + +Of course, the expansion of argument can be canceled to find back the usual behaviour of \TeX{} with the commands \verbinline|\noexpandarg| or \verbinline|\normalexpandarg|.\medskip + +Another expansion mode can be called with \verbinline|\expandarg|. In this case, the \textbf{first token} of each argument is expanded \emph{one time} while all other tokens are left unchanged (if you want the expansion of all tokens one time, you should call the macro \verbinline|\StrExpand|, see page~\pageref{scancs}).\medskip + +The commands \verbinline|\fullexpandarg|, \verbinline|\noexpandarg|, \verbinline|\normalexpandarg| and \verbinline|\expandarg| can be called at any moment in the code; they behave as "switches" and they can be locally used in a group.\medskip + +It is possible to save the expansion mode with \verbinline|\saveexpandmode|, then modify this expansion mode and come back to the situation when it was saved with \verbinline|\restoreexpandmode|.\medskip + +In the following list, for every macro of the previous chapter, the arguments colored in \textcolor{violet}{purple} will possibly be expanded, according to the expansion mode:\smallskip + +\parindent3em +\begin{itemize} + \item\verb|\IfSubStr|\etoile{\colorise\arguC{number}\ARGU{string}\ARGU{stringA}}\ARGU{true}\ARGU{false} + \item\verb|\IfSubStrBefore|\etoile{\colorise\arguCC{number1}{number2}\ARGU{string}\ARGU{stringA}\ARGU{stringB}}\ARGU{true}\ARGU{false} + \item\verb|\IfSubStrBehind|\etoile{\colorise\arguCC{number1}{number2}\ARGU{string}\ARGU{stringA}\ARGU{stringB}}\ARGU{true}\ARGU{false} + \item\verb|\IfBeginWith|\etoile{\colorise\ARGU{string}\ARGU{stringA}}\ARGU{true}\ARGU{false} + \item\verb|\IfEndWith|\etoile{\colorise\ARGU{string}\ARGU{stringA}}\ARGU{true}\ARGU{false} + \item\verb|\IfInteger|{\colorise\ARGU{number}}\ARGU{true}\ARGU{false} + \item\verb|\IfDecimal|{\colorise\ARGU{number}}\ARGU{true}\ARGU{false} + \item\verb|\IfStrEq|\etoile{\colorise\ARGU{stringA}\ARGU{stringB}}\ARGU{true}\ARGU{false} + \item\verb|\IfEq|\etoile{\colorise\ARGU{stringA}\ARGU{stringB}}\ARGU{true}\ARGU{false} + \item\verb|\IfStrEqCase|\etoile{\colorise\ARGU{string}\texttt{\color{black}\{}\colorise\ARGU{string1}}\ARGU{code1}\par + \setbox0=\hbox{{\ttfamily\string\IfStrEqCase}\etoile\ARGU{string}{\ttfamily\{}} + \hskip\wd0{\colorise\ARGU{string2}}\ARGU{code2}\par + \hskip\wd0\ \ldots\par + \hskip\wd0{\colorise\ARGU{string $n$}}\ARGU{code $n$}\verb|}|\arguC{other cases code} + \item\verb|\IfEqCase|\etoile{\colorise\ARGU{string}\texttt{\color{black}\{}\colorise\ARGU{string1}}\ARGU{code1}\par + \setbox0=\hbox{{\ttfamily\string\IfEqCase}\etoile\ARGU{string}{\ttfamily\{}} + \hskip\wd0{\colorise\ARGU{string2}}\ARGU{code2}\par + \hskip\wd0\ \ldots\par + \hskip\wd0{\colorise\ARGU{string $n$}}\ARGU{code $n$}\verb|}|\arguC{other cases code} + \item\verb|\StrBefore|\etoile{\colorise\arguC{number}\ARGU{string}\ARGU{stringA}}\arguC{name} + \item\verb|\StrBehind|\etoile{\colorise\arguC{number}\ARGU{string}\ARGU{stringA}}\arguC{name} + \item\verb|\StrBetween|\etoile{\colorise\arguCC{number1}{number2}\ARGU{string}\ARGU{stringA}\ARGU{stringB}}\arguC{name} + \item\verb|\StrSubstitute|{\colorise\arguC{number}\ARGU{string}\ARGU{stringA}\ARGU{stringB}}\arguC{name} + \item\verb|\StrDel|{\colorise\arguC{number}\ARGU{string}\ARGU{stringA}}\arguC{name} + \item\verb|\StrSplit|{\colorise\ARGU{string}\ARGU{number}}\ARGU{stringA}\ARGU{stringB}\qquad{\small(see macro \verb|StrSplit| page~\pageref{StrSplit})} + \item\verb|\StrGobbleLeft|{\colorise\ARGU{string}\ARGU{number}}\arguC{name} + \item\verb|\StrLeft|{\colorise\ARGU{string}\ARGU{number}}\arguC{name} + \item\verb|\StrGobbleRight|{\colorise\ARGU{string}\ARGU{number}}\arguC{name} + \item\verb|\StrRight|{\colorise\ARGU{string}\ARGU{number}}\arguC{name} + \item\verb|\StrChar|{\colorise\ARGU{string}\ARGU{number}}\arguC{name} + \item\verb|\StrMid|{\colorise\ARGU{string}\ARGU{number1}\ARGU{number2}}\arguC{name} + \item\verb|\StrLen|{\colorise\ARGU{string}}\arguC{name} + \item\verb|\StrCount|{\colorise\ARGU{string}\ARGU{stringA}}\arguC{name} + \item\verb|\StrPosition|{\colorise\arguC{number}\ARGU{string}\ARGU{stringA}}\arguC{name} + \item\verb|\StrCompare|{\colorise\ARGU{stringA}\ARGU{stringB}}\arguC{name} +\end{itemize} +\parindent0pt + +\subsubsection{Chars and tokens allowed in arguments} +First of all, whatever be the current expansion mode, \textbf{tokens with catcode 6 and 14 (usually {\ttfamily\#} and {\ttfamily\%}) are forbidden in all the arguments}\footnote{Maybe, the token {\ttfamily\#} will be allowed in a future version.}.\bigskip + +When full expansion mode is activated with \verbinline|\fullexpandarg|, arguments are expanded with an \verbinline|\edef| before they are read by the macro. Consequently, are allowed in arguments: +\parindent3em +\begin{itemize} + \item letters (uppercase or lowercase, accented\footnote{For a reliable operation with accented letters, the \texttt{\string\fontenc} package with option \texttt{[T1]} and \texttt{\string\inputenc} with appropriated option must be loaded} or not), figures, spaces, and any other character with a catcode of 10, 11 ou 12 (punctuation signs, calculation signs, parenthesis, square bracket, etc).; + \item tokens with catcode 1 to 4, usually : \verb|{|\quad\verb|}|\footnote{Warning : braces \textbf{must} be balanced in arguments !}\quad\verb|$|\quad\verb|&| + \item tokens with catcode 7 and 8, usually : \verb|^|\quad\verb|_| + \item any purely expandable control sequence\footnote{i.e. this control sequence can be {\ttfamily\string\edef}ed.} or tokens with catcode 13 (active chars) whose expansion is allowed chars. +\end{itemize}\parindent0pt +\smallskip + +When arguments are not expanded with the use of \verbinline|\noexpandarg|, other tokens can be put in a string whatever be the code they make: any control sequence, even undefined, any token catcode 13. Moreover, test tokens are allowed like \verbinline|\if| or \verbinline|\ifx|, even without their \verbinline|\fi|. On the same way, a \verbinline|\csname| without its \verbinline|\endcsname| is allowed. + +In this example, the argument contains a \verbinline|\ifx| \emph{without} the \verbinline|\fi|: the \verbinline|\StrBetween| command extracts and dislpays what is between \verbinline|\ifx| and \verbinline|\else|:\par\medskip\nobreak + +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\noexpandarg +\StrBetween{\ifx ab false \else true}{\ifx}{\else} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \noexpandarg + \StrBetween{\ifx ab false \else true}{\ifx}{\else} +\end{minipage} +\medskip + +When \verbinline|\expandarg| is used, the first token needs precaution since it is expanded one time: it must be defined. The other tokens are left unchanged like with \verbinline|\noexpandarg|. + +\subsection{Expansion of macros, optional argument} +\label{argumentoptionnel} +The macros of this package are not purely expandable, i.e. they cannot be put in the argument of an \verbinline|\edef|. Nestling macros is not possible neither.\medskip + +For this reason, all the macros returning a result (i.e. all excepted the tests) have an optional argument in last position. The syntax is \arguC{name}, where \argu{name} is the name of the control sequence that will receive the result of the macro: the assignment is made with an \verbinline|\edef| which make the result of the macro \argu{name} purely expandable. Of course, if an optional argument is present, the macro does not display anything.\medskip + +Thus, this structure not allowed, supposed to assign to \verb|\Result| the 4 chars on the left of \verb|xstring|:\par\nobreak +\hspace{0.2\linewidth}\verbinline|\edef\Result{\StrLeft{xstring}{4}}|\par\nobreak +\qquad is equivalent to :\par\nobreak +\hspace{0.2\linewidth}\verbinline|\StrLeft{xstring}{4}[\Result]|\medskip + +And this nested structure, not allowed neither, supposed to remove the first and last char of \verb|xstring|:\par\nobreak +\hspace{0.2\linewidth}\verbinline|\StrGobbleLeft{\StrGobbleRight{xstring}{1}}{1}|\par\nobreak +\qquad should be written like this:\par\nobreak +\hspace{0.2\linewidth}\verbinline|\StrGobbleRight{xstring}{1}[\mystring]|\par\nobreak +\hspace{0.2\linewidth}\verbinline|\StrGobbleleft{\mystring}{1}|\par + +\subsection{How does \Xstring read the arguments?} +\label{developpementarguments} +\subsubsection{Syntax unit by \US} +The macros of \Xstring read their arguments \US par \US. In the \TeX{} code, a \US\footnote{For advanced users used to \LaTeX{} programming, a \US is what is gobbled by the macro \texttt{\string\@gobble} whose code is: {\ttfamily\string\def\string\@gobble\string#1\string{\string}}} is either:\parindent3em +\begin{itemize} + \item a control sequence; + \item a group, i.e. what is between 2 balanced braces (usually tokens catcode 1 and 2); + \item a char. +\end{itemize} +\medskip\parindent0pt + +Let's see what is a \US with an example. Let's take this argument : "\verb|ab\textbf{xyz}cd|" + +It has 6 \USs: "\verb|a|", "\verb|b|", "\verb|\textbf|", "\verb|{xyz}|", "\verb|c|" and "\verb|d|".\medskip + +What will happen if, while \verbinline|\noexpandarg| is active, we ask \Xstring to find the length of this argument and find its 4\th "char"\medskip + +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\noexpandarg +\StrLen{ab\textbf{xyz}cd}\par +\StrChar{ab\textbf{xyz}cd}{4}[\mychar] +\meaning\mychar +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \noexpandarg + \StrLen{ab\textbf{xyz}cd}\par + \StrChar{ab\textbf{xyz}cd}{4}[\mychar] + \meaning\mychar +\end{minipage}% +\fullexpandarg +\medskip + +It is necessary to use \verbinline|\meaning| to see the real expansion of \verb|\mychar|, and not simply call \verb|\mychar| to display it, which make loose informations (braces here). We do not obtain a "char" but a \US, as expected. + +\subsubsection{Exploration of groups} +By default, the command \verbinline|\noexploregroups| is called, so in the argument containing the string of tokens, \Xstring does not look into groups, and simply consider them as a \US. + +For specific uses, it can be necessary to look into groups: \verbinline|\exploregroups| changes the exploration mode and forces the macros to look inside groups.\medskip + +What does this exploration mode in the previous example? \Xstring does not count the group as a single \US but looks inside it and counts the \US found inside (\verb|x|, \verb|y| and \verb|z|), and so on if there were several nested groups:\smallskip + +\nobreak\smallskip +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\noexpandarg +\exploregroups +\StrLen{ab\textbf{xyz}cd}\par +\StrChar{ab\textbf{xyz}cd}{4}[\mychar] +\meaning\mychar +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \noexpandarg + \exploregroups + \StrLen{ab\textbf{xyz}cd}\par + \StrChar{ab\textbf{xyz}cd}{4}[\mychar] + \meaning\mychar +\end{minipage}% +\fullexpandarg\noexploregroups +\medskip + +Exploring the groups can be usefull for counting a substring in a string (\verbinline|\StrCount|), for the position of a substring in a string (\verbinline|\StrPosition|) or for tests, but has a severe limitation with macros returning a string: when a string is cut inside a group, \textbf{the result does not take into account what is outside this group}. This exploration mode must be used knowingly this limitation when calling macros returning a string.\smallskip + +Let's see what this means with an example. We want to know what is on the left of the second appearance of \verb|\a| in the argument \verb|\a1{\b1\a2}\a3|. As groups are explored, this appearance is inside this group : \verb|{\b1\a2}|. The result will be \verb|\b1|. Let's check:\par\nobreak\smallskip +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\noexpandarg +\exploregroups +\StrBefore[2]{\a1{\b1\a2}\a3}{\a}[\mycs] +\meaning\mycs +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \noexpandarg + \exploregroups + \StrBefore[2]{\a1{\b1\a2}\a3}{\a}[\mycs] + \meaning\mycs +\end{minipage}% +\medskip + +Exploring the groups\footnote{The file test of \Xstring has many examples underlining differences between exploration modes.} can change the behaviour of most of the macros of \Xstring, excepted these macros untouched by the exploration mode; their behaviour is the same in any case: \verbinline|\IfInteger|, \verbinline|\IfDecimal|, \verbinline|\IfStrEq|, \verbinline|\StrEq| et \verbinline|\StrCompare|. + +Moreover, 2 macros run in \verbinline|\noexploregroups| mode, whatever be the current mode: \verbinline|\StrBetween| et \verbinline|\StrMid|.\medskip + +It is possible to save the exploration mode with \verbinline|\saveexploremode|, then modify it and come back to the situation when it was saved with \verbinline|\restoreexploremode|. + +\subsection{Catcode and starred macros} +\label{macrosetoilees} +Macros of this package take the catcodes of tokens into account. To avoid unexpected behaviour (particulary with tests), you should keep in mind that tokens \emph{and their catcodes} are examined.\medskip + +For instance, these two arguments:\par\medskip +\hfil\verbinline|{\string a\string b}|\qquad and\qquad\verb|{ab}|\hfil{}\par\smallskip +do \emph{not} expand into equal strings for xstring! Because of the command \verbinline|\string|, the first expands into "\verb|ab|" with catcodes 12 while the second have characters with their natural catcodes 11. Catcodes do not match! It is necessary to be aware of this, particulary with \TeX{} commands like \verbinline|\string| whose expansions are a strings with chars catcodes 12 and 10 : \verbinline|\detokenize|, \verbinline|\meaning|, \verbinline|\jobname|, \verbinline|\fontname|, \verbinline|\romannumeral|, etc.\medskip + +Starred macros do not take catcodes into account. They simply convert some arguments into arguments with catcodes 10, 11 and 12, and call the non-starred macros with these modified arguments. The optional arguments are not modified and the catcodes are left unchanged.\medskip + +Here is an example:\par\nobreak\smallskip +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\IfStrEq{\string a\string b}{ab}{true}{false}\par +\IfStrEq*{\string a\string b}{ab}{true}{false} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \IfStrEq{\string a\string b}{ab}{true}{false}\par + \IfStrEq*{\string a\string b}{ab}{true}{false} +\end{minipage}% +\smallskip + +The strings do not match because of catcode differences: the test is negative in the non-starred macro.\bigskip + +\textbf{Warning}: the use of a strarred macro has consequences! The arguments are \guill{detokenized}, thus, there is no more control sequences, groups, neither any special char: everything is converted into chars with "harmless" catcodes.\medskip + +For the macros returning a string, if the starred version is used, the result will be a string in which chars have catcodes 12 and 10 for space. For example, after a "\verbinline|\StrBefore*{a \b c d}{c}[\mytext]|", the control sequence \verb|\mytext| expands to "\verb|a|${}_{12}$\verb*| |${}_{10}$\verb|\|${}_{12}$\verb|b|${}_{12}$\verb*| |${}_{10}$".\medskip + +The macro with a starred version are listed below. For these macros, if starred version is used, the \textcolor{violet}{purple} arguments will be detokenized:\smallskip + +\parindent3em +\begin{itemize} + \item\verb|\IfSubStr|\etoile\arguC{number}{\colorise\ARGU{string}\ARGU{stringA}}\ARGU{true}\ARGU{false} + \item\verb|\IfSubStrBefore|\etoile\arguCC{number1}{number2}{\colorise\ARGU{string}\ARGU{stringA}\ARGU{stringB}}\ARGU{true}\ARGU{false} + \item\verb|\IfSubStrBehind|\etoile\arguCC{number1}{number2}{\colorise\ARGU{string}\ARGU{stringA}\ARGU{stringB}}\ARGU{true}\ARGU{false} + \item\verb|\IfBeginWith|\etoile{\colorise\ARGU{string}\ARGU{stringA}}\ARGU{true}\ARGU{false} + \item\verb|\IfEndWith|\etoile{\colorise\ARGU{string}\ARGU{stringA}}\ARGU{true}\ARGU{false} + \item\verb|\IfStrEq|\etoile{\colorise\ARGU{stringA}\ARGU{stringB}}\ARGU{true}\ARGU{false} + \item\verb|\IfEq|\etoile{\colorise\ARGU{stringA}\ARGU{stringB}}\ARGU{true}\ARGU{false} + \item\verb|\IfStrEqCase|\etoile{\colorise\ARGU{string}\texttt{\color{black}\{}\colorise\ARGU{string1}}\ARGU{code1}\par + \setbox0=\hbox{{\ttfamily\string\IfStrEqCase}\etoile\ARGU{string}{\ttfamily\{}} + \hskip\wd0{\colorise\ARGU{string2}}\ARGU{code2}\par + \hskip\wd0\ \ldots\par + \hskip\wd0{\colorise\ARGU{string $n$}}\ARGU{code $n$}\verb|}|\arguC{other cases code} + \item\verb|\IfEqCase|\etoile{\colorise\ARGU{string}\texttt{\color{black}\{}\colorise\ARGU{string1}}\ARGU{code1}\par + \setbox0=\hbox{{\ttfamily\string\IfEqCase}\etoile\ARGU{string}{\ttfamily\{}} + \hskip\wd0{\colorise\ARGU{string2}}\ARGU{code2}\par + \hskip\wd0\ \ldots\par + \hskip\wd0{\colorise\ARGU{string $n$}}\ARGU{code $n$}\verb|}|\arguC{other cases code} + \item\verb|\StrBefore|\etoile\arguC{number}{\colorise\ARGU{string}\ARGU{stringA}}\arguC{name} + \item\verb|\StrBehind|\etoile\arguC{number}{\colorise\ARGU{string}\ARGU{stringA}}\arguC{name} + \item\verb|\StrBetween|\etoile\arguCC{number1}{number2}{\colorise\ARGU{string}\ARGU{stringA}\ARGU{stringB}}\arguC{name} + \item\verb|\StrCompare|\etoile{\colorise\ARGU{stringA}\ARGU{stringB}}\arguC{name} +\end{itemize} +\parindent0pt + +\section{Advanced macros for programming} +Though \Xstring is able to read arguments containing \TeX{} or \LaTeX{} code, for some advanced programming needs, it can be insufficient. This chapter presents other macros able to get round some limitations. + +\subsection{Finding a group, macros {\ttfamily\textbackslash StrFindGroup} and {\ttfamily\textbackslash groupID}} +When \verbinline=\exploregroups= mode is active, the macro \verbinline=\StrFindGroup= finds a group between braces with its identifier:\smallskip + +\verbinline|\StrFindGroup|\ARGU{argument}\ARGU{identifier}\arguC{name}\medskip + +When the group matching the identifier does not exist, an empty string is assigned to \argu{name}. If the group is found, this group \emph{with its braces} is assigned to \argu{name}.\smallskip + +This identifier characterizes the nestling position of the group. It is a list of one or several integers separated with commas. $n_1$, the first integer is the number of the group (not nestled in another) in which the sought group is. Inside this group, the second integer $n_2$ is the number of the group (not nestled in another) in which the sought group is\ldots and so on until the necessary nestling depth is reached to obtain the sougth after group.\bigskip + +Let's take an example with 3 levels of nestled groups. In this example, braces delimiting groups are colored in red for nestling level 1, in blue for level 2 and in green for level 3. The groups are numbered with the rule seen above: +\begingroup + \def\AccO#1{\text{\color{#1}\ttfamily\{}} + \def\AccF#1{\text{\color{#1}\ttfamily\}}} + \def\texte#1{\text{\texttt{\color{black}#1}}} + \def\decalbrace{\vphantom{\underbrace{A}_A}} + \[\texte{a}{\color{red}\underbrace{\AccO{red}{\color{blue}\underbrace{\decalbrace\AccO{blue}\texte{bc}\AccF{blue}}_{\color{blue}1}}\texte{d}{\color{blue}\underbrace{\decalbrace\AccO{blue}\texte{efg}\AccF{blue}}_{\color{blue}2}}\AccF{red}}_{\color{red}1}}\texte{h}{\color{red}\underbrace{\AccO{red}{\color{blue}\underbrace{\decalbrace\AccO{blue}\texte{ij}\AccF{blue}}_{\color{blue}1}}{\color{blue}\underbrace{\decalbrace\AccO{blue}\texte{k}\AccF{blue}}_{\color{blue}2}}{\color{blue}\underbrace{\AccO{blue}\texte{l}{\color{green}\underbrace{\AccO{green}\texte{m}\AccF{green}}_{\color{green}1}}{\color{green}\underbrace{\AccO{green}\texte{no}\AccF{green}}_{\color{green}2}}\AccF{blue}}_{\color{blue}3}}\texte{p}\AccF{red}}_{\color{red}2}}\] +\endgroup +\smallskip +In this example:\parindent3em +\begin{itemize} + \item the group \verb={{bc}d{efg}}= has the identifier: \texttt{\color{red}1} + \item the group \verb={ij}= has the identifier: \texttt{{\color{red}2},\color{blue}1} + \item the group \verb={no}= has the identifier: \texttt{{\color{red}2},{\color{blue}3},\color{green}2} + \item the whole argument \verb=a{{bc}d{efg}}h{{ij}{k}{l{m}{no}}p}= has the identifier \verb=0=, only case where the integer 0 is appears in the identifier of a group. +\end{itemize} +\parindent0pt +\medskip +Here is the full example:\par\nobreak\smallskip +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\exploregroups +\expandarg +\def\mystring{a{{bc}d{efg}}h{{ij}{k}{l{m}{no}}p}} +\StrFindGroup{\mystring}{1}[\mygroup] +\meaning\mygroup\par +\StrFindGroup{\mystring}{2,1}[\mygroup] +\meaning\mygroup\par +\StrFindGroup{\mystring}{2,3,2}[\mygroup] +\meaning\mygroup\par +\StrFindGroup{\mystring}{2,5}[\mygroup] +\meaning\mygroup\par +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \exploregroups + \expandarg + \def\mystring{a{{bc}d{efg}}h{{ij}{k}{l{m}{no}}p}} + \StrFindGroup{\mystring}{1}[\mygroup] + \meaning\mygroup\par + \StrFindGroup{\mystring}{2,1}[\mygroup] + \meaning\mygroup\par + \StrFindGroup{\mystring}{2,3,2}[\mygroup] + \meaning\mygroup\par + \StrFindGroup{\mystring}{2,5}[\mygroup] + \meaning\mygroup\par +\end{minipage}% +\bigskip + +The reverse process exists, and several macros of \Xstring provide the identifier of the group in which they made a cut or they found a substring. These macros are: \verbinline|\IfSubStr|, \verbinline|\StrBefore|, \verbinline|\StrBehind|, \verbinline|\StrSplit|, \verbinline|\StrLeft|, \verbinline|\StrGobbleLeft|, \verbinline|\StrRight|, \verbinline|\StrGobbleRight|, \verbinline|\StrChar|, \verbinline|\StrPosition|.\medskip + +After these macros, the control sequence \verbinline|\groupID| expands to the identifier of the group where the cut has been done or the search has succeeded. When not cut can be done or the search fails, \verbinline|\groupID| is empty. Obvioulsly, the use of \verbinline|\groupID| has sense only when \verbinline|\exploregroups| mode is acive and when non starred macros are used.\smallskip + +Here are some examples with the macro \verbinline|\StrChar|:\par\nobreak\smallskip +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\exploregroups +char 1 = \StrChar{a{b{cd}{e{f}g}h}ijkl}{1}\qquad +\string\groupID = \groupID\par +char 4 = \StrChar{a{b{cd}{e{f}g}h}ijkl}{4}\qquad +\string\groupID = \groupID\par +char 6 = \StrChar{a{b{cd}{e{f}g}h}ijkl}{6}\qquad +\string\groupID = \groupID\par +char 20 = \StrChar{a{b{cd}{e{f}g}h}ijkl}{20}\qquad +\string\groupID = \groupID +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \exploregroups + char 1 = \StrChar{a{b{cd}{e{f}g}h}ijkl}{1}\qquad + \string\groupID = \groupID\par + char 4 = \StrChar{a{b{cd}{e{f}g}h}ijkl}{4}\qquad + \string\groupID = \groupID\par + char 6 = \StrChar{a{b{cd}{e{f}g}h}ijkl}{6}\qquad + \string\groupID = \groupID\par + char 20 = \StrChar{a{b{cd}{e{f}g}h}ijkl}{20}\qquad + \string\groupID = \groupID +\end{minipage} + +\subsection{Splitting a string, the macro {\ttfamily\textbackslash StrSplit}} +\label{StrSplit} +Here is the syntax:\smallskip + +\verbinline|\StrSplit|\ARGU{string}\ARGU{number}\ARGU{stringA}\ARGU{stringB} +\smallskip + +The \argu{string}, is splitted after the \US at position \argu{number}. The left part is assigned to the control sequence \argu{stringA} and the right part is assigned to \argu{stringB}.\par +This macro returns two strings, so it does \emph{not} display anything. Consequently, it does not provide the optional argument in last position.\medskip + +\begin{Conditions} + \item If \argu{number}${}\leqslant0$, \argu{stringA} is empty and \argu{stringB} is equal to \argu{string}; + \item If \argu{number}${}\geqslant$\argu{lengthString}, \argu{stringA} is equal to \argu{string} and \argu{stringB} is empty; + \item If \argu{string} is empty, \argu{stringA} and \argu{stringB} are empty, whatever be the integer \argu{number}. +\end{Conditions} + +\begin{minipage}[c]{0.65\linewidth} + +\begin{lstlisting} +\def\redsep{{\color{red}|}}% +\StrSplit{abcdef}{4}{\csA}{\csB}|\csA\redsep\csB| +\StrSplit{a b c }{2}{\csA}{\csB}|\csA\redsep\csB| +\StrSplit{abcdef}{1}{\csA}{\csB}|\csA\redsep\csB| +\StrSplit{abcdef}{5}{\csA}{\csB}|\csA\redsep\csB| +\StrSplit{abcdef}{9}{\csA}{\csB}|\csA\redsep\csB| +\StrSplit{abcdef}{-3}{\csA}{\csB}|\csA\redsep\csB| +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \def\redsep{{\color{red}|}}% + \StrSplit{abcdef}{4}{\csA}{\csB}|\csA\redsep\csB|\par + \StrSplit{a b c }{2}{\csA}{\csB}|\csA\redsep\csB|\par + \StrSplit{abcdef}{1}{\csA}{\csB}|\csA\redsep\csB|\par + \StrSplit{abcdef}{5}{\csA}{\csB}|\csA\redsep\csB|\par + \StrSplit{abcdef}{9}{\csA}{\csB}|\csA\redsep\csB|\par + \StrSplit{abcdef}{-3}{\csA}{\csB}|\csA\redsep\csB| +\end{minipage}% + +When the exploration of groups is active and the cut is made at the end of a group, the content of the left string will tbe the entire group while the right string will be empty. The example shows this:\par\nobreak\smallskip +\begin{minipage}[c]{0.65\linewidth} +\hfill +\begin{lstlisting} +\exploregroups +\StrSplit{ab{cd{ef}gh}ij}{6}\strA\strB +\meaning\strA\par +\meaning\strB +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \exploregroups + \StrSplit{ab{cd{ef}gh}ij}{6}\strA\strB + \meaning\strA\par + \meaning\strB +\end{minipage}% +\medskip + +This macro provides a star version: in this case, the cut is made just before the \US which follows the \US at position \argu{number}. Both version give same results, except when the cut is made at the end of a group; in that case, \verbinline|\StrSplit| closes as many group as necessary until it finds the next \US: the cut is made just before this \US.\smallskip + +\begin{minipage}[c]{0.65\linewidth} +\hfill +\begin{lstlisting} +\exploregroups +Use without star :\par +\StrSplit{ab{cd{ef}gh}ij}{6}\strA\strB +\meaning\strA\par +\meaning\strB\par +\string\groupID\ = \groupID\par\medskip +Use with star :\par +\StrSplit*{ab{cd{ef}gh}ij}{6}\strA\strB +\meaning\strA\par +\meaning\strB\par +\string\groupID\ = \groupID +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \exploregroups + Use without star :\par + \StrSplit{ab{cd{ef}gh}ij}{6}\strA\strB + \meaning\strA\par + \meaning\strB\par + \string\groupID\ = \groupID\par\medskip + Use with star :\par + \StrSplit*{ab{cd{ef}gh}ij}{6}\strA\strB + \meaning\strA\par + \meaning\strB\par + \string\groupID\ = \groupID +\end{minipage}% + +\subsection{Assign a verb content, the macro \ttfamily\textbackslash verbtocs} +\label{verbtocs} +The macro \verbinline|\verbtocs| allow to read the content of a \guill{verb} argument containing special characters: \verb|&|, \verb|~|, \verb|\|, \verb|{|, \verb|}|, \verb|_|, \verb|#|, \verb|$|, \verb|^| and \verb|%|. The catcodes of \guill{normal} characters are left unchanged while special characters take a catcode 12. Then, these characters are assigned to a control sequence. The syntax is:\par\nobreak\medskip +\hfill\verbinline|\verbtocs|\ARGU{name}|\argu{characters}|\hfill{} +\smallskip + +\argu{name} is the name of the control sequence receiving, with an \verbinline|\edef|, the \argu{characters}. \argu{name} thus contains tokens with catcodes 12 (or 10 for space).\medskip + +By default, the token delimiting the verb content is \guill{|}. Obviously, this token cannot be both delimiting and being contained into what it delimits. If you need to verbatimize strings containing \guill{|}, you can change at any time the token delimiting the verb content with the macro:\par\nobreak\medskip +\hfill\verbinline|\setverbdelim|\ARGU{character}\hfill{}\smallskip + +Any \argu{token} can be used\footnote{Several tokens can be used, but the syntax of \texttt{\textbackslash verbtocs} becomes less readable ! For this reason, a warning occurs when the argument of \texttt{\textbackslash setverbdelim} contains more than a single token.}. For example, after \verbinline|\setverbdelim{=}|, a verb argument look like this: \verb|=|\argu{characters}\verb|=|.\medskip + +About verb arguments, keep in mind that: +\begin{itemize} + \item all the characters before |\argu{characters}| are ignored; + \item inside the verb argument, all the spaces are taken into account, even if they are consecutive. +\end{itemize} +\medskip + +Example:\par\nobreak\medskip +\begin{minipage}[c]{0.65\linewidth} +\lstset{deletecomment=[l]\%} +\begin{lstlisting} +\verbtocs{\result} |a & b{ c% d$ e \f| +I display the result :\par\result +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \verbtocs{\result} |a & b{ c% d$ e \f| + I display the result :\par\result +\end{minipage}% + +\subsection{Tokenization of a text to a control sequence, the macro \ttfamily\textbackslash tokenize} +The reverse process of what has been seen above is to transform chars into tokens. This is done by the macro:\par\nobreak\medskip +\hfill\verbinline|\tokenize|\ARGU{name}\ARGU{control sequences}\hfill{} +\smallskip + +\argu{control sequences} is fully expanded if \verbinline|\fullexpandarg| has been called, and is not expanded if \verbinline|\noexpandarg| or \verbinline|\expandarg| are active. After expansion, the chars are tokenized to tokens and assigned to \argu{name} with a \verbinline|\def|.\medskip + +Example:\par\nobreak\medskip +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\verbtocs{\text}|\textbf{a} $\frac{1}{2}$| +text : \text +\tokenize{\result}{\text}\par +result : \result +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \verbtocs{\text} + |\textbf{a} $\frac{1}{2}$| + text : \text + \tokenize{\result}{\text} \par + result : \result +\end{minipage}% +\medskip + +Obviously, the control sequence \verb|\result| can be called at the last line since the control sequences it contains are defined. + +\subsection{Expansion of a control sequence before verbatimize, the macros {\ttfamily\textbackslash StrExpand} and {\ttfamily\textbackslash scancs}} +\label{scancs} +The macro \verbinline|\StrExpand| expands the tokens of a string:\par\nobreak\medskip +\verbinline|\StrExpand|\arguC{number}\ARGU{string}\ARGU{name}\smallskip + +By default, \argu{number} is 1 and represnts the number of times each token of \argu{string} has to be expanded. The \argu{name} is a control sequence receiving the result of the expansions.\medskip + +Macro works sequentially and by pass: in a pass, each token from left to right is replaced by its 1-expansion. After this expansion, if the \argu{number} of expansions is not reached, an other pass starts, and so on.\medskip + +Here is an example:\par\nobreak\smallskip +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\def\csA{1 2} +\def\csB{a \csA} +\def\csC{\csB\space} +\def\csD{x{\csA y}\csB{\csC z}} +Expansion of \string\csD\ at\par +\StrExpand[0]{\csD}{\csE} depth 0 : +\detokenize\expandafter{\csE}\par +\StrExpand[1]{\csD}{\csE} depth 1 : +\detokenize\expandafter{\csE}\par +\StrExpand[2]{\csD}{\csE} depth 2 : +\detokenize\expandafter{\csE}\par +\StrExpand[3]{\csD}{\csE} depth 3 : +\detokenize\expandafter{\csE}\par +\StrExpand[4]{\csD}{\csE} depth 4 : +\detokenize\expandafter{\csE} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \def\csA{1 2} + \def\csB{a \csA} + \def\csC{\csB\space} + \def\csD{x{\csA y}\csB{\csC z}} + Expansion of \string\csD\ at\par + \StrExpand[0]{\csD}{\csE} depth 0 : + \detokenize\expandafter{\csE}\par + \StrExpand[1]{\csD}{\csE} depth 1 : + \detokenize\expandafter{\csE}\par + \StrExpand[2]{\csD}{\csE} depth 2 : + \detokenize\expandafter{\csE}\par + \StrExpand[3]{\csD}{\csE} depth 3 : + \detokenize\expandafter{\csE}\par + \StrExpand[4]{\csD}{\csE} depth 4 : + \detokenize\expandafter{\csE} +\end{minipage}% +\medskip + +The macro expands each token consecutively, and does not see what follows: tokens whose expansion depends on other tokens cannot be expanded with this macro. For instance, though "\hbox{\verbinline|\iftrue A\else B\fi|}" has a natural expansion ("A"), it cannot be put in the argument of \verbinline|\StrExpand| and:\par\nobreak\smallskip +\hfil\verbinline|\StrExpand{\iftrue A\else B\fi}\resultat|\hfil{}\par\nobreak\smallskip +provokes an error because the first token "\verbinline|\iftrue|" is expanded \emph{alone} without seeing its \verbinline-\fi- which makes \TeX{} angry. + +Expansion inside groups is \emph{independant} of the exploration mode: this macro has its own command to expand or not what is inside the groups. By default, tokens inside groups are expanded, but this can be changed with the macro \verbinline-\noexpandingroups-. The default behaviour can be recoverd with \verbinline-\expandingroups-.\bigskip + +The \verbinline-\scancs- macro returns the detokenized result:\par\nobreak\medskip +\verbinline|\scancs|\arguC{number}\ARGU{name}\ARGU{string}\par\nobreak\smallskip +The \argu{number} is 1 by default and represents the number of expansions.\smallskip + +\verbinline-\scancs- has been kept for compatibility with older versions of \Xstring. This macro now unnecessry, simply takes the result of \verbinline|\StrExpand| and \verbinline|\detokenize| it. + +\subsection{Inside the definition of a macro} +Some difficulties arise inside the definition of a macro, i.e. between braces following a \verbinline|\def\macro| or a\\\verbinline|\newcommand\macro|.\medskip + +It is forbidden to use the command \verbinline|\verb| inside the definition of a macro. For the same reasons:\par\medskip +\hfill\textbf{Do not use \texttt{\textbackslash verbtocs} inside the definition of a macro}.\hfill{}\medskip + +But then, how to manipulate special characters and "verbatimize" inside the définition of macros ?\bigskip + +The \verbinline|\detokenize| primitive of $\varepsilon$-\TeX can be used but it has limitations: +\begin{itemize} + \item braces must be balanced; + \item consecutive spaces make a single space; + \item the \verb|%| sign is not allowed; + \item a space is inserted after each control sequence; + \item \verb|#| signs become \verb|##|. +\end{itemize} +\medskip + +It is better to use \verbinline|\scancs| and define \emph{outside the definition of the macros} control sequences containing special characters with \verbinline|\verbtocs|. It is also possible to use \verbinline|\tokenize| to transform the final result (which is generaly \texte{10,11,12}) into control sequences. See example using these macros at the end of this manual, page~\pageref{exemples}.\medskip + +In the following teaching example\footnote{It is possible to make much more simple using \texttt{\textbackslash detokenize}. The macro becomes:\par\texttt{\textbackslash newcommand\textbackslash bracearg[1]\{\textbackslash detokenize\{\{\#1\}\}\}}}, the macro \verb|\bracearg| adds braces to its argument. To make this possible, 2 control sequences \verb|\Ob| and \verb|\Cb| containing "\verb|{|" and "\verb|}|" are defined outside the definition of \verb|\bracearg|, and expanded inside it:\par\nobreak\medskip +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\verbtocs{\Ob}|{| +\verbtocs{\Cb}|}| +\newcommand\bracearg[1]{% + \def\text{#1}% + \scancs{\result}{\Ob\text\Cb}% + \result} + +\bracearg{xstring}\par +\bracearg{\a} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \verbtocs{\Ob}|{| + \verbtocs{\Cb}|}| + \newcommand\bracearg[1]{% + \def\text{#1}% + \scancs{\result}{\Ob\text\Cb}% + \result} + + \bracearg{xstring}\par + \bracearg{\a} +\end{minipage}% + +\subsection{The macro \ttfamily\textbackslash StrRemoveBraces} +Advanced users may need to remove the braces of an argument. + +The macro \verbinline|\StrRemoveBraces| does this. Its syntax is:\smallskip + +\verbinline|\StrRemoveBraces|\ARGU{string}\arguC{name} +\smallskip + +This macro is sensitive to exploration mode and will remove \emph{all} the braces with \verbinline|\exploregroups| while it will remove braces of lower level with \verbinline|\noexploregroups|.\medskip + +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\noexploregroups +\StrRemoveBraces{a{b{c}d}e{f}g}[\mycs] +\meaning\mycs + +\exploregroups +\StrRemoveBraces{a{b{c}d}e{f}g}[\mycs] +\meaning\mycs +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \noexploregroups + \StrRemoveBraces{a{b{c}d}e{f}g}[\mycs] + \meaning\mycs + + \exploregroups + \StrRemoveBraces{a{b{c}d}e{f}g}[\mycs] + \meaning\mycs +\end{minipage}% + +\subsection{Examples} +\label{exemples} +Here are some very simple examples involving the macros of this package in programming purposes. + +\subsubsection{Example 1} +We want to substitute the 2 first \verbinline|\textit| by \verbinline|\textbf| in the control sequence \verb|\myCS| which contains \par\smallskip +\hfill\verbinline|\textit{A}\textit{B}\textit{C}|\hfill{} +\medskip + +We expect: \textbf{A}\textbf{B}\textit{C}\medskip + +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\expandarg +\def\myCS{\textit{A}\textit{B}\textit{C}} +\def\pattern{\textit} +\def\replace{\textbf} +\StrSubstitute[2]{\myCS}{\pattern}{\replace} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \expandarg + \def\myCS{\textit{A}\textit{B}\textit{C}} + \def\pattern{\textit} + \def\replace{\textbf} + \StrSubstitute[2]{\myCS}{\pattern}{\replace} +\end{minipage}% +\medskip + +It is possible to avoid to define \verb|\pattern| and \verb|\replace|: a "snare" can be used. It can be a control sequence which expansion is empty, like the famous \verbinline|\empty|. The code would have been:\par\nobreak\smallskip +\hfil\verbinline|\StrSubstitute[2]{\myCS}{\empty\textit}{\empty\textbf}|\hfil{}\medskip + +With this code, in both arguments, the first token \verbinline|\empty| is expanded to "nothing" and the following significant tokens \verbinline|\textit| and \verbinline|textbf| are left unchanged.\smallskip + +By this way, \verbinline|\empty| is a way to "hack" \verbinline|\expandarg|: it allows to avoid the expansion of all the other tokens. The control sequence \verbinline|\noexpand| can be used instead of \verbinline|\empty| for the same result. + +\subsubsection{Exemple 2} +Here, we try to write a macro which gobbles \verb|n| \USs in a string from a given position, and assigns the result to a control sequence. + +Let's call this macro \verb|StringDel| and let's give it this syntax:\par\nobreak +\hfil\verb|\StringDel{string}{position}{n}{\name_of_result}|\hfil{} +\medskip + +We can proceed like this: take the string before the position and save it. Then remove \verb|n + position| \USs from the initial string, and add (concatenate) this result to the string previously saved. This gives the following code:\par\nobreak\medskip + +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\newcommand\StringDel[4]{% + \begingroup + \expandarg% locally in this group + \StrLeft{\empty#1}{\number\numexpr#2-1}[#4]% + \StrGobbleLeft{\empty#1}{\numexpr#2+#3-1}[\StrA]% + \expandafter\expandafter\expandafter\endgroup + \expandafter\expandafter\expandafter\def + \expandafter\expandafter\expandafter#4% + \expandafter\expandafter\expandafter + {\expandafter#4\StrA}% +} + +\noexploregroups +\StringDel{abcdefgh}{2}{3}{\cmd} +\meaning\cmd + +\StringDel{a\textbf{1}b\textbf{2c}3d}{3}{4}{\cmd} +\meaning\cmd +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \newcommand\StringDel[4]{% + \begingroup + \expandarg% locally in this group + \StrLeft{\empty#1}{\number\numexpr#2-1}[#4]% + \StrGobbleLeft{\empty#1}{\numexpr#2+#3-1}[\StrA]% + \expandafter\expandafter\expandafter\endgroup + \expandafter\expandafter\expandafter\def + \expandafter\expandafter\expandafter#4% + \expandafter\expandafter\expandafter{\expandafter#4\StrA}% + } + + \noexploregroups + \StringDel{abcdefgh}{2}{3}{\cmd} + \meaning\cmd + + \StringDel{a\textbf{1}b\textbf{2c}3d}{3}{4}{\cmd} + \meaning\cmd +\end{minipage}% +\fullexpandarg\bigskip + +To concatenate, the \LaTeX{} macro \verb|\g@addto@macro| could have been used, leading to a lighter code without the huge bridge of \verbinline|\expandafter|. The assignment\footnote{The macro {\ttfamily\string\g@addto@macro} can be used if the catcode of "{\ttfamily\string@}" is temporarily changed with {\ttfamily\string\makeatletter} and restored with {\ttfamily\string\makeatother}} can be written like this:\par\nobreak\smallskip +\hfil\verbinline|\expandafter\g@addto@macro\expandafter#4\expandafter{\StrA}\endgroup|\hfil{} + +\subsubsection{Example 3} +Let's try to write a macro \verb|\tofrac| that transforms an argument of this type \guill{a/b} into \guill{$\frac{a}{b}$}.\par\medskip + +First of all, let's cancel the expansion of arguments with \verbinline|\noexpandarg|, we do not need expansion here. Then, it's easy to cut what is before and behind the first occurrence of \guill{/} (assumed there is a single occurrence) and assign it to \verb|\num| and \verb|\den| and simply call the macro \verbinline|\frac| :\par\nobreak\medskip +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\noexpandarg +\newcommand\tofrac[1]{% + \StrBefore{#1}{/}[\num]% + \StrBehind{#1}{/}[\den]% + $\frac{\num}{\den}$% +} +\tofrac{15/9} +\tofrac{u_{n+1}/u_n} +\tofrac{a^m/a^n} +\tofrac{x+\sqrt{x}/\sqrt{x^2+x+1}} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \noexpandarg + \newcommand\tofrac[1]{% + \StrBefore{#1}{/}[\num]% + \StrBehind{#1}{/}[\den]% + $\frac{\num}{\den}$% + } + \tofrac{15/9} + \tofrac{u_{n+1}/u_n} + \tofrac{a^m/a^n} + \tofrac{x+\sqrt{x}/\sqrt{x^2+x+1}} +\end{minipage}% + +\subsubsection{Example 4} +Let's try to write a macro \verb|\boldafter| which writes in bold the first word that follows the word contained in the expansion of \verb|\word|.\medskip + +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\newcommand\boldafter[2]{% + \noexpandarg + \StrBehind[1]{#1 }{ #2 }[\word]% + \expandarg + \StrBefore{\word}{ }[\word]% + \StrSubstitute[1]{#1}{\word}{\textbf{\word}}% +} + +\boldafter{The xstring package is new}{xstring} + +\boldafter{The xstring package is new}{ring} + +\boldafter{The xstring package is new}{is} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \newcommand\boldafter[2]{% + \noexpandarg + \StrBehind[1]{#1 }{ #2 }[\word]% + \expandarg + \StrBefore{\word}{ }[\word]% + \StrSubstitute[1]{#1}{\word}{\textbf{\word}}% + } + + \boldafter{The xstring package is new}{xstring} + + \boldafter{The xstring package is new}{ring} + + \boldafter{The xstring package is new}{is} +\end{minipage}% +\fullexpandarg + +\subsubsection{Example 5} +How to reverse the order of the 2 first control sequences? For this, a macro \verb|\swaptwofirst| does the job and displays the result. But this time, it is not possible to seek the token \verb|\| (catcode 0) with the macros of \Xstring. This is why the use of \verbinline|\scancs| is necessary: after the detokenization of the argument, it becomes possible to search the char \verb|\| (catcode 12). At line 5, a retokenization is done by \verbinline|\tokenize| and \verb|\before| and \verb|\after| are swapped at this moment.\medskip + +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\verbtocs{\antislash}|\| +\newcommand\swaptwofirst[1]{% + \begingroup + \fullexpandarg + \scancs[0]\mystring{#1}% + \StrBefore[3]{\mystring}{\antislash}[\firsttwo]% + \StrBehind{\mystring}{\firsttwo}[\others] + \StrBefore[2]{\firsttwo}{\antislash}[\before] + \StrBehind{\firsttwo}{\before}[\after]% + \tokenize\myCS{\after\before\others}% + \myCS + \endgroup +} + +\swaptwofirst{\underline{A}\textbf{B}\textit{C}} + +\swaptwofirst{\Large\underline{A}\textbf{B}123} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \verbtocs{\antislash}|\| + \newcommand\swaptwofirst[1]{% + \begingroup + \fullexpandarg + \scancs[0]\mystring{#1}% + \StrBefore[3]{\mystring}{\antislash}[\firsttwo]% + \StrBehind{\mystring}{\firsttwo}[\others] + \StrBefore[2]{\firsttwo}{\antislash}[\before] + \StrBehind{\firsttwo}{\before}[\after]% + \tokenize\myCS{\after\before\others}% + \myCS + \endgroup + } + + \swaptwofirst{\underline{A}\textbf{B}\textit{C}} + + \swaptwofirst{\Large\underline{A}\textbf{B}123} +\end{minipage}% + + +\subsubsection{Example 6} +In a string, we want to find the $n$\th{} word between 2 given delimiters. For this, let's write a macro \verb|\findword| with an optional argument which content is the delimiter (space by default), 1 argument containing the string and an other argument containing the number $n$.\medskip + +The macro \verb|\findword| artfully uses \verbinline|\StrBetween| and \verbinline|\numexpr|:\par\nobreak\medskip +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\newcommand\findword[3][ ]{% + \StrBetween[#3,\numexpr#3+1]{#1#2#1}{#1}{#1}% +} +\noexpandarg +|\findword{a bc d\textbf{e f} gh}{3}| + +|\findword[\nil]{1 \nil 2 3 \nil4\nil5}{2}| +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \newcommand\findword[3][ ]{% + \StrBetween[#3,\numexpr#3+1]{#1#2#1}{#1}{#1}% + } + \noexpandarg + |\findword{a bc d\textbf{e f} gh}{3}| + + |\findword[\nil]{1 \nil 2 3 \nil4\nil5}{2}| +\end{minipage}% + +\bigskip\bigskip +\begin{center} +$\star$\par +$\star$\quad$\star$ +\end{center} +\par\nobreak\bigskip\bigskip +That's all, I hope you will find this package useful!\par\nobreak +Please, send me an \href{mailto:unbonpetit@netc.fr}{email} if you find a bug or if you have any idea of improvement\ldots\par\nobreak\medskip +Christian Tellechea +\end{document}
\ No newline at end of file diff --git a/macros/generic/xstring/xstring-fr.pdf b/macros/generic/xstring/xstring-fr.pdf Binary files differnew file mode 100644 index 0000000000..a1f72f8635 --- /dev/null +++ b/macros/generic/xstring/xstring-fr.pdf diff --git a/macros/generic/xstring/xstring-fr.tex b/macros/generic/xstring/xstring-fr.tex new file mode 100644 index 0000000000..a339416149 --- /dev/null +++ b/macros/generic/xstring/xstring-fr.tex @@ -0,0 +1,2037 @@ +\documentclass[a4paper,10pt,french]{article} +\usepackage{fontspec} +\usepackage[bookmarks=true,bookmarksopen=true,colorlinks=true,hyperfootnotes=false,filecolor=black,linkcolor=blue,urlcolor=blue,pdfauthor={Christian Tellechea},pdftitle={xstring},pdfsubject={package pour la manipulation de chaines de tokens},pdfkeywords={xstring,latex,tex,string,chaine},pdfcreator={LaTeX}]{hyperref} +\usepackage[margin=1.9cm]{geometry} +\usepackage{libertine} +\usepackage[scale=0.85]{noto-mono} +\usepackage[bottom]{footmisc} +\usepackage{amsmath,amssymb,amsfonts,color,eurosym,xspace,xstring,babel,listings} +\makeatletter +\definecolor{@xs@bckgcolor}{rgb}{0.9,1,1} +\definecolor{@xs@keywordsxstring}{rgb}{0,0,0.9} +\definecolor{@xs@keywordslatex}{rgb}{1,0,0} +\definecolor{@xs@arguments}{rgb}{0,0,0} +\definecolor{@xs@comments}{rgb}{0.5,0.5,0.5} +\definecolor{violet}{rgb}{0.66,0,0.66} +\lstset{% + language=[AlLaTeX]TeX,% + morekeywords={numexpr,detokenize},% + float=hbp,% + basicstyle=\small\ttfamily,% + identifierstyle=\color{@xs@arguments},% + keywordstyle=\color{@xs@keywordslatex},% + commentstyle=\itshape\color{@xs@comments},% + columns=fixed,% + tabsize=4,% + frame=single,% + extendedchars=true,% + showspaces=false,% + showstringspaces=false,% + numbers=left,% + numberstyle=\tiny\ttfamily,% + breaklines=true,% + breakindent=3em,% + backgroundcolor=\color{@xs@bckgcolor},% + breakautoindent=true,% + captionpos=t,% + xleftmargin=1em,% + xrightmargin=1em,% + lineskip=0pt,% + numbersep=1em,% + classoffset=1,% + morekeywords={% les macros et commandes de xstring + IfSubStr,IfSubStrBefore,IfSubStrBehind,% + IfBeginWith,IfEndWith,% + IfInteger,IfDecimal,integerpart,decimalpart,% + IfStrEq,IfEq,IfStrEqCase,IfEqCase,% + StrBefore,StrBehind,StrCut,StrBetween,% + StrSubstitute,StrDel,% + StrGobbleLeft,StrGobbleRight,StrRight,StrLeft,StrMid,StrChar,% + StrSplit,% + StrLen,StrCount,StrPosition,StrCompare,% + StrFindGroup,groupID,verbtocs,tokenize,scancs,StrExpand,StrRemoveBraces,% + exploregroups,noexploregroups,saveexploremode,restoreexploremode,% + comparenormal,comparestrict,savecomparemode,restorecomparemode,% + expandarg,noexpandarg,normalexpandarg,fullexpandarg,saveexpandmode,restoreexpandmode,% + expandingroups,noexpandingroups,% + setverbdelim},% + keywordstyle=\color{@xs@keywordsxstring},% + classoffset=0} +\makeatother + +\newcommand\guill[1]{\og{}#1\fg{}} +\newcommand\argu[1]{$\langle$\textit{#1}$\rangle$} +\newcommand\ARGU[1]{\texttt{\color{black}\{}\argu{#1}\texttt{\color{black}\}}} +\newcommand\arguC[1]{\texttt{\color{black}[}\argu{#1}\texttt{\color{black}]}} +\newcommand\arguCC[2]{\texttt{\color{black}[}\argu{#1}\texttt{\color{black},}\argu{#2}\texttt{\color{black}]}} +\newcommand\texte[1]{\texttt{text}${}_{#1}$} +\newcommand\etoile{$\langle$\texttt{[*]}$\rangle$} +\newenvironment{Conditions}[1][1cm]% +{\begin{list}% + {$\vartriangleright$}% + {\setlength{\leftmargin}{#1} + \setlength{\itemsep}{0pt} + \setlength{\parsep}{0pt} + \setlength{\topsep}{2ptplus3ptminus2pt} + }}% +{\end{list}} + +\newcommand\US{unité syntaxique\xspace} +\newcommand\USs{unités syntaxiques\xspace} +\newcommand\Xstring{\textsf{xstring}\xspace} +\newcommand\styleexemple{\small\baselineskip1.03\baselineskip\vskip\baselineskip\relax} +\newcommand\styleexercice{\footnotesize} +\newcommand\verbinline{\lstinline[basicstyle=\normalsize\ttfamily]} +\newcommand\colorise{\color{violet}} +\def\xstringfrenchdateaux#1/#2/#3\nil{\number#3\relax\ifnum#3=1 \noexpand\ier\fi\space \ifcase #2 \or janvier\or f\'evrier\or mars\or avril\or mai\or juin\or juillet\or aout\or septembre\or octobre\or novembre\or d\'ecembre\fi\space#1} +\edef\xstringfrenchdate{\expandafter\xstringfrenchdateaux\xstringdate\nil} +\begin{document} +\setlength{\parindent}{0pt} +\begin{titlepage} + \null\par\vfill + \begin{center} + \begin{minipage}{0.75\linewidth} + \begin{center} + \Huge\bfseries \Xstring\par\vspace{5pt} + \small v\xstringversion\par\vspace{25pt} + \normalsize Manuel de l'utilisateur + \end{center} + \end{minipage} + \end{center} + \vspace{1cm} + \begin{center} + Christian {\sc Tellechea}\par\small + \href{mailto:unbonpetit@netc.fr}{\nolinkurl{unbonpetit@netc.fr}}\par\vspace{5pt} + \xstringfrenchdate + \end{center} + \vfill\hrulefill + \begin{center} + \begin{minipage}{0.85\linewidth} + \noindent + \hfill\textbf{\textit{Résumé}}\hfill{}\medskip\par + Cette extension, qui requiert Plain $\varepsilon$-\TeX, regroupe un ensemble de macros manipulant des chaînes de tokens (ou lexèmes en français). Les macros peuvent être utilisées de façon basique dans le traitement des chaînes de caractères mais peuvent également être utiles en programmation \TeX{} pour la manipulation des tokens, c'est-à -dire du code \TeX{}. Parmis les fonctionnalités, les principales sont :\smallskip + + \parindent1.5em + \begin{itemize} + \item[$\triangleright$] des tests : + \begin{itemize} + \item une chaîne en contient elle une autre au moins $n$ fois ? + \item une chaîne commence t-elle ou finit-elle par une autre ? etc. + \item une chaîne représente t-elle un entier relatif ? Un nombre décimal ? + \item deux chaînes sont-elles égales ? + \end{itemize} + \item[$\triangleright$] des recherches de chaînes : + \begin{itemize} + \item recherche de ce qui se trouve avant (ou après) la $n$\ieme{} occurrence d'une sous-chaîne; + \item recherche de ce qui se trouve entre les occurrences de 2 sous-chaînes; + \item sous-chaîne comprise entre 2 positions; + \item recherche d'un groupe entre accolades par son identifiant. + \end{itemize} + \item[$\triangleright$] le remplacement de toutes ou des $n$ premières occurrences d'une sous-chaîne par une autre sous-chaîne; + \item[$\triangleright$] des calculs de nombres : + \begin{itemize} + \item longueur d'une chaîne; + \item position de la la $n$\ieme{} occurrence d'une sous-chaîne; + \item comptage du nombre d'occurrences d'une sous-chaîne dans une autre; + \item position de la 1\iere{} différence entre 2 chaînes; + \item renvoi de l'identifiant du groupe dans lequel une recherche ou une coupure s'est faite. + \end{itemize} + \end{itemize} + \setlength{\parindent}{0pt} + \medskip + D'autres commandes permettent de gérer les tokens spéciaux normalement interdits dans les chaînes (\verb|#| et \verb|%|), ainsi que d'éventuelles différences entre catcodes de tokens, ce qui devrait permettre de couvrir tous les besoins en matière de programmation. + \end{minipage} + \end{center} + \hrulefill\vfill{} +\end{titlepage} + +\tableofcontents + +% +\section{Présentation} +\subsection{Description} +Cette extension\footnote{L'extension ne nécessite pas \LaTeX{} et peut être compilée sous Plain $\varepsilon$-\TeX{}.} regroupe des macros et des tests opérant sur des chaînes de tokens, un peu comme en disposent des langages dit \guill{évolués}. On y trouve les opérations habituelles sur les chaînes, comme par exemple : test si une chaîne en contient une autre, commence ou finit par une autre, test si une chaîne est un nombre entier ou décimal, extractions de sous-chaînes, calculs de position d'une sous-chaîne, calculs du nombre d'occurrences, etc.\medskip + +On appelle \guill{chaîne de tokens} une suite de tokens quelconques, sachant qu'aucune supposition n'a été faite quant à leur nature, mis à part que dans les chaînes de tokens, les accolades doivent être équilibrées et que les tokens de catcode 6 et 14 (habituellement \verb|%| et \verb|#|) n'y sont pas admis. Tous les autres tokens, y compris \verbinline|\par|, sont \emph{à priori} permis dans n'importe quel ordre, quel que soit le code qu'ils représentent.\medskip + +Les arguments contenant des chaînes de tokens sont lus par \Xstring \emph{\US par \US\footnote{Sauf cas particulier, une \US est un caractère lu dans le code à ces exceptions près : une séquence de contrôle est une \US, un groupe entre accolades est aussi une \US. Voir également page~\pageref{developpementarguments}.}}, ce qui revient à les lire caractère par caractère lorsque ceux-ci contiennent des tokens \guill{normaux}, c'est-à -dire dont les catcodes sont 10, 11 et 12. On peut également utiliser \Xstring à des fins de programmation en utilisant des arguments contenant des séquences de contrôle et des tokens dont les catcodes sont moins inoffensifs. Voir le chapitre sur le mode de lecture et de développement des arguments (page~\pageref{developpementarguments}), la commande \verbinline|\verbtocs| (page~\pageref{verbtocs}), la commande \verbinline|\scancs| (page~\pageref{scancs}).\medskip + +Certes d'autres packages manipulant les chaînes de caractères existent (par exemple \href{http://mirror.ctan.org/tex-archive/macros/latex/contrib/substr/}{\nolinkurl{substr}} et \href{http://mirror.ctan.org/tex-archive/macros/latex/contrib/stringstrings/}{\nolinkurl{stringstrings}}), mais outre des différences notables quant aux fonctionnalités, ils ne prennent pas en charge les occurrences des sous-chaînes et me semblent soit trop limités, soit trop difficiles à utiliser pour la programmation.\medskip + +Comme les macros manipulent des chaînes de tokens, il peut arriver aux utilisateurs avancés de rencontrer des problèmes de \guill{catcodes\footnote{Codes de catégories, en français.}} conduisant à des comportements inattendus. Ces effets indésirables peuvent être contrôlés. Consulter en particulier le chapitre sur les catcodes des arguments page~\pageref{macrosetoilees}. + +\subsection{Motivation} +J'ai été conduit à écrire ce type de macros car je n'ai jamais vraiment trouvé de d'outils sous \LaTeX{} adaptés à mes besoins concernant le traitement de chaînes. Alors, au fil des mois, et avec l'aide de contributeurs\footnote{Je remercie chaleureusement Manuel alias \guill{\nolinkurl{mpg}} pour son aide précieuse, sa compétence et sa disponibilité.} de \nolinkurl{fr.comp.text.tex}, j'ai écrit quelques macros qui me servaient ponctuellement ou régulièrement. Leur nombre s'étant accru, et celles-ci devenant un peu trop dispersées dans les répertoires de mon ordinateur, je les ai regroupées dans ce package. + +Ainsi, le fait de donner corps à un ensemble cohérent de macros force à davantage de rigueur et induit naturellement de nécessaires améliorations, ce qui a pris la majeure partie du temps que j'ai consacré à ce package. Pour harmoniser le tout, mais à contre-cœur, j'ai fini par choisir des noms de macros à consonances anglo-saxonnes.\medskip + +Ensuite, et cela a été ma principale motivation puisque j'ai découvert \LaTeX{} récemment\footnote{En novembre 2007, je suis donc un \og noob\fg{} pour longtemps encore !}, l'écriture de \Xstring qui est mon premier package m'a surtout permis de beaucoup progresser en programmation pure, et aborder des méthodes propres à la programmation sous \TeX. + +\section{Les macros} +Pour bien comprendre les actions de chaque macro, envisageons tout d'abord le fonctionnement et la présentation des macros dans leur mode de fonctionnement le plus simple. Pas de problème de catcode ici, ni de tokens spéciaux et encore moins de séquence de contrôle dans les arguments : les arguments contiendront des caractères alphanumériques.\medskip + +Dans ce chapitre, la totalité des macros est présentée selon ce plan :\par\nobreak\smallskip +\parindent3em +\begin{itemize} + \item la syntaxe complète\footnote{L'étoile optionnelle après le nom de la macro, et l'argument optionnel entre crochet venant en dernier seront expliqués plus tard. Voir page~\pageref{macrosetoilees} pour les macros étoilées et page~\pageref{argumentoptionnel} pour l'argument optionnel en dernière position.} ainsi que la valeur d'éventuels arguments optionnels; + \item une brève description du fonctionnement; + \item le fonctionnement sous certaines conditions particulières. Pour chaque conditions envisagée, le fonctionnement décrit est prioritaire sur celui (ceux) se trouvant au dessous de lui; + \item enfin, quelques exemples sont donnés. J'ai essayé de les trouver les plus facilement compréhensibles et les plus représentatifs des situations rencontrées dans une utilisation normale\footnote{Pour une collection plus importante d'exemples, on peut aussi consulter le fichier de test.}. Si un doute est possible quant à la présence d'espaces dans le résultat, celui-ci sera délimité par des \guill{\textbar}, étant entendu qu'une chaîne vide est représentée par \guill{\textbar\textbar}. +\end{itemize} +\parindent0pt\smallskip + +\textbf{Important} : dans les macros qui suivent, sauf cas spécifié, un \argu{nombre} est un nombre entier, un compteur, ou le résultat d'une opération arithmétique effectuée à l'aide de la primitive \verb|\numexpr|.\smallskip + +Dans le reste du texte, les macros de \Xstring sont affichées en {\makeatletter\color{@xs@keywordsxstring}rouge}. + +\subsection{Les tests} +\subsubsection{\ttfamily\textbackslash IfSubStr} +\verbinline|\IfSubStr|\etoile\arguC{nombre}\ARGU{chaine}\ARGU{chaineA}\ARGU{vrai}\ARGU{faux} +\smallskip + +L'argument optionnel \argu{nombre} vaut 1 par défaut.\par\nobreak\smallskip +Teste si \argu{chaine} contient au moins \argu{nombre} fois \argu{chaineA} et exécute \argu{vrai} dans l'affirmative, et \argu{faux} dans le cas contraire.\medskip + +\begin{Conditions} + \item Si \argu{nombre}${}\leqslant0$, exécute \argu{faux}; + \item Si \argu{chaine} ou \argu{chaineA} est vide, exécute \argu{faux}. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\IfSubStr{xstring}{tri}{vrai}{faux} +\IfSubStr{xstring}{a}{vrai}{faux} +\IfSubStr{a bc def }{c d}{vrai}{faux} +\IfSubStr{a bc def }{cd}{vrai}{faux} +\IfSubStr[2]{1a2a3a}{a}{vrai}{faux} +\IfSubStr[3]{1a2a3a}{a}{vrai}{faux} +\IfSubStr[4]{1a2a3a}{a}{vrai}{faux} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \IfSubStr{xstring}{tri}{vrai}{faux}\par + \IfSubStr{xstring}{a}{vrai}{faux}\par + \IfSubStr{a bc def }{c d}{vrai}{faux}\par + \IfSubStr{a bc def }{cd}{vrai}{faux}\par + \IfSubStr[2]{1a2a3a}{a}{vrai}{faux}\par + \IfSubStr[3]{1a2a3a}{a}{vrai}{faux}\par + \IfSubStr[4]{1a2a3a}{a}{vrai}{faux} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash IfSubStrBefore} +\verbinline|\IfSubStrBefore|\etoile\arguCC{nombre1}{nombre2}\ARGU{chaine}\ARGU{chaineA}\ARGU{chaineB}\ARGU{vrai}\ARGU{faux} +\smallskip + +Les arguments optionnels \argu{nombre1} et \argu{nombre2} valent 1 par défaut.\par\nobreak\smallskip +Dans \argu{chaine}, la macro teste si l'occurrence \no\argu{nombre1} de \argu{chaineA} se trouve à gauche de l'occurrence \no\argu{nombre2} de \argu{chaineB}. Exécute \argu{vrai} dans l'affirmative, et \argu{faux} dans le cas contraire.\medskip + +\begin{Conditions} + \item Si l'une des occurrences n'est pas trouvée, exécute \argu{faux}; + \item Si l'un des arguments \argu{chaine}, \argu{chaineA} ou \argu{chaineB} est vide, exécute \argu{faux}; + \item Si l'un au moins des deux arguments optionnels est négatif ou nul, exécute \argu{faux}. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\IfSubStrBefore{xstring}{st}{in}{vrai}{faux} +\IfSubStrBefore{xstring}{ri}{s}{vrai}{faux} +\IfSubStrBefore{LaTeX}{LaT}{TeX}{vrai}{faux} +\IfSubStrBefore{a bc def }{ b}{ef}{vrai}{faux} +\IfSubStrBefore{a bc def }{ab}{ef}{vrai}{faux} +\IfSubStrBefore[2,1]{b1b2b3}{b}{2}{vrai}{faux} +\IfSubStrBefore[3,1]{b1b2b3}{b}{2}{vrai}{faux} +\IfSubStrBefore[2,2]{baobab}{a}{b}{vrai}{faux} +\IfSubStrBefore[2,3]{baobab}{a}{b}{vrai}{faux} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \IfSubStrBefore{xstring}{st}{in}{vrai}{faux}\par + \IfSubStrBefore{xstring}{ri}{s}{vrai}{faux}\par + \IfSubStrBefore{LaTeX}{LaT}{TeX}{vrai}{faux}\par + \IfSubStrBefore{a bc def }{ b}{ef}{vrai}{faux}\par + \IfSubStrBefore{a bc def }{ab}{ef}{vrai}{faux}\par + \IfSubStrBefore[2,1]{b1b2b3}{b}{2}{vrai}{faux}\par + \IfSubStrBefore[3,1]{b1b2b3}{b}{2}{vrai}{faux}\par + \IfSubStrBefore[2,2]{baobab}{a}{b}{vrai}{faux}\par + \IfSubStrBefore[2,3]{baobab}{a}{b}{vrai}{faux} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash IfSubStrBehind} +\verbinline|\IfSubStrBehind|\etoile\arguCC{nombre1}{nombre2}\ARGU{chaine}\ARGU{chaineA}\ARGU{chaineB}\ARGU{vrai}\ARGU{faux} +\smallskip + +Les arguments optionnels \argu{nombre1} et \argu{nombre2} valent 1 par défaut.\par\nobreak\smallskip +Dans \argu{chaine}, la macro teste si l'occurrence \no\argu{nombre1} de \argu{chaineA} se trouve après l'occurrence \\\no\argu{nombre2} de \argu{chaineB}. Exécute \argu{vrai} dans l'affirmative, et \argu{faux} dans le cas contraire.\medskip + +\begin{Conditions} + \item Si l'une des occurrences n'est pas trouvée, exécute \argu{faux}; + \item Si l'un des arguments \argu{chaine}, \argu{chaineA} ou \argu{chaineB} est vide, exécute \argu{faux}; + \item Si l'un au moins des deux arguments optionnels est négatif ou nul, exécute \argu{faux}. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\IfSubStrBehind{xstring}{ri}{xs}{vrai}{faux} +\IfSubStrBehind{xstring}{s}{i}{vrai}{faux} +\IfSubStrBehind{LaTeX}{TeX}{LaT}{vrai}{faux} +\IfSubStrBehind{a bc def }{ d}{a}{vrai}{faux} +\IfSubStrBehind{a bc def }{cd}{a b}{vrai}{faux} +\IfSubStrBehind[2,1]{b1b2b3}{b}{2}{vrai}{faux} +\IfSubStrBehind[3,1]{b1b2b3}{b}{2}{vrai}{faux} +\IfSubStrBehind[2,2]{baobab}{b}{a}{vrai}{faux} +\IfSubStrBehind[2,3]{baobab}{b}{a}{vrai}{faux} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \IfSubStrBehind{xstring}{ri}{xs}{vrai}{faux}\par + \IfSubStrBehind{xstring}{s}{i}{vrai}{faux}\par + \IfSubStrBehind{LaTeX}{TeX}{LaT}{vrai}{faux}\par + \IfSubStrBehind{a bc def }{ d}{a}{vrai}{faux}\par + \IfSubStrBehind{a bc def }{cd}{a b}{vrai}{faux}\par + \IfSubStrBehind[2,1]{b1b2b3}{b}{2}{vrai}{faux}\par + \IfSubStrBehind[3,1]{b1b2b3}{b}{2}{vrai}{faux}\par + \IfSubStrBehind[2,2]{baobab}{b}{a}{vrai}{faux}\par + \IfSubStrBehind[2,3]{baobab}{b}{a}{vrai}{faux} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash IfBeginWith} +\verbinline|\IfBeginWith|\etoile\ARGU{chaine}\ARGU{chaineA}\ARGU{vrai}\ARGU{faux} +\smallskip + +Teste si \argu{chaine} commence par \argu{chaineA}, et exécute \argu{vrai} dans l'affirmative, et \argu{faux} dans le cas contraire.\medskip + +\begin{Conditions} +\item Si \argu{chaine} ou \argu{chaineA} est vide, exécute \argu{faux}. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\IfBeginWith{xstring}{xst}{vrai}{faux} +\IfBeginWith{LaTeX}{a}{vrai}{faux} +\IfBeginWith{a bc def }{a b}{vrai}{faux} +\IfBeginWith{a bc def }{ab}{vrai}{faux} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \IfBeginWith{xstring}{xst}{vrai}{faux}\par + \IfBeginWith{LaTeX}{a}{vrai}{faux}\par + \IfBeginWith{a bc def }{a b}{vrai}{faux}\par + \IfBeginWith{a bc def }{ab}{vrai}{faux} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash IfEndWith} +\verbinline|\IfEndWith|\etoile\ARGU{chaine}\ARGU{chaineA}\ARGU{vrai}\ARGU{faux} +\smallskip + +Teste si \argu{chaine} se termine par \argu{chaineA}, et exécute \argu{vrai} dans l'affirmative, et \argu{faux} dans le cas contraire.\medskip + +\begin{Conditions} + \item Si \argu{chaine} ou \argu{chaineA} est vide, exécute \argu{faux}. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\IfEndWith{xstring}{ring}{vrai}{faux} +\IfEndWith{LaTeX}{a}{vrai}{faux} +\IfEndWith{a bc def }{ef }{vrai}{faux} +\IfEndWith{a bc def }{ef}{vrai}{faux} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \IfEndWith{xstring}{ring}{vrai}{faux}\par + \IfEndWith{LaTeX}{a}{vrai}{faux}\par + \IfEndWith{a bc def }{ef }{vrai}{faux}\par + \IfEndWith{a bc def }{ef}{vrai}{faux} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash IfInteger} +\verbinline|\IfInteger|\ARGU{nombre}\ARGU{vrai}\ARGU{faux} +\smallskip + +Teste si \argu{nombre} est un nombre entier relatif (c'est-à -dire dont la partie décimale est absente ou constituée d'une suite de 0), et exécute \argu{vrai} dans l'affirmative, et \argu{faux} dans le cas contraire.\par\nobreak\smallskip +Si le test est faux pour cause de caractères non autorisés, les séquences de contrôle \verb|\@xs@afterinteger| et \verb|\afterinteger| contiennent chacune la partie illégale de \argu{nombre}.\medskip + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\IfInteger{13}{vrai}{faux} +\IfInteger{-219}{vrai}{faux} +\IfInteger{+9}{vrai}{faux} +\IfInteger{3.14}{vrai}{faux} +\IfInteger{8.0}{vrai}{faux} +\IfInteger{0}{vrai}{faux} +\IfInteger{49a}{vrai}{faux} +\IfInteger{+}{vrai}{faux} +\IfInteger{-}{vrai}{faux} +\IfInteger{0000}{vrai}{faux} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \IfInteger{13}{vrai}{faux}\par + \IfInteger{-219}{vrai}{faux}\par + \IfInteger{+9}{vrai}{faux}\par + \IfInteger{3.14}{vrai}{faux}\par + \IfInteger{8.0}{vrai}{faux}\par + \IfInteger{0}{vrai}{faux}\par + \IfInteger{49a}{vrai}{faux}\par + \IfInteger{+}{vrai}{faux}\par + \IfInteger{-}{vrai}{faux}\par + \IfInteger{0000}{vrai}{faux} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash IfDecimal} +\label{ifdecimal} +\verbinline|\IfDecimal|\ARGU{nombre}\ARGU{vrai}\ARGU{faux} +\smallskip + +Teste si \argu{nombre} est un nombre décimal, et exécute \argu{vrai} dans l'affirmative, et \argu{faux} dans le cas contraire.\par\nobreak\smallskip +Les compteurs \verb|\integerpart| et \verb|\decimalpart| contiennent les parties entières et décimales de \argu{nombre}. + +Si le test est faux pour cause de caractères non autorisés, les séquences de contrôle \verb|\@xs@afterdecimal| et \verb|\afterdecimal| contiennent chacune la partie illégale de \argu{nombre}, alors que si le test est faux parce que la partie décimale après le séparateur décimal est vide, elles contiennent \guill{X}.\medskip + +\begin{Conditions} + \item Le séparateur décimal peut être un point ou une virgule; + \item Si le \argu{nombre} commence par un séparateur décimal, le test est vrai (lignes 4 et 5) et la partie entière est considérée comme étant 0; + \item Si le \argu{nombre} se termine par un séparateur décimal, le test est faux (lignes 9 et 10). +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\IfDecimal{3.14}{vrai}{faux} +\IfDecimal{3,14}{vrai}{faux} +\IfDecimal{-0.5}{vrai}{faux} +\IfDecimal{.7}{vrai}{faux} +\IfDecimal{,9}{vrai}{faux} +\IfDecimal{1..2}{vrai}{faux} +\IfDecimal{+6}{vrai}{faux} +\IfDecimal{-15}{vrai}{faux} +\IfDecimal{1.}{vrai}{faux} +\IfDecimal{2,}{vrai}{faux} +\IfDecimal{.}{vrai}{faux} +\IfDecimal{,}{vrai}{faux} +\IfDecimal{+}{vrai}{faux} +\IfDecimal{-}{vrai}{faux} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \IfDecimal{3.14}{vrai}{faux}\par + \IfDecimal{3,14}{vrai}{faux}\par + \IfDecimal{-0.5}{vrai}{faux}\par + \IfDecimal{.7}{vrai}{faux}\par + \IfDecimal{,9}{vrai}{faux}\par + \IfDecimal{1..2}{vrai}{faux}\par + \IfDecimal{+6}{vrai}{faux}\par + \IfDecimal{-15}{vrai}{faux}\par + \IfDecimal{1.}{vrai}{faux}\par + \IfDecimal{2,}{vrai}{faux}\par + \IfDecimal{.}{vrai}{faux}\par + \IfDecimal{,}{vrai}{faux}\par + \IfDecimal{+}{vrai}{faux}\par + \IfDecimal{-}{vrai}{faux} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash IfStrEq} + +\verbinline|\IfStrEq|\etoile\ARGU{chaineA}\ARGU{chaineB}\ARGU{vrai}\ARGU{faux} +\smallskip + +Teste si les chaînes \argu{chaineA} et \argu{chaineB} sont égales, c'est-à -dire si elles contiennent successivement les mêmes \US dans le même ordre. Exécute \argu{vrai} dans l'affirmative, et \argu{faux} dans le cas contraire.\smallskip + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\IfStrEq{a1b2c3}{a1b2c3}{vrai}{faux} +\IfStrEq{abcdef}{abcd}{vrai}{faux} +\IfStrEq{abc}{abcdef}{vrai}{faux} +\IfStrEq{3,14}{3,14}{vrai}{faux} +\IfStrEq{12.34}{12.340}{vrai}{faux} +\IfStrEq{abc}{}{vrai}{faux} +\IfStrEq{}{abc}{vrai}{faux} +\IfStrEq{}{}{vrai}{faux} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \IfStrEq{a1b2c3}{a1b2c3}{vrai}{faux}\par + \IfStrEq{abcdef}{abcd}{vrai}{faux}\par + \IfStrEq{abc}{abcdef}{vrai}{faux}\par + \IfStrEq{3,14}{3,14}{vrai}{faux}\par + \IfStrEq{12.34}{12.340}{vrai}{faux}\par + \IfStrEq{abc}{}{vrai}{faux}\par + \IfStrEq{}{abc}{vrai}{faux}\par + \IfStrEq{}{}{vrai}{faux} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash IfEq} +\verbinline|\IfEq|\etoile\ARGU{chaineA}\ARGU{chaineB}\ARGU{vrai}\ARGU{faux} +\smallskip + +Teste si les chaînes \argu{chaineA} et \argu{chaineB} sont égales, \emph{sauf} si \argu{chaineA} et \argu{chaineB} contiennent des nombres, auquel cas la macro teste si les nombres sont égaux. Exécute \argu{vrai} dans l'affirmative, et \argu{faux} dans le cas contraire.\smallskip + +\begin{Conditions} + \item La définition de \emph{nombre} est celle évoquée dans la macro \verbinline|\IfDecimal| (voir page~\pageref{ifdecimal}), et donc : + \item Les signes \guill{+} sont facultatifs; + \item Le séparateur décimal peut être indifféremment la virgule ou le point. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\IfEq{a1b2c3}{a1b2c3}{vrai}{faux} +\IfEq{abcdef}{ab}{vrai}{faux} +\IfEq{ab}{abcdef}{vrai}{faux} +\IfEq{12.34}{12,34}{vrai}{faux} +\IfEq{+12.34}{12.340}{vrai}{faux} +\IfEq{10}{+10}{vrai}{faux} +\IfEq{-10}{10}{vrai}{faux} +\IfEq{+0,5}{,5}{vrai}{faux} +\IfEq{1.001}{1.01}{vrai}{faux} +\IfEq{3*4+2}{14}{vrai}{faux} +\IfEq{\number\numexpr3*4+2}{14}{vrai}{faux} +\IfEq{0}{-0.0}{vrai}{faux} +\IfEq{}{}{vrai}{faux} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \IfEq{a1b2c3}{a1b2c3}{vrai}{faux}\par + \IfEq{abcdef}{ab}{vrai}{faux}\par + \IfEq{ab}{abcdef}{vrai}{faux}\par + \IfEq{12.34}{12,34}{vrai}{faux}\par + \IfEq{+12.34}{12.340}{vrai}{faux}\par + \IfEq{10}{+10}{vrai}{faux}\par + \IfEq{-10}{10}{vrai}{faux}\par + \IfEq{+0,5}{,5}{vrai}{faux}\par + \IfEq{1.001}{1.01}{vrai}{faux}\par + \IfEq{3*4+2}{14}{vrai}{faux}\par + \IfEq{\number\numexpr3*4+2}{14}{vrai}{faux}\par + \IfEq{0}{-0.0}{vrai}{faux}\par + \IfEq{}{}{vrai}{faux} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash IfStrEqCase} +\begin{minipage}{\textwidth} + \verbinline|\IfStrEqCase|\etoile\ARGU{chaine}\verb|{%|\par + \qquad\qquad\ARGU{chaine1}\ARGU{code1}\verb|%|\par + \qquad\qquad\ARGU{chaine2}\ARGU{code2}\verb|%|\par + \qquad\qquad\verb|etc...|\par + \qquad\qquad\ARGU{chaineN}\ARGU{codeN}\verb|}|\arguC{code alternatif} +\end{minipage} +\smallskip + +Teste successivement si \argu{chaine} est égale à \argu{chaine1}, \argu{chaine2}, etc. La comparaison se fait au sens de \verbinline|\IfStrEq| (voir paragraphes précédents). Si un test est positif, le code correspondant est exécuté et la macro se termine. Si tous les tests sont négatifs, le code optionnel \argu{code alternatif} est exécuté s'il est présent.\smallskip + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\IfStrEqCase{b}{{a}{AA}{b}{BB}{c}{CC}} +|\IfStrEqCase{abc}{{a}{AA}{b}{BB}{c}{CC}}| +\IfStrEqCase{c}{{a}{AA}{b}{BB}{c}{CC}}[autre] +\IfStrEqCase{d}{{a}{AA}{b}{BB}{c}{CC}}[autre] +\IfStrEqCase{+3}{{1}{un}{2}{deux}{3}{trois}}[autre] +\IfStrEqCase{0.5}{{0}{zero}{.5}{demi}{1}{un}}[autre] +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \IfStrEqCase{b}{{a}{AA}{b}{BB}{c}{CC}}\par + |\IfStrEqCase{abc}{{a}{AA}{b}{BB}{c}{CC}}|\par + \IfStrEqCase{c}{{a}{AA}{b}{BB}{c}{CC}}[autre]\par + \IfStrEqCase{d}{{a}{AA}{b}{BB}{c}{CC}}[autre]\par + \IfStrEqCase{+3}{{1}{un}{2}{deux}{3}{trois}}[autre]\par + \IfStrEqCase{0.5}{{0}{zero}{.5}{demi}{1}{un}}[autre] +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash IfEqCase} +\begin{minipage}{\textwidth} + \verbinline|\IfEqCase|\etoile\ARGU{chaine}\verb|{%|\par + \qquad\qquad\ARGU{chaine1}\ARGU{code1}\verb|%|\par + \qquad\qquad\ARGU{chaine2}\ARGU{code2}\verb|%|\par + \qquad\qquad\verb|etc...|\par + \qquad\qquad\ARGU{chaineN}\ARGU{codeN}\verb|}|\arguC{code alternatif} +\end{minipage} +\smallskip + +Teste successivement si \argu{chaine} est égale à \argu{chaine1}, \argu{chaine2}, etc. La comparaison se fait au sens de \verbinline|\IfEq| (voir paragraphes précédents). Si un test est positif, le code correspondant est exécuté et la macro se termine. Si tous les tests sont négatifs, le code optionnel \argu{code alternatif} est exécuté s'il est présent.\smallskip + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\IfEqCase{b}{{a}{AA}{b}{BB}{c}{CC}} +|\IfEqCase{abc}{{a}{AA}{b}{BB}{c}{CC}}| +\IfEqCase{c}{{a}{AA}{b}{BB}{c}{CC}}[autre] +\IfEqCase{d}{{a}{AA}{b}{BB}{c}{CC}}[autre] +\IfEqCase{+3}{{1}{un}{2}{deux}{3}{trois}}[autre] +\IfEqCase{0.5}{{0}{zero}{.5}{demi}{1}{un}}[autre] +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \IfEqCase{b}{{a}{AA}{b}{BB}{c}{CC}}\par + |\IfEqCase{abc}{{a}{AA}{b}{BB}{c}{CC}}|\par + \IfEqCase{c}{{a}{AA}{b}{BB}{c}{CC}}[autre]\par + \IfEqCase{d}{{a}{AA}{b}{BB}{c}{CC}}[autre]\par + \IfEqCase{+3}{{1}{un}{2}{deux}{3}{trois}}[autre]\par + \IfEqCase{0.5}{{0}{zero}{.5}{demi}{1}{un}}[autre] +\end{minipage}% + +\subsection{Les macros renvoyant une chaîne} +\subsubsection{\ttfamily\textbackslash StrBefore} +\verbinline|\StrBefore|\etoile\arguC{nombre}\ARGU{chaine}\ARGU{chaineA}\arguC{nom} +\smallskip + +L'argument optionnel \argu{nombre} vaut 1 par défaut.\par\nobreak\smallskip +Dans \argu{chaine}, renvoie ce qui se trouve avant l'occurrence \no\argu{nombre} de \argu{chaineA}.\medskip + +\begin{Conditions} + \item Si \argu{chaine} ou \argu{chaineA} est vide, une chaîne vide est renvoyée; + \item Si \argu{nombre}${}<1$ alors, la macro se comporte comme si \argu{nombre}${}=1$; + \item Si l'occurrence n'est pas trouvée, une chaîne vide est renvoyée. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrBefore{xstring}{tri} +\StrBefore{LaTeX}{e} +|\StrBefore{LaTeX}{p}| +|\StrBefore{LaTeX}{L}| +|\StrBefore{a bc def }{def}| +|\StrBefore{a bc def }{cd}| +\StrBefore[1]{1b2b3}{b} +\StrBefore[2]{1b2b3}{b} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrBefore{xstring}{tri}\par + \StrBefore{LaTeX}{e}\par + |\StrBefore{LaTeX}{p}|\par + |\StrBefore{LaTeX}{L}|\par + |\StrBefore{a bc def }{def}|\par + |\StrBefore{a bc def }{cd}|\par + \StrBefore[1]{1b2b3}{b}\par + \StrBefore[2]{1b2b3}{b} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrBehind} +\verbinline|\StrBehind|\etoile\arguC{nombre}\ARGU{chaine}\ARGU{chaineA}\arguC{nom} +\smallskip + +L'argument optionnel \argu{nombre} vaut 1 par défaut.\par\nobreak\smallskip +Dans \argu{chaine}, renvoie ce qui se trouve après l'occurrence \no\argu{nombre} de \argu{chaineA}.\medskip + +\begin{Conditions} + \item Si \argu{chaine} ou \argu{chaineA} est vide, une chaîne vide est renvoyée; + \item Si \argu{nombre}${}<1$ alors, la macro se comporte comme si \argu{nombre}${}=1$; + \item Si l'occurrence n'est pas trouvée, une chaîne vide est renvoyée. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrBehind{xstring}{tri} +\StrBehind{LaTeX}{e} +|\StrBehind{LaTeX}{p}| +|\StrBehind{LaTeX}{X}| +|\StrBehind{a bc def }{bc}| +|\StrBehind{a bc def }{cd}| +\StrBehind[1]{1b2b3}{b} +\StrBehind[2]{1b2b3}{b} +|\StrBehind[3]{1b2b3}{b}| +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrBehind{xstring}{tri}\par + \StrBehind{LaTeX}{e}\par + |\StrBehind{LaTeX}{p}|\par + |\StrBehind{LaTeX}{X}|\par + |\StrBehind{a bc def }{bc}|\par + |\StrBehind{a bc def }{cd}|\par + \StrBehind[1]{1b2b3}{b}\par + \StrBehind[2]{1b2b3}{b}\par + |\StrBehind[3]{1b2b3}{b}| +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrCut} +Voici la syntaxe de cette macro :\par\nobreak\smallskip +\verbinline|\StrCut|\etoile\arguC{nombre}\ARGU{chaine}\ARGU{chaineA}\ARGU{macroA}\ARGU{macroB} +\smallskip + +L'argument optionnel \argu{nombre} vaut 1 par défaut.\par\nobreak\smallskip +La \argu{chaine} est coupée en deux chaînes à l'occurrence \no\arguC{nombre} de la \ARGU{chaineA}. Ce qui se trouve à gauche de cette occurrence est assigné à la séquence de contrôle \argu{macroA} et ce qui se trouve à droite à \argu{macroB}. + +Cette macro renvoie \emph{deux chaînes} et donc \textbf{n'affiche rien}. Par conséquent, elle ne dispose pas de l'argument optionnel en dernière position.\medskip + +\begin{Conditions} + \item Si \argu{chaine} ou \argu{chaineA} est vide, \argu{macroA} et\argu{macroB} seront vides ; + \item Si \argu{nombre}${}<1$ alors, la macro se comporte comme si \argu{nombre}${}=1$; + \item Si l'occurrence n'est pas trouvée, \argu{macroA} reçoit la totalité de \argu{chaine} tandis que \argu{macroB} est vide. +\end{Conditions} +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrCut{abracadabra}{a}\csA\csB |\csA|\csB|\par +\StrCut[2]{abracadabra}{a}\csA\csB |\csA|\csB|\par +\StrCut[3]{abracadabra}{a}\csA\csB |\csA|\csB|\par +\StrCut[4]{abracadabra}{a}\csA\csB |\csA|\csB|\par +\StrCut[5]{abracadabra}{a}\csA\csB |\csA|\csB|\par +\StrCut[6]{abracadabra}{a}\csA\csB |\csA|\csB|\par +\StrCut[-4]{abracadabra}{a}\csA\csB |\csA|\csB|\par +\StrCut{abracadabra}{brac}\csA\csB |\csA|\csB|\par +\StrCut{abracadabra}{foo}\csA\csB |\csA|\csB|\par +\StrCut{abracadabra}{}\csA\csB |\csA|\csB| +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \def\seprouge{{\color{red}|}} + \styleexemple + \StrCut{abracadabra}{a}\csA\csB |\csA\seprouge\csB|\par + \StrCut[2]{abracadabra}{a}\csA\csB |\csA\seprouge\csB|\par + \StrCut[3]{abracadabra}{a}\csA\csB |\csA\seprouge\csB|\par + \StrCut[4]{abracadabra}{a}\csA\csB |\csA\seprouge\csB|\par + \StrCut[5]{abracadabra}{a}\csA\csB |\csA\seprouge\csB|\par + \StrCut[6]{abracadabra}{a}\csA\csB |\csA\seprouge\csB|\par + \StrCut[-4]{abracadabra}{a}\csA\csB |\csA\seprouge\csB|\par + \StrCut{abracadabra}{brac}\csA\csB |\csA\seprouge\csB|\par + \StrCut{abracadabra}{foo}\csA\csB |\csA\seprouge\csB|\par + \StrCut{abracadabra}{}\csA\csB |\csA\seprouge\csB| +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrBetween} +\verbinline|\StrBetween|\etoile\arguCC{nombre1}{nombre2}\ARGU{chaine}\ARGU{chaineA}\ARGU{chaineB}\arguC{nom} +\smallskip + +Les arguments optionnels \argu{nombre1} et \argu{nombre2} valent 1 par défaut.\par\nobreak\smallskip +Dans \argu{chaine}, renvoie ce qui se trouve entre\footnote{Au sens strict, c'est-à -dire \emph{sans} les chaînes frontière} les occurrences \no\argu{nombre1} de \argu{chaineA} et \no \argu{nombre2} de \argu{chaineB}.\medskip + +\begin{Conditions} + \item Si les occurrences ne sont pas dans l'ordre (\argu{chaineA} \emph{puis} \argu{chaineB}) dans \argu{chaine}, une chaîne vide est renvoyée; + \item Si l'une des 2 occurrences n'existe pas dans \argu{chaine}, une chaîne vide est renvoyée; + \item Si l'un des arguments optionnels \argu{nombre1} ou \argu{nombre2} est négatif ou nul, une chaîne vide est renvoyée. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrBetween{xstring}{xs}{ng} +|\StrBetween{xstring}{i}{n}| +|\StrBetween{xstring}{a}{tring}| +|\StrBetween{a bc def }{a}{d}| +|\StrBetween{a bc def }{a }{f}| +\StrBetween{a1b1a2b2a3b3}{a}{b} +\StrBetween[2,3]{a1b1a2b2a3b3}{a}{b} +\StrBetween[1,3]{a1b1a2b2a3b3}{a}{b} +|\StrBetween[3,1]{a1b1a2b2a3b3}{a}{b}| +\StrBetween[3,2]{abracadabra}{a}{bra} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrBetween{xstring}{xs}{ng}\par + |\StrBetween{xstring}{i}{n}|\par + |\StrBetween{xstring}{a}{tring}|\par + |\StrBetween{a bc def }{a}{d}|\par + |\StrBetween{a bc def }{a }{f}|\par + \StrBetween{a1b1a2b2a3b3}{a}{b}\par + \StrBetween[2,3]{a1b1a2b2a3b3}{a}{b}\par + \StrBetween[1,3]{a1b1a2b2a3b3}{a}{b}\par + |\StrBetween[3,1]{a1b1a2b2a3b3}{a}{b}|\par + \StrBetween[3,2]{abracadabra}{a}{bra}\par +\end{minipage}% + + + +\subsubsection{\ttfamily\textbackslash StrSubstitute} +\verbinline|\StrSubstitute|\arguC{nombre}\ARGU{chaine}\ARGU{chaineA}\ARGU{chaineB}\arguC{nom} +\smallskip + +L'argument optionnel \argu{nombre} vaut 0 par défaut.\par\nobreak\smallskip +Dans \argu{chaine}, la macro remplace les \argu{nombre} premières occurrences de \argu{chaineA} par \argu{chaineB}, sauf si \argu{nombre}${}=0$ auquel cas, \emph{toutes} les occurrences sont remplacées. + +\begin{Conditions} + \item Si \argu{chaine} est vide, une chaîne vide est renvoyée; + \item Si \argu{chaineA} est vide ou n'existe pas dans \argu{chaine}, la macro est sans effet; + \item Si \argu{nombre} est supérieur au nombre d'occurrences de \argu{chaineA}, alors toutes les occurrences sont remplacées; + \item Si \argu{nombre}${}<0$ alors la macro se comporte comme si \argu{nombre}${}=0$; + \item Si \argu{chaineB} est vide, alors les occurrences de \argu{chaineA}, si elles existent, sont supprimées. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrSubstitute{xstring}{i}{a} +\StrSubstitute{abracadabra}{a}{o} +\StrSubstitute{abracadabra}{br}{TeX} +\StrSubstitute{LaTeX}{m}{n} +\StrSubstitute{a bc def }{ }{M} +\StrSubstitute{a bc def }{ab}{AB} +\StrSubstitute[1]{a1a2a3}{a}{B} +\StrSubstitute[2]{a1a2a3}{a}{B} +\StrSubstitute[3]{a1a2a3}{a}{B} +\StrSubstitute[4]{a1a2a3}{a}{B} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrSubstitute{xstring}{i}{a}\par + \StrSubstitute{abracadabra}{a}{o}\par + \StrSubstitute{abracadabra}{br}{TeX}\par + \StrSubstitute{LaTeX}{m}{n}\par + \StrSubstitute{a bc def }{ }{M}\par + \StrSubstitute{a bc def }{ab}{AB}\par + \StrSubstitute[1]{a1a2a3}{a}{B}\par + \StrSubstitute[2]{a1a2a3}{a}{B}\par + \StrSubstitute[3]{a1a2a3}{a}{B}\par + \StrSubstitute[4]{a1a2a3}{a}{B} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrDel} +\verbinline|\StrDel|\arguC{nombre}\ARGU{chaine}\ARGU{chaineA}\arguC{nom} +\smallskip + +L'argument optionnel \argu{nombre} vaut 0 par défaut.\par\nobreak\smallskip +Supprime les \argu{nombre} premières occurrences de \argu{chaineA} dans \argu{chaine}, sauf si \argu{nombre}${}=0$ auquel cas, \emph{toutes} les occurrences sont supprimées.\medskip + +\begin{Conditions} + \item Si \argu{chaine} est vide, une chaîne vide est renvoyée; + \item Si \argu{chaineA} est vide ou n'existe pas dans \argu{chaine}, la macro est sans effet; + \item Si \argu{nombre} est supérieur au nombre d'occurrences de \argu{chaineA}, alors toutes les occurrences sont supprimées; + \item Si \argu{nombre}${}<0$ alors la macro se comporte comme si \argu{nombre}${}=0$; +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrDel{abracadabra}{a} +\StrDel[1]{abracadabra}{a} +\StrDel[4]{abracadabra}{a} +\StrDel[9]{abracadabra}{a} +\StrDel{a bc def }{ } +|\StrDel{a bc def }{def}| +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrDel{abracadabra}{a}\par + \StrDel[1]{abracadabra}{a}\par + \StrDel[4]{abracadabra}{a}\par + \StrDel[9]{abracadabra}{a}\par + \StrDel{a bc def }{ }\par + |\StrDel{a bc def }{def}| +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrGobbleLeft} +\verbinline|\StrGobbleLeft|\ARGU{chaine}\ARGU{nombre}\arguC{nom} +\smallskip + +Dans \argu{chaine}, enlève les \argu{nombre} premieres \USs de gauche.\medskip + +\begin{Conditions} + \item Si \argu{chaine} est vide, renvoie une chaîne vide; + \item Si \argu{nombre}${}\leqslant0$, aucune \US n'est supprimée; + \item Si \argu{nombre}${}\geqslant{}$\argu{longueurChaine}, toutes les \USs sont supprimées. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrGobbleLeft{xstring}{2} +|\StrGobbleLeft{xstring}{9}| +\StrGobbleLeft{LaTeX}{4} +\StrGobbleLeft{LaTeX}{-2} +|\StrGobbleLeft{a bc def }{4}| +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrGobbleLeft{xstring}{2}\par + |\StrGobbleLeft{xstring}{9}|\par + \StrGobbleLeft{LaTeX}{4}\par + \StrGobbleLeft{LaTeX}{-2}\par + |\StrGobbleLeft{a bc def }{4}| +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrLeft} +\verbinline|\StrLeft|\ARGU{chaine}\ARGU{nombre}\arguC{nom} +\smallskip + +Dans \argu{chaine}, renvoie la sous-chaîne de gauche de longueur \argu{nombre}.\medskip + +\begin{Conditions} + \item Si \argu{chaine} est vide, renvoie une chaîne vide; + \item Si \argu{nombre}${}\leqslant0$, aucune \US n'est retournée; + \item Si \argu{nombre}${}\geqslant{}$\argu{longueurChaine}, toutes les \USs sont retournées. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrLeft{xstring}{2} +\StrLeft{xstring}{9} +\StrLeft{LaTeX}{4} +|\StrLeft{LaTeX}{-2}| +|\StrLeft{a bc def }{5}| +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrLeft{xstring}{2}\par + \StrLeft{xstring}{9}\par + \StrLeft{LaTeX}{4}\par + |\StrLeft{LaTeX}{-2}|\par + |\StrLeft{a bc def }{5}| +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrGobbleRight} +\verbinline|\StrGobbleRight|\ARGU{chaine}\ARGU{nombre}\arguC{nom} +\smallskip + +Agit comme \verbinline|\StrGobbleLeft|, mais enlève les \USs à droite de \argu{chaine}. + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrGobbleRight{xstring}{2} +|\StrGobbleRight{xstring}{9}| +\StrGobbleRight{LaTeX}{4} +|\StrGobbleRight{LaTeX}{-2}| +|\StrGobbleRight{a bc def }{4}| +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrGobbleRight{xstring}{2}\par + |\StrGobbleRight{xstring}{9}|\par + \StrGobbleRight{LaTeX}{4}\par + |\StrGobbleRight{LaTeX}{-2}|\par + |\StrGobbleRight{a bc def }{4}| +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrRight} +\verbinline|\StrRight|\ARGU{chaine}\ARGU{nombre}\arguC{nom} +\smallskip + +Agit comme \verbinline|\StrLeft|, mais renvoie les \USs à la droite de \argu{chaine}. + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrRight{xstring}{2} +\StrRight{xstring}{9} +\StrRight{LaTeX}{4} +|\StrRight{LaTeX}{-2}| +\StrRight{a bc def }{5} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrRight{xstring}{2}\par + \StrRight{xstring}{9}\par + \StrRight{LaTeX}{4}\par + |\StrRight{LaTeX}{-2}|\par + \StrRight{a bc def }{5} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrChar} +\verbinline|\StrChar|\ARGU{chaine}\ARGU{nombre}\arguC{nom} +\smallskip + +Renvoie l'\US à la position \argu{nombre} dans la chaîne \argu{chaine}.\medskip + +\begin{Conditions} + \item Si \argu{chaine} est vide, aucune \US n'est renvoyée; + \item Si \argu{nombre}${}\leqslant0$ ou si \argu{nombre}${}>{}$\argu{longueurChaine}, aucune \US n'est renvoyée. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrChar{xstring}{4} +|\StrChar{xstring}{9}| +|\StrChar{xstring}{-5}| +\StrChar{a bc def }{6} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrChar{xstring}{4}\par + |\StrChar{xstring}{9}|\par + |\StrChar{xstring}{-5}|\par + \StrChar{a bc def }{6} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrMid} +\verbinline|\StrMid|\ARGU{chaine}\ARGU{nombre1}\ARGU{nombre2}\arguC{nom} +\smallskip + +Dans \argu{chaine}, renvoie la sous chaîne se trouvant entre\footnote{Au sens large, c'est-à -dire que les chaînes \guill{frontière} sont renvoyés.} les positions \argu{nombre1} et \argu{nombre2}.\medskip + +\begin{Conditions} + \item Si \argu{chaine} est vide, une chaîne vide est renvoyée; + \item Si \argu{nombre1}${}>{}$\argu{nombre2}, alors rien n'est renvoyé; + \item Si \argu{nombre1}${}<1$ et \argu{nombre2}${}<1$ alors rien n'est renvoyé; + \item Si \argu{nombre1}${}>{}$\argu{longueurChaine} et \argu{nombre2}${}>{}$\argu{longueurChaine}, alors rien n'est renvoyé; + \item Si \argu{nombre1}${}<1$, alors la macro se comporte comme si \argu{nombre1}${}=1$; + \item Si \argu{nombre2}${}>{}$\argu{longueurChaine}, alors la macro se comporte comme si \argu{nombre2}${}={}$\argu{longueurChaine}. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrMid{xstring}{2}{5} +\StrMid{xstring}{-4}{2} +|\StrMid{xstring}{5}{1}| +\StrMid{xstring}{6}{15} +\StrMid{xstring}{3}{3} +|\StrMid{a bc def }{2}{7}| +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrMid{xstring}{2}{5}\par + \StrMid{xstring}{-4}{2}\par + |\StrMid{xstring}{5}{1}|\par + \StrMid{xstring}{6}{15}\par + \StrMid{xstring}{3}{3}\par + |\StrMid{a bc def }{2}{7}| +\end{minipage}% + +\subsection{Les macros renvoyant des nombres} +\subsubsection{\ttfamily\textbackslash StrLen} +\verbinline|\StrLen|\ARGU{chaine}\arguC{nom} +\smallskip + +Renvoie la longueur de \argu{chaine}. + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrLen{xstring} +\StrLen{A} +\StrLen{a bc def } +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrLen{xstring}\par + \StrLen{A}\par + \StrLen{a bc def } +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrCount} +\verbinline|\StrCount|\ARGU{chaine}\ARGU{chaineA}\arguC{nom} +\smallskip + +Compte combien de fois \argu{chaineA} est contenue dans \argu{chaine}.\par\medskip + +\begin{Conditions} + \item Si l'un au moins des arguments \argu{chaine} ou \argu{chaineA} est vide, la macro renvoie 0. +\end{Conditions} + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrCount{abracadabra}{a} +\StrCount{abracadabra}{bra} +\StrCount{abracadabra}{tic} +\StrCount{aaaaaa}{aa} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrCount{abracadabra}{a}\par + \StrCount{abracadabra}{bra}\par + \StrCount{abracadabra}{tic}\par + \StrCount{aaaaaa}{aa} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrPosition} +\verbinline|\StrPosition|\arguC{nombre}\ARGU{chaine}\ARGU{chaineA}\arguC{nom} +\smallskip + +L'argument optionnel \argu{nombre} vaut 1 par défaut.\par\nobreak\smallskip +Dans \argu{chaine}, renvoie la position de l'occurrence \no\argu{nombre} de \argu{chaineA}.\medskip + +\begin{Conditions} + \item Si \argu{nombre} est supérieur au nombre d'occurrences de \argu{chaineA}, alors la macro renvoie 0. + \item Si \argu{chaine} ne contient pas \argu{chaineA}, alors la macro renvoie 0. +\end{Conditions} +\medskip + +\begin{minipage}[t]{0.65\linewidth} +\begin{lstlisting} +\StrPosition{xstring}{ring} +\StrPosition[4]{abracadabra}{a} +\StrPosition[2]{abracadabra}{bra} +\StrPosition[9]{abracadabra}{a} +\StrPosition{abracadabra}{z} +\StrPosition{a bc def }{d} +\StrPosition[3]{aaaaaa}{aa} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \StrPosition{xstring}{ring}\par + \StrPosition[4]{abracadabra}{a}\par + \StrPosition[2]{abracadabra}{bra}\par + \StrPosition[9]{abracadabra}{a}\par + \StrPosition{abracadabra}{z}\par + \StrPosition{a bc def }{d}\par + \StrPosition[3]{aaaaaa}{aa} +\end{minipage}% + +\subsubsection{\ttfamily\textbackslash StrCompare} +\verbinline|\StrCompare|\etoile\ARGU{chaineA}\ARGU{chaineB}\arguC{nom} +\smallskip + +Cette macro peut fonctionner avec 2 tolérances, la tolérance \guill{normale} qui est sélectionnée par défaut et la tolérance \guill{stricte}.\medskip + +\begin{itemize} + \item La tolérance normale, activée par la commande \verbinline|\comparenormal|.\par + La macro compare successivement les \US de gauche à droite des chaînes \argu{chaineA} et \argu{chaineB} jusqu'à ce qu'une différence apparaisse ou que la fin de la plus courte chaîne soit atteinte. Si aucune différence n'est trouvée, la macro renvoie 0. Sinon, la position de la 1\iere{} différence est renvoyée. + \item La tolérance stricte, activée par la commande \verbinline|\comparestrict|.\par + La macro compare les 2 chaînes. Si elles sont égales, elle renvoie 0 sinon la position de la 1\iere{} différence est renvoyée. +\end{itemize} +\smallskip + +L'ordre des 2 chaînes n'a aucune influence sur le comportement de la macro. + +\medskip On peut également mémoriser le mode de comparaison en cours avec \verbinline|\savecomparemode|, le modifier par la suite et revenir à la situation lors de la sauvegarde avec \verbinline|\restorecomparemode|.\medskip + +Exemples en tolérance normale :\par\nobreak +\begin{minipage}[t]{0.65\linewidth} +\comparenormal +\begin{lstlisting} +\StrCompare{abcd}{abcd} +\StrCompare{abcd}{abc} +\StrCompare{abc}{abcd} +\StrCompare{a b c}{abc} +\StrCompare{aaa}{baaa} +\StrCompare{abc}{xyz} +\StrCompare{123456}{123457} +\StrCompare{abc}{} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \comparenormal + \StrCompare{abcd}{abcd}\par + \StrCompare{abcd}{abc}\par + \StrCompare{abc}{abcd}\par + \StrCompare{a b c}{abc}\par + \StrCompare{aaa}{baaa}\par + \StrCompare{abc}{xyz}\par + \StrCompare{123456}{123457}\par + \StrCompare{abc}{} +\end{minipage}% +\medskip + +Exemples en tolérance stricte :\par\nobreak +\begin{minipage}[t]{0.65\linewidth} +\comparestrict +\begin{lstlisting} +\StrCompare{abcd}{abcd} +\StrCompare{abcd}{abc} +\StrCompare{abc}{abcd} +\StrCompare{a b c}{abc} +\StrCompare{aaa}{baaa} +\StrCompare{abc}{xyz} +\StrCompare{123456}{123457} +\StrCompare{abc}{} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[t]{0.35\linewidth} + \styleexemple + \comparestrict + \StrCompare{abcd}{abcd}\par + \StrCompare{abcd}{abc}\par + \StrCompare{abc}{abcd}\par + \StrCompare{a b c}{abc}\par + \StrCompare{aaa}{baaa}\par + \StrCompare{abc}{xyz}\par + \StrCompare{123456}{123457}\par + \StrCompare{abc}{} +\end{minipage}% + +\section{Modes de fonctionnement} +\subsection{Développement des arguments} +\label{devarg} +\lstset{basicstyle=\footnotesize\ttfamily} +\subsubsection{Les macros {\ttfamily \textbackslash fullexpandarg}, {\ttfamily \textbackslash expandarg} et {\ttfamily \textbackslash noexpandarg}} +La macro \verbinline|\fullexpandarg| est appelée par défaut, ce qui fait que certains arguments (en \textcolor{violet}{violet} dans la liste ci dessous) transmis aux macros sont développés le plus possible (pour cela, un \verb|\edef| est utilisé). Ce mode de développement maximal permet dans la plupart des cas d'éviter d'utiliser des chaînes d'\verb|\expandafter|. Le code en est souvent allégé. + +On peut interdire le développement de ces arguments (et ainsi revenir au comportement normal de \TeX) en invoquant \verbinline|\noexpandarg| ou \verbinline|\normalexpandarg| qui sont synonymes.\medskip + +Il existe enfin un autre mode de développement de ces arguments que l'on appelle avec \verbinline|\expandarg|. Dans ce cas, le \textbf{premier token} de ces arguments est développé \emph{une fois} avant que la macro ne soit appelée. Si l'argument contient plus d'un token, les tokens qui suivent le premier ne sont pas développés (on peut contourner cette volontaire limitation et utiliser la macro \verbinline|\StrExpand|, voir page~\pageref{scancs}).\medskip + +Les commandes \verbinline|\fullexpandarg|, \verbinline|\noexpandarg|, \verbinline|\normalexpandarg| et \verbinline|\expandarg| peuvent être appelées à tout moment dans le code et fonctionnent comme des bascules. On peut rendre leur portée locale dans un groupe.\medskip + +On peut également mémoriser le mode de développement en cours avec \verbinline|\saveexpandmode|, le modifier par la suite et revenir à la situation lors de la sauvegarde avec \verbinline|\restoreexpandmode|.\medskip + +Dans la liste ci-dessous, on peut voir en \textcolor{violet}{violet} quels arguments sont soumis à l'éventuel développement pour chaque macro vue dans le chapitre précedent : + +\nobreak\smallskip +\parindent3em +\begin{itemize} + \item\verb|\IfSubStr|\etoile{\colorise\arguC{nombre}\ARGU{chaine}\ARGU{chaineA}}\ARGU{vrai}\ARGU{faux} + \item\verb|\IfSubStrBefore|\etoile{\colorise\arguCC{nombre1}{nombre2}\ARGU{chaine}\ARGU{chaineA}\ARGU{chaineB}}\ARGU{vrai}\ARGU{faux} + \item\verb|\IfSubStrBehind|\etoile{\colorise\arguCC{nombre1}{nombre2}\ARGU{chaine}\ARGU{chaineA}\ARGU{chaineB}}\ARGU{vrai}\ARGU{faux} + \item\verb|\IfBeginWith|\etoile{\colorise\ARGU{chaine}\ARGU{chaineA}}\ARGU{vrai}\ARGU{faux} + \item\verb|\IfEndWith|\etoile{\colorise\ARGU{chaine}\ARGU{chaineA}}\ARGU{vrai}\ARGU{faux} + \item\verb|\IfInteger|{\colorise\ARGU{nombre}}\ARGU{vrai}\ARGU{faux} + \item\verb|\IfDecimal|{\colorise\ARGU{nombre}}\ARGU{vrai}\ARGU{faux} + \item\verb|\IfStrEq|\etoile{\colorise\ARGU{chaineA}\ARGU{chaineB}}\ARGU{vrai}\ARGU{faux} + \item\verb|\IfEq|\etoile{\colorise\ARGU{chaineA}\ARGU{chaineB}}\ARGU{vrai}\ARGU{faux} + \item\verb|\IfStrEqCase|\etoile{\colorise\ARGU{chaine}\texttt{\color{black}\{}\colorise\ARGU{chaine1}}\ARGU{code1}\par + \setbox0=\hbox{{\ttfamily\string\IfStrEqCase}\etoile\ARGU{chaine}{\ttfamily\{}} + \hskip\wd0{\colorise\ARGU{chaine2}}\ARGU{code2}\par + \hskip\wd0\ \ldots\par + \hskip\wd0{\colorise\ARGU{chaine $n$}}\ARGU{code $n$}\verb|}|\arguC{code alternatif} + \item\verb|\IfEqCase|\etoile{\colorise\ARGU{chaine}\texttt{\color{black}\{}\colorise\ARGU{chaine1}}\ARGU{code1}\par + \setbox0=\hbox{{\ttfamily\string\IfEqCase}\etoile\ARGU{chaine}{\ttfamily\{}} + \hskip\wd0{\colorise\ARGU{chaine2}}\ARGU{code2}\par + \hskip\wd0\ \ldots\par + \hskip\wd0{\colorise\ARGU{chaine $n$}}\ARGU{code $n$}\verb|}|\arguC{code alternatif} + \item\verb|\StrBefore|\etoile{\colorise\arguC{nombre}\ARGU{chaine}\ARGU{chaineA}}\arguC{nom} + \item\verb|\StrBehind|\etoile{\colorise\arguC{nombre}\ARGU{chaine}\ARGU{chaineA}}\arguC{nom} + \item\verb|\StrBetween|\etoile{\colorise\arguCC{nombre1}{nombre2}\ARGU{chaine}\ARGU{chaineA}\ARGU{chaineB}}\arguC{nom} + \item\verb|\StrSubstitute|{\colorise\arguC{nombre}\ARGU{chaine}\ARGU{chaineA}\ARGU{chaineB}}\arguC{nom} + \item\verb|\StrDel|{\colorise\arguC{nombre}\ARGU{chaine}\ARGU{chaineA}}\arguC{nom} + \item\verb|\StrSplit|{\colorise\ARGU{chaine}\ARGU{nombre}}\ARGU{chaineA}\ARGU{chaineB}\qquad{\small(voir page~\pageref{StrSplit} pour la macro \verb|StrSplit|)} + \item\verb|\StrGobbleLeft|{\colorise\ARGU{chaine}\ARGU{nombre}}\arguC{nom} + \item\verb|\StrLeft|{\colorise\ARGU{chaine}\ARGU{nombre}}\arguC{nom} + \item\verb|\StrGobbleRight|{\colorise\ARGU{chaine}\ARGU{nombre}}\arguC{nom} + \item\verb|\StrRight|{\colorise\ARGU{chaine}\ARGU{nombre}}\arguC{nom} + \item\verb|\StrChar|{\colorise\ARGU{chaine}\ARGU{nombre}}\arguC{nom} + \item\verb|\StrMid|{\colorise\ARGU{chaine}\ARGU{nombre1}\ARGU{nombre2}}\arguC{nom} + \item\verb|\StrLen|{\colorise\ARGU{chaine}}\arguC{nom} + \item\verb|\StrCount|{\colorise\ARGU{chaine}\ARGU{chaineA}}\arguC{nom} + \item\verb|\StrPosition|{\colorise\arguC{nombre}\ARGU{chaine}\ARGU{chaineA}}\arguC{nom} + \item\verb|\StrCompare|{\colorise\ARGU{chaineA}\ARGU{chaineB}}\arguC{nom} +\end{itemize} +\parindent0pt + +\subsubsection{Caractères et lexèmes autorisés dans les arguments} +Tout d'abord, quelque soit le mode de développement choisi, \textbf{les tokens de catcode 6 et 14 (habituellement {\ttfamily\#} et {\ttfamily\%}) sont interdits dans tous les arguments}\footnote{Le token {\ttfamily\#} sera peut-être autorisé dans une future version !}.\bigskip + +Lorsque le mode \verbinline|\fullexpandarg| est activé, les arguments sont évalués à l'aide de la primitive \verb|\edef| avant d'être transmis aux macros. Par conséquent, sont autorisés dans les arguments : + +\nobreak\smallskip\parindent3em +\begin{itemize} + \item les lettres, majuscules, minuscules, accentuées\footnote{Pour pouvoir utiliser des lettres accentuées de façon fiable, il est nécessaire de charger le packages \texttt{\string\fontenc} avec l'option \texttt{[T1]}, ainsi que \texttt{\string\inputenc} avec l'option correspondant au codage du fichier tex.} ou non, les chiffres, les espaces\footnote{Selon la règle \TeX{}iènne, plusieurs espaces consécutifs n'en font qu'un.} ainsi que tout autre token de catcode 10, 11 ou 12 (signes de ponctuation, signes opératoires mathématiques, parenthèses, crochets, etc); + \item les tokens de catcode 1 à 4, qui sont habituellement : \og\verb|{|\fg\quad\og\verb|}|\fg\footnote{Attention : les accolades \textbf{doivent} être équilibrées dans les arguments !}\quad\og\verb|$|\fg\quad\og\verb|&|\fg + \item les tokens de catcode 7 et 8, qui sont habituellement : \og\verb|^|\fg\quad\og\verb|_|\fg + \item toute séquence de contrôle si elle est purement développable\footnote{C'est-à -dire qu'elle peut être mise à l'intérieur d'un {\ttfamily\string\edef }.} et dont le développement maximal donne des caractères autorisés; + \item un token de catcode 13 (caractère actif) s'il est purement développable. +\end{itemize} +\parindent0pt\smallskip + +Lorsque les arguments ne sont plus développés (utilisation de \verbinline|\noexpandarg|), on peut aussi inclure dans les arguments n'importe quel token, quelque soit le code qui en résulte comme par exemple toute séquence de contrôle, même non définie ou tout token de catcode 13. On peut également inclure dans les arguments des tokens de test comme \verbinline|\if| ou \verbinline|\ifx| ou tout autre token de test, même sans leur \verbinline|\fi| correspondant; ou bien un \verbinline|\csname| sans le \verbinline|\endcsname| correspondant. + +Dans l'exemple suivant, l'argument contient un \verbinline|\ifx| \emph{sans} le \verbinline|\fi|, et l'on isole ce qui est entre le \verbinline|\ifx| et le \verbinline|\else| :\par\medskip\nobreak + +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\noexpandarg +\StrBetween{\ifx ab faux \else vrai}{\ifx}{\else} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \noexpandarg + \StrBetween{\ifx ab faux \else vrai}{\ifx}{\else} +\end{minipage} +\medskip + +Lorsqu'on utilise \verbinline|\expandarg|, la précaution concerne le premier token qui est développé une fois et doit donc être défini. Les autres tokens sont laissés tel quels comme avec \verbinline|\noexpandarg|. + +\subsection{Développement des macros, argument optionnel} +\label{argumentoptionnel} +Les macros de ce package ne sont pas purement développables et ne peuvent donc pas être mises dans l'argument d'un \verb|\edef|. L'imbrication des macros de ce package n'est pas permise non plus.\medskip + +C'est pour cela que les macros renvoyant un résultat, c'est-à -dire toutes sauf les tests, sont dotées d'un argument optionnel venant en dernière position. Cet argument prend la forme de \arguC{nom}, où \argu{nom} est une séquence de contrôle qui recevra (l'assignation se fait avec un \verb|\edef|) le résultat de la macro, ce qui fait que \argu{nom} est purement développable et peut donc se trouver dans l'argument d'un \verb|\edef|. Dans le cas de la présence d'un argument optionnel en dernière position, aucun affichage n'aura lieu. Cela permet donc contourner les limitations évoquées dans les exemples ci dessus.\medskip + +Ainsi cette construction non permise censée assigner à \verb|\Resultat| les 4 caractères de gauche de \verb|xstring| :\par\nobreak +\hspace{0.2\linewidth}\verbinline|\edef\Resultat{\StrLeft{xstring}{4}}|\par\nobreak +\qquad est équivalente à :\par\nobreak +\hspace{0.2\linewidth}\verbinline|\StrLeft{xstring}{4}[\Resultat]|\medskip + +Et cette imbrication non permise censée enlever le premier et le dernier caractère de \verb|xstring| :\par\nobreak +\hspace{0.2\linewidth}\verbinline|\StrGobbleLeft{\StrGobbleRight{xstring}{1}}{1}|\par\nobreak +\qquad se programme ainsi :\par\nobreak +\hspace{0.2\linewidth}\verbinline|\StrGobbleRight{xstring}{1}[\machaine]|\par\nobreak +\hspace{0.2\linewidth}\verbinline|\StrGobbleLeft{\machaine}{1}|\par + +\subsection{Traitement des arguments} +\label{developpementarguments} +\subsubsection{Traitement à l'\US prés} +Les macros de \Xstring traitent les arguments \US par \US. Dans le code \TeX{}, une \US\footnote{Pour les utilisateurs familiers avec la programmation \LaTeX, une \US est ce qui est supprimé par la macro \texttt{\string\@gobble} dont le code, d'une grande simplicité, est : {\ttfamily\string\def\string\@gobble\string#1\string{\string}}} est soit :\par\nobreak\smallskip\parindent3em +\begin{itemize} + \item une séquence de contrôle; + \item un groupe, c'est à dire une suite de tokens située entre deux accolades équilibrées; + \item un caractère ne faisant pas partie des 2 espèces ci dessus. +\end{itemize} +\medskip\parindent0pt + +Voyons ce qu'est la notion d'\US sur un exemple. Prenons cet argument : \og\verb|ab\textbf{xyz}cd|\fg + +\nobreak Il contient 6 \USs qui sont : \og\verb|a|\fg, \og\verb|b|\fg, \og\verb|\textbf|\fg, \og\verb|{xyz}|\fg, \og\verb|c|\fg{} et \og\verb|d|\fg. + +\nobreak\medskip Que va t-il arriver si l'on se place sous \verbinline|\noexpandarg| et que l'on demande à \Xstring de trouver la longueur de cet argument et d'en trouver le 4\ieme{} \guill{caractère} ?\medskip + +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\noexpandarg +\StrLen{ab\textbf{xyz}cd}\par +\StrChar{ab\textbf{xyz}cd}{4}[\mychar] +\meaning\mychar +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \noexpandarg + \StrLen{ab\textbf{xyz}cd}\par + \StrChar{ab\textbf{xyz}cd}{4}[\mychar] + \meaning\mychar +\end{minipage}% +\fullexpandarg +\medskip + +Il est nécessaire d'utiliser \verb|\meaning| pour bien visualiser le véritable contenu de \verb|\mychar| et non pas de simplement d'appeler cette séquence de contrôle, ce qui fait perdre des informations ---~les accolades ici. On voit qu'on n'obtient pas vraiment un \guill{caractère}, mais cela était prévisible : il s'agit d'une \US. + +\subsubsection{Exploration des groupes} +Par défaut, la commande \verbinline|\noexploregroups| est appelée et donc dans l'argument à examiner qui contient la chaîne de tokens, \Xstring considère les groupes entre accolades comme \USs fermées dans lesquelles \Xstring ne regarde pas. + +Pour certains besoins spécifiques, il peut être nécessaire de modifier le mode de lecture des arguments et d'explorer l'intérieur des groupes entre accolades. Pour cela on peut invoquer \verbinline|\exploregroups|.\medskip + +Que va donner ce nouveau mode d'exploration sur l'exemple précédent ? \Xstring ne va plus compter le groupe comme une seule \US mais va compter les \USs se trouvant à l'intérieur, et ainsi de suite s'il y avait plusieurs niveaux d'imbrication de groupes: + +\nobreak\smallskip +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\noexpandarg +\exploregroups +\StrLen{ab\textbf{xyz}cd}\par +\StrChar{ab\textbf{xyz}cd}{4}[\mychar] +\meaning\mychar +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \noexpandarg + \exploregroups + \StrLen{ab\textbf{xyz}cd}\par + \StrChar{ab\textbf{xyz}cd}{4}[\mychar] + \meaning\mychar +\end{minipage}% +\fullexpandarg\noexploregroups +\medskip + +L'exploration des groupes peut se réveler utile pour le comptage, le calcul de position ou les tests, mais comporte une limitation lorsque l'on appelle des macros renvoyant des chaînes : lorsqu'un argument est coupé à l'intérieur d'un groupe, alors \textbf{le résultat ne tient pas compte de ce qui se trouve à l'extérieur de ce groupe}. Il faut donc utiliser ce mode en connaissance de cause lorsque l'on utilise les macros renvoyant des chaînes. + +Voyons ce que cela signifie sur un exemple : mettons que l'on veuille renvoyer ce qui se trouve à droite de la 2\ieme{} occurrence de \verb|\a| dans l'argument \verb|\a1{\b1\a2}\a3|. Comme l'on explore les groupes, cette occurrence se trouve à l'intérieur du groupe \verb|{\b1\a2}|. Le résultat renvoyé sera donc : \verb|\b1|. Vérifions-le : + + + +L'exploration des groupes\footnote{On peut consulter le fichier de test de \Xstring qui comporte de nombreux exemples et met en évidence les différences selon le mode d'exploration des groupes.} peut ainsi changer le comportement de la plupart des macros de \Xstring, à l'exception de \verbinline|\IfInteger|, \verbinline|\IfDecimal|, \verbinline|\IfStrEq|, \verbinline|\IfEq| et \verbinline|\StrCompare| qui sont insensibles au mode d'exploration en cours. + +De plus, pour des raison d'équilibrage d'accolades, 2 macros n'opèrent qu'en mode \verbinline|\noexploregroups|, quelque soit le mode d'exploration en cours : \verbinline|\StrBetween| et \verbinline|\StrMid|.\medskip + +On peut mémoriser le mode de d'exploration en cours avec \verbinline|\saveexploremode|, le modifier par la suite et revenir à la situation lors de la sauvegarde avec \verbinline|\restoreexploremode|. + +\subsection{Catcodes et macros étoilées} +\label{macrosetoilees} +Les macros de \Xstring tiennent compte des catcodes des tokens constituant les arguments. Il faut donc garder à l'esprit, particulièrement lors des tests, que les tokens \emph{et leurs catcodes} sont examinés.\medskip + +Par exemple, ces 2 arguments :\par\nobreak\smallskip +\hfil\verb|{\string a\string b}|\qquad et\qquad\verb|{ab}|\hfil{}\par\smallskip +ne se développent pas en 2 arguments égaux aux yeux de \Xstring. Dans le premier cas, à cause de l'emploi de la primitive \verb|\string|, les caractères \og\verb|ab|\fg{} ont un catcode de 12 alors que dans l'autre cas, ils ont leurs catcodes naturels de 11. Il convient donc d'être conscient de ces subtilités lorsque l'on emploie des primitives dont les résultats sont des chaînes de caractères ayant des catcodes de 12 et 10. Ces primitives sont par exemple : \verb|\string|, \verb|\detokenize|, \verb|\meaning|, \verb|\jobname|, \verb|\fontname|, \verb|\romannumeral|, etc.\medskip + +Pour demander aux macros de ne pas tenir compte des catcodes, on peut utiliser les macros étoilées. Après l'éventuel développement des arguments en accord avec le mode de développement, celles-ci convertissent (à l'aide d'un \verb|\detokenize|) leur arguments en chaînes de caractères dont les catcodes sont 12 et 10 pour l'espace, avant que la macro non étoilée travaille sur ces arguments ainsi modifiés. Il faut noter que les arguments optionnels ne sont pas concernés par ces modifications et gardent leur catcode.\smallskip + +Voici un exemple :\par\nobreak\smallskip +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\IfStrEq{\string a\string b}{ab}{vrai}{faux}\par +\IfStrEq*{\string a\string b}{ab}{vrai}{faux} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \IfStrEq{\string a\string b}{ab}{vrai}{faux}\par + \IfStrEq*{\string a\string b}{ab}{vrai}{faux} +\end{minipage}% +\smallskip + +Les chaînes n'étant pas égales à cause des catcodes, le test est bien \emph{négatif} dans la version non étoilée.\bigskip + +\textbf{Attention} : utiliser une macro étoilée a des conséquenses ! Les arguments sont \guill{détokénisés}, il n'y a donc plus de séquence de contrôle, plus de goupes, ni aucun caractère de catcode spécial puisque tout est converti en caractères \guill{inoffensifs} ayant le même catcode.\medskip + +Ainsi, pour les macros renvoyant une chaîne, si on emploie les versions étoilées, le résultat sera une chaîne de caractères dont les catcodes sont 12, et 10 pour l'espace. + +Et donc, après un \og\verbinline|\StrBefore*{a \b c d}{c}[\montexte]|\fg{}, la séquence de contrôle \verb|\montexte| se développera en \og{}\verb|a|${}_{12}$\verb*| |${}_{10}$\verb|\|${}_{12}$\verb|b|${}_{12}$\verb*| |${}_{10}$\fg{}.\medskip + +Les macros détokenisant leur arguments par l'utilisation de l'étoile sont présentées dans la liste ci-dessous. Pour chacune d'entre elles, on peut voir en \textcolor{violet}{violet} quels arguments seront détokenisé lorsque l'étoile sera employée : + +\nobreak\smallskip\parindent3em +\begin{itemize} + \item\verb|\IfSubStr|\etoile\arguC{nombre}{\colorise\ARGU{chaine}\ARGU{chaineA}}\ARGU{vrai}\ARGU{faux} + \item\verb|\IfSubStrBefore|\etoile\arguCC{nombre1}{nombre2}{\colorise\ARGU{chaine}\ARGU{chaineA}\ARGU{chaineB}}\ARGU{vrai}\ARGU{faux} + \item\verb|\IfSubStrBehind|\etoile\arguCC{nombre1}{nombre2}{\colorise\ARGU{chaine}\ARGU{chaineA}\ARGU{chaineB}}\ARGU{vrai}\ARGU{faux} + \item\verb|\IfBeginWith|\etoile{\colorise\ARGU{chaine}\ARGU{chaineA}}\ARGU{vrai}\ARGU{faux} + \item\verb|\IfEndWith|\etoile{\colorise\ARGU{chaine}\ARGU{chaineA}}\ARGU{vrai}\ARGU{faux} + \item\verb|\IfStrEq|\etoile{\colorise\ARGU{chaineA}\ARGU{chaineB}}\ARGU{vrai}\ARGU{faux} + \item\verb|\IfEq|\etoile{\colorise\ARGU{chaineA}\ARGU{chaineB}}\ARGU{vrai}\ARGU{faux} + \item\verb|\IfStrEqCase|\etoile{\colorise\ARGU{chaine}\texttt{\color{black}\{}\colorise\ARGU{chaine1}}\ARGU{code1}\par + \setbox0=\hbox{{\ttfamily\string\IfStrEqCase}\etoile\ARGU{chaine}{\ttfamily\{}} + \hskip\wd0{\colorise\ARGU{chaine2}}\ARGU{code2}\par + \hskip\wd0\ \ldots\par + \hskip\wd0{\colorise\ARGU{chaine $n$}}\ARGU{code $n$}\verb|}|\arguC{code alternatif} + \item\verb|\IfEqCase|\etoile{\colorise\ARGU{chaine}\texttt{\color{black}\{}\colorise\ARGU{chaine1}}\ARGU{code1}\par + \setbox0=\hbox{{\ttfamily\string\IfEqCase}\etoile\ARGU{chaine}{\ttfamily\{}} + \hskip\wd0{\colorise\ARGU{chaine2}}\ARGU{code2}\par + \hskip\wd0\ \ldots\par + \hskip\wd0{\colorise\ARGU{chaine $n$}}\ARGU{code $n$}\verb|}|\arguC{code alternatif} + \item\verb|\StrBefore|\etoile\arguC{nombre}{\colorise\ARGU{chaine}\ARGU{chaineA}}\arguC{nom} + \item\verb|\StrBehind|\etoile\arguC{nombre}{\colorise\ARGU{chaine}\ARGU{chaineA}}\arguC{nom} + \item\verb|\StrBetween|\etoile\arguCC{nombre1}{nombre2}{\colorise\ARGU{chaine}\ARGU{chaineA}\ARGU{chaineB}}\arguC{nom} + \item\verb|\StrCompare|\etoile{\colorise\ARGU{chaineA}\ARGU{chaineB}}\arguC{nom} +\end{itemize} +\parindent0pt + +\section{Macros avancées pour la programmation} +Bien que \Xstring ait la possibilité de lire et traiter des arguments contenant du code \TeX{} ou \LaTeX{} ce qui devrait couvrir la plupart des besoins en programmation, il peut arriver pour des besoins très spécifiques que les macros décritesz précédemment ne suffisent pas. Ce chapitre présente d'autres macros qui permettent d'aller plus loin ou de contourner certaines limitations. +\subsection{Recherche d'un groupe, les macros {\ttfamily\textbackslash StrFindGroup} et {\ttfamily\textbackslash groupID}} +Lorsque le mode \verbinline=\exploregroups= est actif, la macro \verbinline=\StrFindGroup= permet de trouver un groupe entre accolades explicites en spécifiant son identifiant : + +\nobreak\smallskip +\verbinline|\StrFindGroup|\ARGU{argument}\ARGU{identifiant}\arguC{nom}\medskip + +Lorsque le groupe caractérisé par l'identifiant n'existe pas, une chaîne vide sera assignée à la séquence de contrôle \argu{nom}. Si le groupe existe, ce groupe \emph{avec ses accolades} sera assigné à \argu{nom}.\smallskip + +Cet identifiant est une suite d'entiers séparés par des virgules caractérisant le groupe cherché dans l'argument. Le premier entier est le $n$\ieme{} groupe (d'imbrication 1) dans lequel est le groupe cherché. Puis, en se plaçant dans ce groupe, le 2\ieme{} entier est le $n$\ieme{} groupe dans lequel est le groupe cherché. Et ainsi de suite jusqu'à ce que l'imbrication du groupe soit atteinte.\bigskip + +Prenons par exemple l'argument suivant où l'on a 3 niveaux d'imbrication de groupes. Pour plus de clarté, les accolades délimitant les groupes sont colorées en rouge pour l'imbrication de niveau 1, en bleu pour le niveau 2 et en vert pour le niveau 3. Les groupes dans chaque imbrication sont ensuite numérotés selon la règle décrite ci-dessus : +\begingroup + \def\AccO#1{\text{\color{#1}\ttfamily\{}} + \def\AccF#1{\text{\color{#1}\ttfamily\}}} + \def\texte#1{\text{\texttt{\color{black}#1}}} + \def\decalbrace{\vphantom{\underbrace{A}_A}} + \[\texte{a}{\color{red}\underbrace{\AccO{red}{\color{blue}\underbrace{\decalbrace\AccO{blue}\texte{bc}\AccF{blue}}_{\color{blue}1}}\texte{d}{\color{blue}\underbrace{\decalbrace\AccO{blue}\texte{efg}\AccF{blue}}_{\color{blue}2}}\AccF{red}}_{\color{red}1}}\texte{h}{\color{red}\underbrace{\AccO{red}{\color{blue}\underbrace{\decalbrace\AccO{blue}\texte{ij}\AccF{blue}}_{\color{blue}1}}{\color{blue}\underbrace{\decalbrace\AccO{blue}\texte{k}\AccF{blue}}_{\color{blue}2}}{\color{blue}\underbrace{\AccO{blue}\texte{l}{\color{green}\underbrace{\AccO{green}\texte{m}\AccF{green}}_{\color{green}1}}{\color{green}\underbrace{\AccO{green}\texte{no}\AccF{green}}_{\color{green}2}}\AccF{blue}}_{\color{blue}3}}\texte{p}\AccF{red}}_{\color{red}2}}\] +\endgroup +\smallskip +Dans cet exemple : + +\nobreak\parindent3em +\begin{itemize} + \item le groupe \verb={{bc}d{efg}}= a donc pour identifiant \texttt{\color{red}1}; + \item le groupe \verb={ij}= a pour identifiant \texttt{{\color{red}2},\color{blue}1}; + \item le groupe \verb={no}= a pour identifiant \texttt{{\color{red}2},{\color{blue}3},\color{green}2}; + \item l'argument dans sa totalité \og\verb=a{{bc}d{efg}}h{{ij}{k}{l{m}{no}}p}=\fg{} a pour identifiant \verb=0=, seul cas où l'entier 0 est contenu dans l'identifiant d'un groupe. +\end{itemize} +\parindent0pt +\medskip +Voici l'exemple complet :\par\nobreak\smallskip +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\exploregroups +\expandarg +\def\chaine{a{{bc}d{efg}}h{{ij}{k}{l{m}{no}}p}} +\StrFindGroup{\chaine}{1}[\mongroupe] +\meaning\mongroupe\par +\StrFindGroup{\chaine}{2,1}[\mongroupe] +\meaning\mongroupe\par +\StrFindGroup{\chaine}{2,3,2}[\mongroupe] +\meaning\mongroupe\par +\StrFindGroup{\chaine}{2,5}[\mongroupe] +\meaning\mongroupe\par +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \exploregroups + \expandarg + \def\chaine{a{{bc}d{efg}}h{{ij}{k}{l{m}{no}}p}} + \StrFindGroup{\chaine}{1}[\mongroupe] + \meaning\mongroupe\par + \StrFindGroup{\chaine}{2,1}[\mongroupe] + \meaning\mongroupe\par + \StrFindGroup{\chaine}{2,3,2}[\mongroupe] + \meaning\mongroupe\par + \StrFindGroup{\chaine}{2,5}[\mongroupe] + \meaning\mongroupe\par +\end{minipage}% +\bigskip + +Le processus inverse existe, et plusieurs macros de \Xstring donnent aussi comme information l'identifiant du groupe dans lequel elles ont fait une coupure ou trouvé une recherche. Ces macros sont : \verbinline|\IfSubStr|, \verbinline|\StrBefore|, \verbinline|\StrBehind|, \verbinline|\StrSplit|, \verbinline|\StrLeft|, \verbinline|\StrGobbleLeft|, \verbinline|\StrRight|, \verbinline|\StrGobbleRight|, \verbinline|\StrChar|, \verbinline|\StrPosition|.\medskip + +Après l'appel à ces macros, la commande \verbinline|\groupID| se développe en l'identifiant du groupe dans lequel la coupure s'est faite ou la recherche d'un argument a abouti. Lorsque la coupure ne peut avoir lieu ou que la recherche n'a pas abouti, \verbinline|\groupID| est vide. Évidemment, l'utilisation de \verbinline|\groupID| n'a de sens que lorsque le mode \verbinline|\exploregroups| est actif, et quand les macros ne sont pas étoilées.\smallskip + +Voici quelques exemples avec la macro \verbinline|\StrChar| :\par\nobreak\smallskip +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\exploregroups +char 1 = \StrChar{a{b{cd}{e{f}g}h}ijkl}{1}\qquad +\string\groupID = \groupID\par +char 4 = \StrChar{a{b{cd}{e{f}g}h}ijkl}{4}\qquad +\string\groupID = \groupID\par +char 6 = \StrChar{a{b{cd}{e{f}g}h}ijkl}{6}\qquad +\string\groupID = \groupID\par +char 20 = \StrChar{a{b{cd}{e{f}g}h}ijkl}{20}\qquad +\string\groupID = \groupID +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \exploregroups + char 1 = \StrChar{a{b{cd}{e{f}g}h}ijkl}{1}\qquad + \string\groupID = \groupID\par + char 4 = \StrChar{a{b{cd}{e{f}g}h}ijkl}{4}\qquad + \string\groupID = \groupID\par + char 6 = \StrChar{a{b{cd}{e{f}g}h}ijkl}{6}\qquad + \string\groupID = \groupID\par + char 20 = \StrChar{a{b{cd}{e{f}g}h}ijkl}{20}\qquad + \string\groupID = \groupID +\end{minipage} + +\subsection{Coupure d'une chaîne, la macro {\ttfamily\textbackslash StrSplit}} +\label{StrSplit} +Voici la syntaxe de cette macro :\par\nobreak\smallskip +\verbinline|\StrSplit|\ARGU{chaine}\ARGU{nombre}\ARGU{chaineA}\ARGU{chaineB} +\smallskip + +La \argu{chaine}, est coupée en deux chaînes juste après l'\US se situant à la position \argu{nombre}. La partie gauche est assigné à la séquence de contrôle \argu{chaineA} et la partie droite à \argu{chaineB}.\par +Cette macro renvoie \emph{deux chaînes} et donc \textbf{n'affiche rien}. Par conséquent, elle ne dispose pas de l'argument optionnel en dernière position.\medskip + +\begin{Conditions} + \item Si \argu{nombre}${}\leqslant0$, \argu{chaineA} sera vide et \argu{chaineB} contiendra la totalité de \argu{chaine}; + \item Si \argu{nombre}${}\geqslant$\argu{longueurChaine}, \argu{chaineA} contiendra la totalité de \argu{chaine} et \argu{chaineB} sera vide; + \item Si \argu{chaine} est vide \argu{chaineA} et \argu{chaineB} seront vides, quelque soit l'entier \argu{nombre}. +\end{Conditions} + +\begin{minipage}[c]{0.65\linewidth} +\hfill +\begin{lstlisting} +\def\seprouge{{\color{red}|}} +\StrSplit{abcdef}{4}{\csA}{\csB}|\csA\seprouge\csB|\par +\StrSplit{a b c }{2}{\csA}{\csB}|\csA\seprouge\csB|\par +\StrSplit{abcdef}{1}{\csA}{\csB}|\csA\seprouge\csB|\par +\StrSplit{abcdef}{5}{\csA}{\csB}|\csA\seprouge\csB|\par +\StrSplit{abcdef}{9}{\csA}{\csB}|\csA\seprouge\csB|\par +\StrSplit{abcdef}{-3}{\csA}{\csB}|\csA\seprouge\csB| +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} +\styleexercice +\def\seprouge{{\color{red}|}} +\StrSplit{abcdef}{4}{\csA}{\csB}|\csA\seprouge\csB|\par +\StrSplit{a b c }{2}{\csA}{\csB}|\csA\seprouge\csB|\par +\StrSplit{abcdef}{1}{\csA}{\csB}|\csA\seprouge\csB|\par +\StrSplit{abcdef}{5}{\csA}{\csB}|\csA\seprouge\csB|\par +\StrSplit{abcdef}{9}{\csA}{\csB}|\csA\seprouge\csB|\par +\StrSplit{abcdef}{-3}{\csA}{\csB}|\csA\seprouge\csB| +\end{minipage}% + +\setverbdelim{|}\medskip + +Lorsque l'exploration des groupes est activée, et que l'on demande une coupure en fin de groupe, alors une chaîne contiendra la totalité du groupe tansque l'autre sera vide comme on le voit sur cet exemple :\par\nobreak\smallskip +\begin{minipage}[c]{0.65\linewidth} +\hfill +\begin{lstlisting} +\exploregroups +\StrSplit{ab{cd{ef}gh}ij}{6}\strA\strB +\meaning\strA\par +\meaning\strB +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \exploregroups + \StrSplit{ab{cd{ef}gh}ij}{6}\strA\strB + \meaning\strA\par + \meaning\strB +\end{minipage}% +\medskip + +Une version étoilée de cette macro existe : dans ce cas, la coupure se fait juste avant la prochaine \US qui suit l'\US désirée. La version étoilée ne donne des résultats différents de la version normale que lorsque la $n$\ieme{} \US est à la fin d'un groupe auquel cas, la coupure intervient non pas après cette \US mais \emph{avant} la prochaine \US, que \verbinline|\StrSplit| atteint en fermant autant de groupes que nécessaire.\smallskip + +\begin{minipage}[c]{0.65\linewidth} +\hfill +\begin{lstlisting} +\exploregroups +Utilisation sans \'etoile :\par +\StrSplit{ab{cd{ef}gh}ij}{6}\strA\strB +\meaning\strA\par +\meaning\strB\par +\string\groupID\ = \groupID\par\medskip +Utilisation avec \'etoile :\par +\StrSplit*{ab{cd{ef}gh}ij}{6}\strA\strB +\meaning\strA\par +\meaning\strB\par +\string\groupID\ = \groupID +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \exploregroups + Utilisation sans étoile :\par + \StrSplit{ab{cd{ef}gh}ij}{6}\strA\strB + \meaning\strA\par + \meaning\strB\par + \string\groupID\ = \groupID\par\medskip + Utilisation avec \'etoile :\par + \StrSplit*{ab{cd{ef}gh}ij}{6}\strA\strB + \meaning\strA\par + \meaning\strB\par + \string\groupID\ = \groupID +\end{minipage}% + +\subsection{Assigner un contenu verb, la macro \ttfamily\textbackslash verbtocs} +\label{verbtocs} +La macro \verbinline|\verbtocs| permet le lire le contenu d'un \guill{verb} qui peut contenir tous les caractères spéciaux : \verb|&|, \verb|~|, \verb|\|, \verb|{|, \verb|}|, \verb|_|, \verb|#|, \verb|$|, \verb|^| et \verb|%|. Les caractères \guill{normaux} gardent leur catcodes naturels, sauf les caractères spéciaux qui prennent un catcode de 12. Ensuite, ces caractères sont assignés à une séquence de contrôle. La syntaxe complète est :\par\nobreak\medskip +\hfill\verbinline|\verbtocs|\ARGU{nom}|\argu{caractères}|\hfill{} +\smallskip + +\argu{nom} est le nom d'une séquence de contrôle qui recevra à l'aide d'un \verb|\edef| les \argu{caractères}. \argu{nom} contiendra donc des caractères de catcodes 12 ou 10 pour l'espace.\medskip + +Par défaut, le token délimitant le contenu verb est \guill{|}, étant entendu que ce token ne peut être à la fois le délimiteur et être contenu dans ce qu'il délimite. Au cas où on voudrait lire un contenu verb contenant \guill{|}, on peut changer à tout moment le token délimitant le contenu verb par la macro :\par\medskip +\hfill\verbinline|\setverbdelim|\ARGU{token}\hfill{}\smallskip + +Tout \argu{token} de catcode 12 peut être utilisé\footnote{Plusieurs tokens peuvent être utilisés au risque d'alourdir la syntaxe de \texttt{\string\verbtocs} ! Pour cette raison, avertissement sera émis si l'argument de \texttt{\string\setverbdelim} contient plusieurs tokens.}.\medskip + +Concernant ces arguments verb, il faut tenir compte des deux points suivants : + +\nobreak +\begin{itemize} + \item tous les caractères se trouvant avant |\argu{caractères}| seront ignorés; + \item à l'intérieur des délimiteurs, tous les espaces sont comptabilisés même s'ils sont consécutifs. +\end{itemize} +\medskip + +Exemple :\par\nobreak\medskip +\begin{minipage}[c]{0.65\linewidth} +\lstset{deletecomment=[l]\%} +\begin{lstlisting} +\verbtocs{\resultat} |a & b{ c% d$ e \f| +J'affiche le r\'esultat :\par\resultat +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \verbtocs{\resultat} |a & b{ c% d$ e \f| + J'affiche le r\'esultat :\par\resultat +\end{minipage}% + +\subsection{Tokenisation d'un texte vers une séquence de contrôle, la macro \ttfamily\textbackslash tokenize} +Le processus inverse de ce qui a été vu au dessus consiste à interpréter une suite de caractères en tokens. Pour cela, on dispose de la macro :\par\nobreak\medskip +\hfill\verbinline|\tokenize|\ARGU{nom}\ARGU{texte}\hfill{} +\smallskip + +\argu{texte} est développé le plus possible si l'on a invoqué \verbinline|\fullexpandarg|; il n'est pas développé si l'on a invoqué \verbinline|\noexpandarg| ou \verbinline|\expandarg|. Après développement éventuel, le \argu{texte} est transformé en tokens puis assigné à l'aide d'un \verb|\def| à la séquence de contrôle \argu{nom}.\medskip + +Voici un exemple où l'on détokenise un argument, on affiche le texte obtenu, puis on transforme ce texte en ce que l'argument était au début; enfin, on affiche le résultat de la tokenisation :\par\nobreak\medskip +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\verbtocs{\text}|\textbf{a} $\frac{1}{2}$| +texte : \text +\tokenize{\resultat}{\text}\par +r\'esultat : \resultat +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \verbtocs{\text}|\textbf{a} $\frac{1}{2}$| + texte : \text + \tokenize{\resultat}{\text} \par + r\'esultat : \resultat +\end{minipage}% +\medskip + +Il est bien évident à la dernière ligne, que l'appel à la séquence de contrôle \verb|\resultat| est ici possible puisque les séquences de contrôle qu'elle contient sont définies.\medskip + +\subsection{Développement contrôlé, les macros {\ttfamily\textbackslash StrExpand} et {\ttfamily\textbackslash scancs}} +\label{scancs} +La macro \verbinline|\StrExpand| développe les tokens de la chaîne passée en argument. Voici sa syntaxe :\par\nobreak\medskip +\verbinline|\StrExpand|\arguC{nombre}\ARGU{chaine}\ARGU{nom}\smallskip + +Le \argu{nombre} vaut 1 par défaut et représente le nombre de développement(s) que doit subir la \argu{chaine} de tokens. Le \argu{nom} est le nom d'une séquence de contrôle à laquelle est assigné le résultat, une fois que tous les tokens aient été développé le nombre de fois demandé.\medskip + +La macro opère séquentiellement et par passe : chaque token est remplacé par son 1-dévelopement, et le token suivant subit le même traitement jusqu'à ce que la chaîne ait été parcourue. Ensuite, s'il reste des niveaux de développement à faire, une nouvelle passe est initiée, et ainsi de suite jusqu'à ce que le nombre de développements voulu aient été exécutés.\medskip + +Voici un exemple :\par\nobreak\smallskip +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\def\csA{1 2} +\def\csB{a \csA} +\def\csC{\csB\space} +\def\csD{x{\csA y}\csB{\csC z}} +D\'eveloppement de \string\csD\ au\par +\StrExpand[0]{\csD}{\csE} niveau 0 : +\detokenize\expandafter{\csE}\par +\StrExpand[1]{\csD}{\csE} niveau 1 : +\detokenize\expandafter{\csE}\par +\StrExpand[2]{\csD}{\csE} niveau 2 : +\detokenize\expandafter{\csE}\par +\StrExpand[3]{\csD}{\csE} niveau 3 : +\detokenize\expandafter{\csE}\par +\StrExpand[4]{\csD}{\csE} niveau 4 : +\detokenize\expandafter{\csE} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \def\csA{1 2} + \def\csB{a \csA} + \def\csC{\csB\space} + \def\csD{x{\csA y}\csB{\csC z}} + Développement de \string\csD\ au\par + \StrExpand[0]{\csD}{\csE} niveau 0 : + \detokenize\expandafter{\csE}\par + \StrExpand[1]{\csD}{\csE} niveau 1 : + \detokenize\expandafter{\csE}\par + \StrExpand[2]{\csD}{\csE} niveau 2 : + \detokenize\expandafter{\csE}\par + \StrExpand[3]{\csD}{\csE} niveau 3 : + \detokenize\expandafter{\csE}\par + \StrExpand[4]{\csD}{\csE} niveau 4 : + \detokenize\expandafter{\csE} +\end{minipage}% +\medskip + +La macro agit séquentiellement et chaque token est développé isolément sans tenir compte de ce qui suit. On ne peut donc développer que des tokens qui se suffisent à eux même et dont le développement ne nécessite aucun autre token. Ainsi, \og\hbox{\verbinline|\iftrue A\else B\fi|}\fg, bien que se développant en \guill{A} ne peut être mis dans l'argument de \verbinline|\StrExpand|, et l'instruction :\par\nobreak\smallskip +\hfil\verbinline|\StrExpand{\iftrue A\else B\fi}\resultat|\hfil{}\par\nobreak\smallskip +fera échouer la compilation puisque le premier token \og\verbinline|\iftrue|\fg{} sera développé \emph{seul}, c'est-à -dire sans son \verbinline-\fi- correspondant, ce qui fâchera \TeX{} !\smallskip + +Les règles habituelles de lecture des arguments sont en vigueur, à savoir qu'un espace suivant une séquence de contrôle est ignoré, et plusieurs espaces consécutifs n'en font qu'un. Ces règles ne s'appliquent pas pour des espaces explicitement demandés avec \verb-\space- ou \verb*-\ -\footnote{À ce propos, \texttt{\string\space} n'a pas la même signification que \texttt{\string\ }. La première séquence de contrôle se \emph{développe} en un espace tandis que la deuxième est une primitive \TeX{} qui \emph{affiche} une espace. Comme toutes les primitives, cette dernière est son propre développement.}.\smallskip + +Le développement de ce qui se trouve à l'intérieur des groupes est \emph{indépendant} du mode d'exploration des groupes : cette macro possède ses propres commandes pour développer ce qui est dans les groupes ou pas. Par défaut, les tokens se trouvant à l'intérieur des groupes sont développés, mais on peut demander à ce que ce développement ne se fasse pas en invoquant \verbinline-\noexpandingroups- et revenir au comportement par defaut par \verbinline-\expandingroups-.\bigskip + +On peut détokeniser le résultat obtenu par la macro \verbinline-\StrExpand- avec la macro \verbinline-\scancs- dont la syntaxe est :\par\nobreak\medskip +\verbinline|\scancs|\arguC{nombre}\ARGU{nom}\ARGU{chaine}\par\nobreak\smallskip +Le \argu{nombre} vaut 1 par défaut et représente le nombre de développement(s) que doit subir chaque token constituant la \argu{chaine}. Le \argu{nom} est le nom d'une séquence de contrôle à laquelle est assigné le résultat, une fois que tous les tokens aient été développés le nombre de fois demandé et ensuite détokénisés.\smallskip + +\verbinline-\scancs- a été conservée pour garder une compatibilité avec des précédentes versions de \Xstring. Pour les mêmes raisons, sa syntaxe n'est pas cohérente avec la syntaxe des autres macros. Cette macro, devenue triviale, prend le résultat de \verbinline|\StrExpand| et lui applique simplement un \verbinline|\detokenize|. + +\subsection{À l'intérieur d'une définition de macro} +Avec le verbatim, certaines difficultés surviennent lorsque l'on se trouve à l'intérieur de la définition d'une macro, c'est-à -dire entre les accolades suivant un \verb|\def\macro| ou un \verb|\newcommand\macro|.\medskip + +Pour les mêmes raison qu'il est interdit d'employer la commande \verb|\verb| à l'intérieur de la définition d'une macro, les arguments verb du type |\argu{caractères}| sont également interdits, ce qui disqualifie la macro \verbinline|\verbtocs|. Il faut donc observer la règle suivante :\par\medskip +\hfill{\bfseries Ne pas utiliser la macro \verbinline-\verbtocs- à l'intérieur de la définition d'une macro}.\hfill{}\bigskip + +Mais alors, comment faire pour manipuler des arguments textuels verb et \guill{verbatimiser} dans les définitions de macro ?\bigskip + +Il y a la primitive \verb|\detokenize| de $\varepsilon$-\TeX, mais elle comporte des restrictions, entre autres : + +\nobreak +\begin{itemize} + \item les accolades doivent être équilibrées; + \item les espaces consécutifs sont ignorés; + \item les signes \verb|%| sont interdits; + \item une espace est ajoutée après chaque séquence de contrôle. +\end{itemize} +\medskip + +Il est préférable d'utiliser la macro \verbinline|\scancs|, et définir avec \verbinline|\verbtocs| à l'extérieur des définitions de macros, des séquences de contrôle contenant des caractères spéciaux détokénisés. On pourra aussi utiliser la macro \verbinline|\tokenize| pour transformer le résultat final (qui est une chaîne de caractères) en une séquence de contrôle. On peut voir des exemples utilisant ces macros page~\pageref{exemples}, à la fin de ce manuel.\medskip + +Dans l'exemple artificiel\footnote{On peut agir beaucoup plus simplement en utilisant la commande \texttt{\string\detokenize}. Il suffit de définir la macro ainsi :\par\texttt{\string\newcommand\string\bracearg[1]\{\string\detokenize\{\{\#1\}\}\}}} qui suit, on écrit une macro qui met son argument entre accolades. Pour cela, on définit en dehors de la définition de la macro 2 séquences de contrôles \verb|\Ob| et \verb|\Cb| contenant une accolade ouvrante et une accolade fermante de catcodes 12. Ces séquences de contrôle sont ensuite développées et utilisées à l'intérieur de la macro pour obtenir le résultat voulu :\par\nobreak\medskip +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\verbtocs{\Ob}|{| +\verbtocs{\Cb}|}| +\newcommand\bracearg[1]{% + \def\text{#1}% + \scancs{\result}{\Ob\text\Cb}% + \result} + +\bracearg{xstring}\par +\bracearg{\a} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \verbtocs{\Ob}|{| + \verbtocs{\Cb}|}| + \newcommand\bracearg[1]{% + \def\text{#1}% + \scancs{\result}{\Ob\text\Cb}% + \result} + + \bracearg{xstring}\par + \bracearg{\a} +\end{minipage}% + +\subsection{La macro \ttfamily\textbackslash StrRemoveBraces} +Pour des utilisations spéciales, on peut désirer retirer les accolades délimitant les groupes dans un argument. + +On peut utiliser la macro \verbinline|\StrRemoveBraces| dont voici la syntaxe :\par\nobreak\smallskip +\verbinline|\StrRemoveBraces|\ARGU{chaine}\arguC{nom} +\smallskip + +Cette macro est sensible au mode d'exploration, et retirera \emph{toutes} les accolades avec \verbinline|\exploregroups| alors qu'elle ne retirera que les accolades des groupes de plus bas niveau avec \verbinline|\noexploregroups|.\medskip + +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\noexploregroups +\StrRemoveBraces{a{b{c}d}e{f}g}[\mycs] +\meaning\mycs + +\exploregroups +\StrRemoveBraces{a{b{c}d}e{f}g}[\mycs] +\meaning\mycs +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \noexploregroups + \StrRemoveBraces{a{b{c}d}e{f}g}[\mycs] + \meaning\mycs + + \exploregroups + \StrRemoveBraces{a{b{c}d}e{f}g}[\mycs] + \meaning\mycs +\end{minipage}% + +\subsection{Exemples d'utilisation en programmation} +\label{exemples} +Voici quelques exemples très simples d'utilisation des macros comme on pourrait en rencontrer en programmation. + +\subsubsection{Exemple 1} +On cherche à remplacer les deux premiers \verb|\textit| par \verb|\textbf| dans la séquence de contrôle \verb|\myCS| qui contient :\par\nobreak\smallskip +\hfill\verb|\textit{A}\textit{B}\textit{C}|\hfill{} +\medskip + +On cherche évidemment à obtenir \verb|\textbf{A}\textbf{B}\textit{C}| qui affiche : \textbf{A}\textbf{B}\textit{C}\medskip + +Pour cela, on va développer les arguments des macros une fois avant qu'elles les traitent, en invoquant la commande \verbinline|\expandarg|. + +Ensuite, on définit \verb|\pattern| qui est le motif à remplacer, et \verb|\replace| qui est le motif de substitution. On travaille token par token puisque \verbinline|\expandarg| a été appelé, il suffit d'invoquer \verbinline|\StrSubstitute| pour faire les 2 substitutions.\medskip + +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\expandarg +\def\myCS{\textit{A}\textit{B}\textit{C}} +\def\pattern{\textit} +\def\replace{\textbf} +\StrSubstitute[2]{\myCS}{\pattern}{\replace} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \expandarg + \def\myCS{\textit{A}\textit{B}\textit{C}} + \def\pattern{\textit} + \def\replace{\textbf} + \StrSubstitute[2]{\myCS}{\pattern}{\replace} +\end{minipage}% +\medskip + +Pour éviter de définir les séquences de contrôle \verb|\pattern| et \verb|\replace|, on aurait pu utiliser un leurre comme par exemple une séquence de contrôle qui se développe en \guill{rien} comme \verb|\empty|, et coder de cette façon :\par\smallskip +\hfil\verbinline|\StrSubstitute[2]{\myCS}{\empty\textit}{\empty\textbf}|\hfil{}\medskip + +Ainsi, \verb|\empty| est développée en \guill{rien} et il reste dans les 2 derniers arguments les séquences de contrôles significatives \verb|\textit| et \verb|textbf|.\smallskip + +La séquence de contrôle \verbinline|\empty| est donc un \guill{hack} pour \verbinline|\expandarg| : elle permet de bloquer le développement du 1\ier{} token ! On aurait d'ailleurs pu utiliser \verbinline|\noexpand| au lieu de \verbinline|\empty| pour obtenir le même résultat. + +\subsubsection{Exemple 2} +On cherche ici à écrire une commande qui efface \verb|n| unités syntaxiques dans une chaîne à partir d'une position donnée, et affecte le résultat dans une séquence de contrôle dont on peut choisir le nom. + +On va appeler cette macro \verb|StringDel| et lui donner la syntaxe :\par\nobreak\smallskip +\hfil\verb|\StringDel{chaine}{position}{n}{\nom_resultat}|\hfil{} +\medskip + +On peut procéder ainsi : sauvegarder la chaîne se trouvant juste avant la position. Ensuite enlever \verb|n + position| \USs à la chaîne initiale, et concaténer ce résultat à ce qui a été sauvegardé auparavant. Cela donne le code suivant :\par\nobreak\medskip + +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\newcommand\StringDel[4]{% + \begingroup + \expandarg% portee locale au groupe + \StrLeft{\empty#1}{\number\numexpr#2-1}[#4]% + \StrGobbleLeft{\empty#1}{\numexpr#2+#3-1}[\StrA]% + \expandafter\expandafter\expandafter\endgroup + \expandafter\expandafter\expandafter\def + \expandafter\expandafter\expandafter#4% + \expandafter\expandafter\expandafter + {\expandafter#4\StrA}% +} + +\noexploregroups +\StringDel{abcdefgh}{2}{3}{\cmd} +\meaning\cmd + +\StringDel{a\textbf{1}b\textbf{2c}3d}{3}{4}{\cmd} +\meaning\cmd +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \newcommand\StringDel[4]{% + \begingroup + \expandarg% portée locale au groupe + \StrLeft{\empty#1}{\number\numexpr#2-1}[#4]% + \StrGobbleLeft{\empty#1}{\numexpr#2+#3-1}[\StrA]% + \expandafter\expandafter\expandafter\endgroup + \expandafter\expandafter\expandafter\def + \expandafter\expandafter\expandafter#4% + \expandafter\expandafter\expandafter{\expandafter#4\StrA}% + } + + \noexploregroups + \StringDel{abcdefgh}{2}{3}{\cmd} + \meaning\cmd + + \StringDel{a\textbf{1}b\textbf{2c}3d}{3}{4}{\cmd} + \meaning\cmd +\end{minipage}% +\fullexpandarg\bigskip + +Pour la concaténation, on aurait pu procéder différemment en utilisant la macro \verb|\g@addto@macro| de \LaTeX{}. Cela évite aussi ces laborieux \guill{ponts} d'\verbinline|\expandafter|. Il suffit alors de remplacer l'assignation et la sortie du groupe se trouvant entre les lignes 6 à 10 par\footnote{À condition d'avoir provisoirement changé le code de catégorie de \og{\ttfamily\string@}\fg{} en écrivant la macro entre les commandes {\ttfamily\string\makeatletter} et {\ttfamily\string\makeatother}} :\par\nobreak\smallskip +\hfil\verbinline|\expandafter\g@addto@macro\expandafter#4\expandafter{\StrA}\endgroup|\hfil{} + +\subsubsection{Exemple 3} +Cherchons à écrire une macro \verb|\tofrac| qui transforme une écriture du type \guill{a/b} par \guill{$\frac{a}{b}$}.\medskip + +Tout d'abord, annulons le développement des arguments avec \verbinline|\noexpandarg| : nous n'avons pas besoin de développement ici. Il suffit d'isoler ce qui se trouve avant et après la 1\iere{} occurrence de \guill{/} (on suppose qu'il n'y a qu'une seule occurrence), le mettre dans les séquences de contrôle \verb|\num| et \verb|\den| et simplement appeler la macro \TeX{} \verb|\frac| :\par\nobreak\medskip +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\noexpandarg +\newcommand\tofrac[1]{% + \StrBefore{#1}{/}[\num]% + \StrBehind{#1}{/}[\den]% + $\frac{\num}{\den}$% +} +\tofrac{15/9} +\tofrac{u_{n+1}/u_n} +\tofrac{a^m/a^n} +\tofrac{x+\sqrt{x}/\sqrt{x^2+x+1}} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \noexpandarg + \newcommand\tofrac[1]{% + \StrBefore{#1}{/}[\num]% + \StrBehind{#1}{/}[\den]% + $\frac{\num}{\den}$% + } + \tofrac{15/9} + \tofrac{u_{n+1}/u_n} + \tofrac{a^m/a^n} + \tofrac{x+\sqrt{x}/\sqrt{x^2+x+1}} +\end{minipage}% + +\subsubsection{Exemple 4} +Soit une phrase composée de texte. Dans cette phrase, essayons construire une macro qui mette en gras le 1\ier{} mot qui suit un mot donné. On entend par mot une suite de caractère ne commençant ni ne finissant par un espace. Si le mot n'existe pas dans la phrase, rien n'est fait.\medskip + +On va écrire une macro \verb|\grasapres| qui effectue ce travail. On appelle \verbinline|\StrBehind| qui assigne à \verb|\mot| ce qui se trouve après la 1\iere{} occurrence du mot (précédé et suivi de son espace). Ensuite, le mot à mettre en gras est ce qui se trouve avant le 1\ier{} espace dans la séquence de contrôle \verb|\mot|. Remarquons que ceci reste vrai même si le mot à mettre en gras est le dernier de l'argument car un espace a été rajouté à la fin de l'argument par \verb|{#1 }| lors de l'appel à \verbinline|\StrBehind|. Remarquons aussi que \verbinline|\expandarg| a été appelé et donc, le premier token de l'argument \verb|\textbf{\mot}| est développé 1 fois, \emph{lui aussi} ! Cela est possible (heureusement sinon, il aurait fallu faire autrement et utiliser le hack de l'exemple précédent) puisque le 1-développement de cette macro de \LaTeX{} est \og\verb|\protect\textbf|\fg{}\footnote{En toute rigueur, il aurait fallu écrire :\par\hspace{2em}{\ttfamily\string\StrSubstitute[1]\{\string#1\}\{\string\mot\}\{\string\expandafter\string\textbf\string\expandafter\{\string\mot\}\}}\newline De cette façon, dans {\ttfamily\{\string\expandafter\string\textbf\string\expandafter\{\string\mot\}\}}, la séquence de contrôle {\ttfamily\string\mot} est développée \textbf{avant} que l'appel à la macro ne se fasse. Cela est dû à l'{\ttfamily\string\expandafter} placé en début d'argument qui est développé à cause de {\ttfamily\string\expandarg} et grace à l'autre {\ttfamily\string\expandafter}, provoque le développement de {\ttfamily\string\mot}}.\medskip + +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\newcommand\grasapres[2]{% + \noexpandarg + \StrBehind[1]{#1 }{ #2 }[\mot]% + \expandarg + \StrBefore{\mot}{ }[\mot]% + \StrSubstitute[1]{#1}{\mot}{\textbf{\mot}}% +} + +\grasapres{Le package xstring est nouveau}{package} + +\grasapres{Le package xstring est nouveau}{ckage} + +\grasapres{Le package xstring est nouveau}{est} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \newcommand\grasapres[2]{% + \noexpandarg + \StrBehind[1]{#1 }{ #2 }[\mot]% + \expandarg + \StrBefore{\mot}{ }[\mot]% + \StrSubstitute[1]{#1}{\mot}{\textbf{\mot}}% + } + + \grasapres{Le package xstring est nouveau}{package} + + \grasapres{Le package xstring est nouveau}{ckage} + + \grasapres{Le package xstring est nouveau}{est} +\end{minipage}% +\fullexpandarg + +\subsubsection{Exemple 5} +Soit un argument commençant par au moins 3 séquences de contrôles avec leurs éventuels arguments. Comment intervertir les 2 premières séquences de contrôle de telle sorte qu'elles gardent leurs arguments ? On va pour cela écrire une macro \verb|\swaptwofirst|. + +Cette fois ci, on ne peut pas chercher le seul caractère \og\verb|\|\fg{} (de catcode 0) dans un argument. Nous serons obligé de détokeniser l'argument, c'est ce que fait \verbinline|\scancs[0]\chaine{#1}| qui met le résultat dans \verb|\chaine|. Ensuite, on cherchera dans cette séquence de contrôle les occurrences de \verb|\antislash| qui contient le caractère \og\verb|\|\fg{} de catcode 12, assigné avec un \verbinline|\verbtocs| écrit \emph{en dehors\footnote{En effet, la macro {\tt\string\verbtocs} et son argument verb est interdite à l'intérieur de la définition d'une macro.}} du corps de la macro. La macro se termine par une retokenisation, une fois que les chaînes \verb|\avant| et \verb|\apres| aient été échangées.\medskip + +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\verbtocs{\antislash}|\| +\newcommand\swaptwofirst[1]{% + \begingroup + \fullexpandarg + \scancs[0]\chaine{#1}% + \StrBefore[3]{\chaine}{\antislash}[\firsttwo]% + \StrBehind{\chaine}{\firsttwo}[\others] + \StrBefore[2]{\firsttwo}{\antislash}[\avant] + \StrBehind{\firsttwo}{\avant}[\apres]% + \tokenize\myCS{\apres\avant\others}% + \myCS + \endgroup +} + +\swaptwofirst{\underline{A}\textbf{B}\textit{C}} + +\swaptwofirst{\Large\underline{A}\textbf{B}123} +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \verbtocs{\antislash}|\| + \newcommand\swaptwofirst[1]{% + \begingroup + \fullexpandarg + \scancs[0]\chaine{#1}% + \StrBefore[3]{\chaine}{\antislash}[\firsttwo]% + \StrBehind{\chaine}{\firsttwo}[\others] + \StrBefore[2]{\firsttwo}{\antislash}[\avant] + \StrBehind{\firsttwo}{\avant}[\apres]% + \tokenize\myCS{\apres\avant\others}% + \myCS + \endgroup + } + + \swaptwofirst{\underline{A}\textbf{B}\textit{C}} + + \swaptwofirst{\Large\underline{A}\textbf{B}123} +\end{minipage}% + +\subsubsection{Exemple 6} +Dans une chaîne, on cherche ici à isoler le n\ieme{} mot se trouvant entre 2 délimiteurs précis. Pour cela on écrira une macro \verb|\findword| admettant comme argument optionnel le délimiteur de mot (l'espace par défaut), 1 argument contenant la chaîne, 1 argument contenant le nombre correspondant au n\ieme{} mot cheché.\medskip + +La macro \verb|\findword| utilise \verbinline|\StrBetween| et \verb|\numexpr| de façon astucieuse, et profite du fait que \verbinline-\StrBetween- n'explore pas les groupes :\par\nobreak\medskip +\begin{minipage}[c]{0.65\linewidth} +\begin{lstlisting} +\newcommand\findword[3][ ]{% + \StrBetween[#3,\numexpr#3+1]{#1#2#1}{#1}{#1}% +} +\noexpandarg +|\findword{a bc d\textbf{e f} gh}{3}| + +|\findword[\nil]{1 \nil 2 3 \nil4\nil5}{2}| +\end{lstlisting}% +\end{minipage}\hfill +\begin{minipage}[c]{0.35\linewidth} + \styleexercice + \newcommand\findword[3][ ]{% + \StrBetween[#3,\numexpr#3+1]{#1#2#1}{#1}{#1}% + } + \noexpandarg + |\findword{a bc d\textbf{e f} gh}{3}| + + |\findword[\nil]{1 \nil 2 3 \nil4\nil5}{2}| +\end{minipage}% + +On peut observer que le résultat de la ligne 7 qui est \og\verb*|2 3 |\fg{} ne commence \emph{pas} par une espace puisque dans le code, cet espace suit une séquence de contrôle~---~ici \verb|\nil|. +\bigskip\bigskip +\begin{center} +$\star$\par +$\star$\quad$\star$ +\end{center} +\bigskip\bigskip + +C'est tout, j'espère que ce package vous sera utile !\par\nobreak +Merci de me signaler par \href{mailto:unbonpetit@netc.fr}{email} tout bug ou toute proposition d'amélioration\ldots\par\nobreak\bigskip +Christian \textsc{Tellechea} +\end{document}
\ No newline at end of file diff --git a/macros/generic/xstring/xstring.sty b/macros/generic/xstring/xstring.sty new file mode 100644 index 0000000000..18632cd872 --- /dev/null +++ b/macros/generic/xstring/xstring.sty @@ -0,0 +1,3 @@ +\input xstring.tex +\ProvidesPackage{xstring}[\xstringdate\space v\xstringversion\space String manipulations (CT)] +\endinput
\ No newline at end of file diff --git a/macros/generic/xstring/xstring.tex b/macros/generic/xstring/xstring.tex new file mode 100644 index 0000000000..654fe462ae --- /dev/null +++ b/macros/generic/xstring/xstring.tex @@ -0,0 +1,1227 @@ +% !TeX encoding = ISO-8859-1 +% Ce fichier contient le code de l'extension "xstring" +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +\def\xstringname {xstring} % +\def\xstringversion {1.83} % +% % +\def\xstringdate {2019/02/06} % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% Author : Christian Tellechea % +% Status : Maintained % +% Maintainer : Christian Tellechea % +% Email : unbonpetit@netc.fr % +% Package URL: https://www.ctan.org/pkg/xstring % +% Bug tracker: https://framagit.org/unbonpetit/xstring/issues % +% Repository : https://framagit.org/unbonpetit/xstring/tree/master % +% Copyright : Christian Tellechea 2008-2019 % +% Licence : Released under the LaTeX Project Public License v1.3c % +% or later, see http://www.latex-project.org/lppl.txt % +% Files : 1) xstring.tex % +% 2) xstring.sty % +% 3) xstring-fr.tex % +% 4) xstring-fr.pdf % +% 5) xstring-en.tex % +% 6) xstring-en.pdf % +% 7) README % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\ifdefined\usepackage\else + \immediate\write-1 {Package: xstring \xstringdate\space v\xstringversion\space String manipulations (CT)}% +\fi +\newcount\integerpart +\newcount\decimalpart% compteurs utilisés par xstring + +\edef\restorexstringcatcode{\catcode\number`\_ =\number\catcode`\_\relax} +\catcode`\_=11 + +\long\def\xs_execfirst#1#2{#1} +\long\def\xs_execsecond#1#2{#2} +\long\def\xs_gobarg#1{} +\expandafter\def\expandafter\xs_gobspace\space{} +\def\xs_deftok#1#2{\let#1= #2\relax}\xs_deftok\xs_sptoken{ } +\long\def\xs_ifnxttok#1#2#3{\xs_deftok\xs_toksmatch{#1}\def\__truecode{#2}\def\__falsecode{#3}\xs_ifnxttok_a} +\def\xs_ifnxttok_a{\futurelet\__futurtok\xs_ifnxttok_b} +\def\xs_ifnxttok_b{% + \xs_ifx{\__futurtok\xs_sptoken} + {\afterassignment\xs_ifnxttok_a\let\__futurtok= } + {\xs_ifx{\__futurtok\xs_toksmatch}\__truecode\__falsecode}% +} +\def\xs_ifstar#1{\xs_ifnxttok*{\xs_execfirst{#1}}} +\long\def\xs_testopt#1#2{\xs_ifnxttok[{#1}{#1[{#2}]}} +\long\def\xs_exparg#1#2{\expandafter\xs_exparg_a\expandafter{#2}{#1}}% +\long\def\xs_exparg_a#1#2{#2{#1}} +\long\def\xs_exptwoargs#1#2#3{\xs_exparg{\xs_exparg{#1}{#2}}{#3}} +\long\def\xs_eearg#1#2{\xs_exparg{\xs_exparg{#1}}{#2}} +\long\def\xs_edefaddtomacro#1#2{\edef#1{\unexpanded\expandafter{#1}#2}} +\long\def\xs_addtomacro#1#2{\xs_exparg{\def#1}{#1#2}} +\long\def\xs_eaddtomacro#1#2{\xs_exparg{\xs_addtomacro#1}{#2}} +\long\def\xs_eeaddtomacro#1#2{\xs_exparg{\xs_eaddtomacro#1}{#2}} +\long\def\xs_endgroup_eaddtomacro#1#2{\xs_exparg{\endgroup\xs_addtomacro#1}{#2}} +\long\def\xs_beforespace#1 #2\_nil{#1} +\long\def\xs_afterspace#1 #2\_nil{#2} +\long\def\xs_gobtonil#1\_nil{} +\long\def\xs_gobtobrace#1#{} +\long\def\xs_ifx#1{\ifx#1\expandafter\xs_execfirst\else\expandafter\xs_execsecond\fi} +\def\xs_ifnum#1{\ifnum#1\expandafter\xs_execfirst\else\expandafter\xs_execsecond\fi} +\long\def\xs_ifempty#1{\expandafter\xs_ifx\expandafter{\expandafter\relax\detokenize{#1}\relax}} + +\def\xs_toks_toverb{% lit 1 argument et le transforme en verb + \begingroup + \def\do##1{\catcode`##112 }% + \dospecials + \obeyspaces + \xs_read_verb +} + +\def\setverbdelim#1{% définit quel est le délimiteur de verb + \xs_exparg\xs_ifempty{\xs_gobarg#1}% + {} + {\errmessage{Package xstring Warning: verb delimiter "\detokenize{#1}" is not a single token}}% + \def\xs_read_verb##1#1##2#1{\endgroup\xs_assign_verb{##2}}% on appelle l'exécution de fin +} + +% Assigne l'argument entre délimiteur verb dans la sc #1 +\def\verbtocs#1{% + \def\xs_assign_verb##1{\def#1{##1}}% + \xs_toks_toverb +} + +\begingroup + \catcode0 3 \gdef\xs_twozeroschars{^^00}% + \catcode0 7 \xdef\xs_twozeroschars{\xs_twozeroschars^^00}% +\endgroup + +\edef\xs_reserved_A{\long\def\noexpand\xs_assigntokenizeresult##1\xs_twozeroschars} +\xs_reserved_A#2{\endgroup\xs_exparg{\def#2}{\xs_gobarg#1}} + +\def\tokenize#1#2{% + \begingroup + \xs_def\xs_reserved_A{#2}% on développe en accord avec \fullexpandarg ou \noexpandarg + \everyeof\expandafter{\xs_twozeroschars#1}% + \endlinechar-1 + \expandafter\xs_assigntokenizeresult\scantokens\expandafter{\expandafter\relax\xs_reserved_A}% on fait l'assignation +}% + +\long\def\xs_assign_xstringresult#1#2{\xs_ifempty{#2}{#1}{\def#2{#1}}} + +\def\xs_ldef{\long\def} +\def\xs_ledef{\long\edef} + +\def\normalexpandarg{% + \let\xs_def\xs_ldef% on définit \xs_call avec \def + \def\xs_expand##1{\unexpanded\expandafter{##1}}% +} +\let\noexpandarg\normalexpandarg% synonyme + +\def\expandarg{% + \let\xs_def\xs_ldef% on définit \xs_call avec \def + \def\xs_expand##1{\unexpanded\expandafter\expandafter\expandafter{##1}}% +} + +\def\fullexpandarg{% + \let\xs_def\xs_ledef% on définit\xs_call avec \edef + \def\xs_expand##1{##1}% et on neutralise \xs_expand +} + +\def\saveexpandmode{\let\xs_saved_def\xs_defarg\let\xs_saved_expand\xs_expand} +\def\restoreexpandmode{\let\xs_defarg\xs_saved_def\let\xs_expand\xs_saved_expand} + +% Macro interne renvoyant #2 si son argument commence par une accolade ouvrante "{" +% et #3 sinon (Ulrich Diez sur comp.text.tex) +\long\def\xs_ifbeginwithbrace#1{% + \csname xs_exec% + \expandafter\xs_gobarg\string{% + \expandafter\xs_gobarg\expandafter{\expandafter{\string#1}% + \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\xs_execfirst + \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\xs_gobarg + \expandafter\expandafter\expandafter\xs_gobarg + \expandafter\expandafter\expandafter{\expandafter\string\expandafter}\string}% + \expandafter\xs_gobarg\string}% + \xs_execsecond{first}{second}% + \endcsname +} + +% Cette macro interne prend la 1ere unité syntaxique de #1 et assigne le résultat à #2 +\long\def\xs_returnfirstsyntaxunit#1#2{% + \let\xs_toks\relax + \xs_ifempty{#1} + {\let#2\empty + } + {\xs_eearg\xs_ifempty{\expandafter\xs_beforespace\detokenize{#1} \_nil}% #1 commence par un espace ? + {\def#2{ }} + {\xs_ifbeginwithbrace{#1} + {\def\xs_groupfound{\xs_exparg{\def#2}{\expandafter{#2}}\xs_gobtonil}% on met #2 dans des accolades et on finit + \let\xs_toks\bgroup + \afterassignment\xs_groupfound + \def#2% + } + {\long\def\xs_assignfirstarg##1##2\_nil{\def#2{##1}}% + \xs_assignfirstarg + }% + #1\_nil + }% + }% +} + +\long\def\xs_removefirstsyntaxunit#1#2{% + \xs_ifempty{#1} + {\let#2\empty + } + {\xs_eearg\xs_ifempty{\expandafter\xs_beforespace\detokenize{#1} \_nil}% #1 commence par un espace ? + {\xs_exparg\xs_ifbeginwithbrace{\xs_gobspace#1} + {\xs_exparg{\def#2}{\xs_gobtobrace#1}}% + {\xs_exparg{\def#2}{\xs_afterspace#1\_nil}}% + }% + {\xs_exparg{\def#2}{\xs_gobarg#1}}% + }% +} + +% Cette macro interne est utilisée dans les macros étoilées pour : +% 1) développer l'argument selon qu'on a choisit \fullexpandarg +% ou \normalexpandarg, et ceci à l'aide de la macro \xs_def +% 2) Ensuite, on détokenize ce développement de façon n'avoir plus que +% des catcodes de 10 pour les espaces et 12 pour le reste. +\long\def\xs_expand_and_detokenize#1#2{% + \long\def#1{#2}% + \expandafter\edef\expandafter#1\expandafter{\xs_expand#1}% on développe #2 selon le mode de développement + \long\edef#1{\detokenize\expandafter{#1}}% puis on détokenize et on assigne à #1 +} + +\long\def\xs_expand_and_assign#1#2{\xs_def#1{#2}}% on développe #2 selon \fullexpandarg ou \normalexpandarg + +\def\xs_arglist{0########1########2########3########4########5########6########7########8########9} + +% \xs_assign_args{3} met dans la sc \xs_myarg les tokens "####1####2####3" +\def\xs_assign_args#1{\def\xs_assign_args_i0##1#1##2\_nil{\def\xs_myarg{##1#1}}\expandafter\xs_assign_args_i\xs_arglist\_nil} + +% \xs_assign_opt_args{3} met dans la sc \xs_myarg les tokens "[####1]####2####3####4" +\def\xs_assign_opt_args#1{\xs_exparg\xs_assign_opt_args_i{\number\numexpr#1+1}} +\def\xs_assign_opt_args_i#1{\def\xs_assign_opt_args_ii0##11##2#1##3\_nil{\def\xs_myarg{[##11]##2#1}}\expandafter\xs_assign_opt_args_ii\xs_arglist\_nil} + +% \xs_assign_one_arg{3} met dans la sc \xs_myarg les tokens "####3" +\def\xs_assign_one_arg#1{\xs_exparg\xs_assign_one_arg_i{\number\numexpr#1-1}{#1}} +\def\xs_assign_one_arg_i#1#2{\def\xs_assign_one_arg_ii##1#1##2#2##3\_nil{\def\xs_myarg{##2#2}}\expandafter\xs_assign_one_arg_ii\xs_arglist\_nil} + +% #1 : numéro du 1er argument; #2 : nombre de lignes; #3 argument optionnel; #4 : dernier numéro de l'argument devant être détokenisé si étoile +\def\xs_buildlines#1#2#3#4{% + \let\xs_newlines\empty + \let\xs_newargs\empty + \def\xs_buildlines_i##1{% + \xs_exparg\xs_assign_one_arg{\number\numexpr##1+#1-1}% + \edef\xs_reserved_B{\noexpand\xs_expand\csname xs_arg_\romannumeral\numexpr##1\endcsname}% + \xs_ifnum{##1=1 }% si c'est le premier argument + {\xs_ifempty{#3}% + {\xs_eaddtomacro\xs_newargs{\expandafter{\xs_reserved_B}}% + \edef\xs_reserved_B{\ifnum##1>#4 xs_def\else xs_assign\fi}% + }% et s'il y a un argument optionnel alors, on met des crochets + {\xs_eaddtomacro\xs_newargs{\expandafter[\xs_reserved_B]}% + \def\xs_reserved_B{xs_def}% ne pas détokéniser l'argument optionnel grace au \xs_def + }% + } + {\xs_eaddtomacro\xs_newargs{\expandafter{\xs_reserved_B}}% + \edef\xs_reserved_B{\ifnum##1>#4 xs_def\else xs_assign\fi}% + }% + \edef\xs_newlines{\unexpanded\expandafter{\xs_newlines}\expandafter\noexpand\csname\xs_reserved_B\endcsname\expandafter\noexpand\csname xs_arg_\romannumeral\numexpr##1\endcsname{\xs_myarg}}% + \xs_ifnum{##1<#2 } + {\xs_exparg\xs_buildlines_i{\number\numexpr##1+1}} + {}% + }% + \xs_buildlines_i1% +} + +\def\xs_newmacro{% + \xs_ifstar + {\let\xs_reserved_D\empty\xs_newmacro_} + {\let\xs_reserved_D\relax\xs_newmacro_0}% +} + +% #1 : dernier numéro de l'argument devant être détokenisé +% #2 : nom de la macro publique +% #3 : argument optionnel (vide si pas d'arg optionnel) +% #4 : nombre d'arguments obligatoires +% #5 : utilisation de testopt (1 si oui, 0 si non) +% #6 : code de la macro +\def\xs_newmacro_#1#2#3#4#5{% + \edef\xs_reserved_A{xs_\expandafter\xs_gobarg\string#2}% + \edef\xs_reserved_C{\expandafter\noexpand\csname\xs_reserved_A _\ifx\empty#3\empty _\fi\endcsname}% + \edef\xs_reserved_B{% + \long + \ifx\empty\xs_reserved_D + \def\noexpand#2{\noexpand\xs_ifstar + {\let\noexpand\xs_assign\noexpand\xs_expand_and_detokenize\expandafter\noexpand\xs_reserved_C}% + {\let\noexpand\xs_assign\noexpand\xs_expand_and_assign\expandafter\noexpand\xs_reserved_C}% + }% + \else + \def\noexpand#2{\let\noexpand\xs_assign\noexpand\xs_expand_and_assign\expandafter\noexpand\xs_reserved_C}% + \fi + \ifx\empty#3\empty + \else + \def\expandafter\noexpand\xs_reserved_C{% + \noexpand\xs_testopt{\expandafter\noexpand\csname\xs_reserved_A __\endcsname}{\ifx\xs_def\xs_ledef#3\else\unexpanded{#3}\fi}}% + \fi + }% + % Que fait \xs_reserved_B ? Il définit : + % si #3 est vide : \NOM{\xs_ifstar{\let\xs_assign\xs_expand_and_detokenize\xs_NOM__}{\let\xs_assign\xs_expand_and_assign\xs_NOM__}} + % si #3 existe : \NOM{\xs_ifstar{\let\xs_assign\xs_expand_and_detokenize\xs_NOM_}{\let\xs_assign\xs_expand_and_assign\xs_NOM_}} + % \xs_NOM_{\xs_testopt{\xs_NOM__}{#3}}} + \xs_reserved_B + \ifx\empty#3\empty + \xs_buildlines1{#4}{#3}{#1}% + \xs_assign_args{#4}% + \else + \xs_exparg{\xs_buildlines1}{\number\numexpr#4+1}{#3}{#1}% + \xs_assign_opt_args{#4}% + \fi + \edef\xs_reserved_B{\def\expandafter\noexpand\csname\xs_reserved_A __\endcsname\xs_myarg}% + \edef\xs_reserved_C{\unexpanded\expandafter{\xs_newlines}\edef\noexpand\xs_call}% + \edef\xs_reserved_D{\noexpand\noexpand\expandafter\noexpand\csname\xs_reserved_A\endcsname\unexpanded\expandafter{\xs_newargs}}% + \ifnum#5=1 \edef\xs_reserved_D{\noexpand\noexpand\noexpand\xs_testopt{\unexpanded\expandafter{\xs_reserved_D}}{}}\fi + \xs_edefaddtomacro\xs_reserved_C{{\unexpanded\expandafter{\xs_reserved_D}}\noexpand\xs_call}% + \xs_edefaddtomacro\xs_reserved_B{{\unexpanded\expandafter{\xs_reserved_C}}}% + % Que fait \xs_reserved_B ? Il définit par exemple pour 3 arguments obligatoires et 1 facultatif : + % \def\xs_NOM__[##2]##3##4##5{% + % \xs_def\xs_arg_i{##2}\xs_assign\xs_arg_ii{##3}\xs_assign\xs_arg_iii{##4}\xs_asign\xs_arg_iv{##5}% + % si #5=0: \edef\xs_call{\noexpand\xs_NOM[\xs_expand\xs_arg_i]{\xs_expand\xs_arg_ii}{\xs_expand\xs_arg_iii}{\xs_expand\xs_arg_iv}}% + % si #5=1: \edef\xs_call{\noexpand\xs_testopt{\noexpand\xs_NOM[\xs_expand\xs_arg_i]{\xs_expand\xs_arg_i}{\xs_expand\xs_arg_ii}{\xs_expand\xs_arg_iii}{\xs_expand\xs_arg_iv}}{}}% + % \xs_call} + \long\xs_reserved_B + \edef\xs_reserved_B{% + \def\expandafter\noexpand\csname\xs_reserved_A\endcsname + \xs_myarg\ifnum#5=1 [\unexpanded{##}\number\numexpr\ifx\empty#3\empty#4+1\else#4+2\fi]\fi + }% + % Que fait \xs_reserved_B ? Il définit par exemple pour 3 arguments obligatoires et 1 facultatif : + % \def \xs_NOM[##2]##3##4##5[##6]{#6} + \long\xs_reserved_B +} + +% macro générique qui lit \xs_reserved_C us par us +% 3 sous-routines sont appelées à des moments clé : +% \xs_atendofgroup (un groupe se finit, appel récursif) +% \xs_atbegingroup (un groupe vient d'être ouvert) +% \xs_atnextsyntaxunit (la future US n'est pas un groupe) +\def\xs_read_reserved_C{% + \xs_exparg\xs_ifempty{\xs_reserved_C}% + {\xs_ifnum{\xs_nestlevel=0 } + {} + {\xs_atendofgroup + \xs_read_reserved_C + }% + } + {\xs_exparg\xs_returnfirstsyntaxunit{\xs_reserved_C}\xs_reserved_A + \xs_exparg\xs_removefirstsyntaxunit{\xs_reserved_C}\xs_reserved_C + \xs_exploregroups + \xs_ifx{\bgroup\xs_toks} + {\advance\integerpart1 + \begingroup + \expandafter\def\expandafter\xs_reserved_C\xs_reserved_A + \xs_calc_grouIP + \def\xs_nestlevel{1}% + \integerpart0 + \xs_atbegingroup + } + {\advance\decimalpart1 + \xs_atnextsyntaxunit + }% + \xs_read_reserved_C + }% +} + +% macro générique qui lit \xs_reserved_D en procédant à des tests avec \IfBeginWith +% 1 sous-routine est appelée : +% \xs_atoccurfound (une occurrence a été trouvée) +\def\xs_read_reserved_D{% + \xs_exparg\xs_ifempty{\xs_reserved_D}% + {\xs_ifnum{\xs_nestlevel=0 } + {} + {\edef\__temp{% + \endgroup + \noexpand\decimalpart=\number\decimalpart\relax + \unexpanded{\xs_addtomacro\xs_reserved_C}{{\unexpanded\expandafter{\xs_reserved_C}}}% + }% + \__temp + \xs_read_reserved_D + }% + }% + {\xs_exptwoargs\xs_IfBeginWith_i\xs_reserved_D\xs_reserved_E + {\advance\decimalpart1 + \let\xs_reserved_D\xs_reserved_A + \xs_atoccurfound + }% + {\xs_exparg\xs_returnfirstsyntaxunit{\xs_reserved_D}\xs_reserved_A + \xs_exparg\xs_removefirstsyntaxunit{\xs_reserved_D}\xs_reserved_D + \xs_exploregroups + \xs_ifx{\bgroup\xs_toks} + {\advance\integerpart1 + \begingroup + \expandafter\def\expandafter\xs_reserved_D\xs_reserved_A + \xs_calc_grouIP + \let\xs_reserved_C\empty + \def\xs_nestlevel{1}% + \integerpart0 + } + {\xs_eaddtomacro\xs_reserved_C{\xs_reserved_A}% + }% + }% + \xs_read_reserved_D + }% +} + +\xs_newmacro\StrRemoveBraces{}{1}{1}{% + \def\xs_reserved_C{#1}% + \let\xs_reserved_B\empty + \def\xs_nestlevel{0}% + \xs_StrRemoveBraces_i + \xs_exparg\xs_assign_xstringresult{\xs_reserved_B}{#2}% +} + +\def\xs_StrRemoveBraces_i{% + \xs_exparg\xs_ifempty{\xs_reserved_C}% + {\xs_ifnum{\xs_nestlevel=0 } + {} + {\xs_endgroup_eaddtomacro\xs_reserved_B\xs_reserved_B + \xs_StrRemoveBraces_i + }% + } + {\xs_exparg\xs_returnfirstsyntaxunit{\xs_reserved_C}\xs_reserved_A + \xs_exparg\xs_removefirstsyntaxunit{\xs_reserved_C}\xs_reserved_C + \xs_ifx{\bgroup\xs_toks} + {\xs_ifx{\xs_exploregroups\relax}% on explore les groupes ? + {\begingroup + \expandafter\def\expandafter\xs_reserved_C\xs_reserved_A + \def\xs_nestlevel{1}% + \let\xs_reserved_B\empty + } + {\expandafter\xs_addtomacro\expandafter\xs_reserved_B\xs_reserved_A + }% + } + {\xs_eaddtomacro\xs_reserved_B{\xs_reserved_A}% + }% + \xs_StrRemoveBraces_i + }% +} + +% \xs_cutafteroccur coupe l'argument #1 après la #3ème occurrence de #2 +% \xs_reserved_C : contient ce qui se trouve avant cette occurrence +% \xs_reserved_D : contient ce qui se trouve avant cette occurrence y compris cette occurrence +% \xs_reserved_E : contient ce qui se trouve après l'occurrence +% si l'occurrence n'existe pas ou qu'un des arguments est vide, toutes les chaines renvoyées sont vides +\long\def\xs_cutafteroccur#1#2#3{% + \xs_ifnum{#3<1 } + {\let\xs_reserved_C\empty\let\xs_reserved_E\empty\gdef\groupID{}} + {\xs_cutafteroccur_i{#1}{#2}{#3}}% +} + +\long\def\xs_cutafteroccur_i#1#2#3{% + \def\xs_reserved_D{#1}\let\xs_reserved_C\empty\def\xs_reserved_E{#2}% + \decimalpart0 \integerpart0 \gdef\groupID{0}\def\xs_nestlevel{0}% + \def\xs_atoccurfound{% + \xs_ifnum{\decimalpart=\numexpr(#3)\relax} + {\edef\__temp{% + \def\noexpand\xs_reserved_C{\unexpanded\expandafter{\xs_reserved_C}}% + \def\noexpand\xs_reserved_D{\unexpanded\expandafter{\xs_reserved_D}}% + \noexpand\decimalpart=\number\decimalpart\relax + }% + \expandafter\xs_exitallgroups\__temp + \xs_gobarg% mange l'appel récursif \xs_read_reserved_D dans \xs_read_reserved_D + } + {\xs_eaddtomacro\xs_reserved_C{\xs_reserved_E}% + }% + }% + \xs_read_reserved_D + \xs_ifnum{\decimalpart=\numexpr(#3)\relax}% occurrence trouvée ? + {\let\xs_reserved_E\xs_reserved_D + \xs_exparg{\def\xs_reserved_D}{\xs_reserved_C#2}% + } + {\let\xs_reserved_C\empty + \let\xs_reserved_E\empty + \gdef\groupID{}% + }% +} + +\xs_newmacro*3\IfSubStr{1}{2}{0}{% + \xs_cutafteroccur{#2}{#3}{#1}% + \xs_exparg\xs_ifempty{\xs_reserved_D}\xs_execsecond\xs_execfirst +} + +\xs_newmacro*2\IfBeginWith{}{2}{0}{% + \xs_ifempty{#2}% + {\xs_execsecond} + {\xs_IfBeginWith_i{#1}{#2}}% +} + +\long\def\xs_IfBeginWith_i#1#2{% + \xs_ifempty{#2}% + {\xs_execfirst% #2 est vide, tous les tests sont passés avec succès : on renvoie #3 + } + {\xs_ifempty{#1}% + {\xs_execsecond% #1 est vide, c'est que #2 est + long que #1 : on renvoie #4 + } + {\xs_returnfirstsyntaxunit{#2}\xs_reserved_B + \xs_returnfirstsyntaxunit{#1}\xs_reserved_A + \xs_ifx{\xs_reserved_A\xs_reserved_B}% il y a égalité... + {\xs_removefirstsyntaxunit{#2}\xs_reserved_B + \xs_removefirstsyntaxunit{#1}\xs_reserved_A% on enlève les 1ere unités syntaxiques + \xs_exptwoargs\xs_IfBeginWith_i\xs_reserved_A\xs_reserved_B + } + {\xs_execsecond + }% + }% + }% +} + +\xs_newmacro*2\IfEndWith{}{2}{0}{% + \xs_ifempty{#2}% + {\xs_execsecond + } + {\xs_StrCount{#1}{#2}[\xs_reserved_A]% + \xs_ifnum{\xs_reserved_A=0 } + {\xs_execsecond} + {\xs_exparg\xs_ifempty{\xs_reserved_C}}% + }% +} + +\xs_newmacro*4\IfSubStrBefore{1,1}{3}{0}{\xs_IfSubStrBefore_i[#1]{#2}{#3}{#4}} + +\def\xs_IfSubStrBefore_i[#1,#2]#3#4#5{% + \def\xs_reserved_C{#3}% + \xs_ifx{\xs_exploregroups\relax}% si on explore les groupes + {\let\xs_reserved_B\empty + \def\xs_nestlevel{0}% + \xs_StrRemoveBraces_i% on retire les accolades + \let\xs_reserved_C\xs_reserved_B + } + {}% + \xs_exparg\xs_cutafteroccur\xs_reserved_C{#5}{#2}% + \xs_exparg\xs_cutafteroccur\xs_reserved_C{#4}{#1}% + \gdef\groupID{}% + \xs_exparg\xs_ifempty{\xs_reserved_C}% + \xs_execsecond + \xs_execfirst +} + +\xs_newmacro*4\IfSubStrBehind{1,1}{3}{0}{\xs_IfSubStrBehind_i[#1]{#2}{#3}{#4}} +\long\def\xs_IfSubStrBehind_i[#1,#2]#3#4#5{\xs_IfSubStrBefore_i[#2,#1]{#3}{#5}{#4}} + +\long\def\xs_formatnumber#1#2{% + \xs_ifempty{#1}% + {\def#2{0X}% si vide, renvoie 0X + } + {\xs_returnfirstsyntaxunit{#1}\xs_reserved_A + \def\xs_reserved_B{+}% + \xs_ifx{\xs_reserved_A\xs_reserved_B} + {\xs_removefirstsyntaxunit{#1}\xs_reserved_C + \xs_exparg\xs_ifempty{\xs_reserved_C}% + {\def#2{+0X}} + {\xs_exparg{\def#2}{\expandafter+\expandafter0\xs_reserved_C}}% + } + {\def\xs_reserved_B{-}% + \xs_ifx{\xs_reserved_A\xs_reserved_B} + {\xs_removefirstsyntaxunit{#1}\xs_reserved_A + \xs_exparg\xs_ifempty{\xs_reserved_A}% + {\def#2{-0X}}% + {\xs_exparg{\def#2}{\expandafter-\expandafter0\xs_reserved_A}}% + } + {\def#2{0#1}% + }% + }% + }% +} + +\xs_newmacro\IfInteger{}{1}{0}{% + \xs_formatnumber{#1}\xs_reserved_A + \decimalpart0 + \afterassignment\xs_defafterinteger\integerpart\xs_reserved_A\relax\_nil + \let\xs_after_intpart\afterinteger + \expandafter\xs_testdot\afterinteger\_nil + \xs_ifx{\empty\afterdecimal} + {\xs_ifnum{\decimalpart=0 } + {\xs_execfirst% partie décimale constituée de 0 --> seul cas où on renvoie vrai + } + {\expandafter\xs_defafterinteger\xs_after_intpart\relax\_nil + \xs_execsecond + }% + } + {\expandafter\xs_defafterinteger\xs_after_intpart\relax\_nil + \xs_execsecond + }% +} + +\xs_newmacro\IfDecimal{}{1}{0}{% + \xs_formatnumber{#1}\xs_reserved_A + \decimalpart0 + \afterassignment\xs_defafterinteger\integerpart\xs_reserved_A\relax\_nil + \expandafter\xs_testdot\afterinteger\_nil + \xs_ifx{\empty\afterdecimal} +} + +\begingroup\catcode`\@ 11 +\long\gdef\xs_defafterinteger#1\relax\_nil{\def\@xs@afterinteger{#1}\let\afterinteger\@xs@afterinteger} +\long\gdef\xs_defafterdecimal#1\_nil{\def\@xs@afterdecimal{#1}\let\afterdecimal\@xs@afterinteger} +\endgroup + +\def\xs_testdot{% + \let\xs_decsep\empty + \xs_ifnxttok. + {\def\xs_decsep{.}\xs_readdecimalpart}% + {\xs_testcomma}% +} + +\def\xs_testcomma{% + \xs_ifnxttok, + {\def\xs_dessep{,}\xs_readdecimalpart}% + {\xs_defafterdecimal}% +} + +\long\def\xs_readdecimalpart#1#2\_nil{% + \xs_ifempty{#2} + {\def\xs_reserved_A{0X}} + {\def\xs_reserved_A{0#2}}% + \afterassignment\xs_defafterinteger\decimalpart\xs_reserved_A\relax\_nil + \expandafter\xs_defafterdecimal\afterinteger\_nil +} + +% test d'égalité sur des chaines (et des chaines contenant des nombres) +\long\def\xs_IfStrEqFalse_i#1#2{\let\xs_reserved_A\xs_execsecond} +\long\def\xs_IfStrEqFalse_ii#1#2{% renvoie vrai si les 2 arg sont décimaux et s'ils sont égaux, faux sinon + \xs_IfDecimal{#1}% + {\xs_IfDecimal{#2}% + {\ifdim#1pt=#2pt + \let\xs_reserved_A\xs_execfirst + \else + \let\xs_reserved_A\xs_execsecond + \fi% les 2 sont décimaux : on fait le test + }% + {\let\xs_reserved_A\xs_execsecond}% un seul est décimal + }% + {\let\xs_reserved_A\xs_execsecond}% #1 n'est pas décimal +} + +\long\def\xs_TestEqual#1#2{% teste si les 2 arguments sont égaux + \def\xs_reserved_A{#1}\def\xs_reserved_B{#2}% + \xs_ifx{\xs_reserved_A\xs_reserved_B} + {\let\xs_reserved_A\xs_execfirst}% égalité parfaite des 2 chaines + {\xs_reserved_D{#1}{#2}}% + \xs_reserved_A +} + +\xs_newmacro*2\IfStrEq{}{2}{0}{% teste si les deux chaines sont égales + \let\xs_reserved_D\xs_IfStrEqFalse_i + \xs_TestEqual{#1}{#2}% +} + +\xs_newmacro*2\IfEq{}{2}{0}{% teste si les 2 arguments (chaine ou nombre) sont égaux + \let\xs_reserved_D\xs_IfStrEqFalse_ii + \xs_TestEqual{#1}{#2}% +} + +\def\IfStrEqCase{% + \xs_ifstar + {\xs_IfStringCase{\IfStrEq*}}% + {\xs_IfStringCase\IfStrEq}% +} + +\def\IfEqCase{% + \xs_ifstar + {\xs_IfStringCase{\IfEq*}}% + {\xs_IfStringCase\IfEq}% +} + +\long\def\xs_IfStringCase#1#2#3{% #1=macro avec ou sans étoile #2=argument à tester #3=liste des {<cas>}{code>} + \long\def\xs_testcase##1##2##3\_nil{% lit les 2 premieres unités syntaxiques dans ##1 et ##2. Les autres dans ##3 + #1{#2}{##1}% compare + {\xs_testopt{\xs_IfStringCase_ii{##2}}{}}% le test est positif, on exécute le code correspondant et on mange l'argument optionnel ## BUGfix dans 1.82 + {\xs_ifempty{##3}% + {\xs_testopt{\xs_IfStringCase_i}{}}% s'il n'y a plus de cas, on exécute le code <autres cas> ## BUGfix dans 1.82 + {\xs_testcase##3\_nil}% sinon, on recommence avec ce qui reste + }% + }% + \xs_testcase#3\_nil +} + +\long\def\xs_IfStringCase_i[#1]{#1} +\long\def\xs_IfStringCase_ii#1[#2]{#1} + +% Renvoie ce qui est à gauche de l'occurence n°#1 de la sous chaine #3 dans la chaine #2 +\xs_newmacro*3\StrBefore{1}{2}{1}{% + \xs_cutafteroccur{#2}{#3}{#1}% + \xs_exparg\xs_assign_xstringresult{\xs_reserved_C}{#4}% +} + +% Renvoie ce qui est à droite de l'occurence n°#1 de la sous chaine #3 dans la chaine #2 +\xs_newmacro*3\StrBehind{1}{2}{1}{% + \xs_cutafteroccur{#2}{#3}{#1}% + \xs_exparg\xs_assign_xstringresult{\xs_reserved_E}{#4}% +} + +% Renvoie ce qui est strictement compris entre les occurrences n°#1 et n°#2 +% des chaines #4 et #5 dans la chaine #3 +\xs_newmacro*4\StrBetween{1,1}{3}{1}{\xs_StrBetween_i[#1]{#2}{#3}{#4}[#5]} +\long\def\xs_StrBetween_i[#1,#2]#3#4#5[#6]{% + \begingroup + \noexploregroups + \xs_cutafteroccur{#3}{#5}{#2}% + \xs_exparg\xs_cutafteroccur{\xs_reserved_C}{#4}{#1}% + \expandafter + \endgroup + \expandafter\xs_assign_xstringresult\expandafter{\xs_reserved_E}{#6}% + \gdef\groupID{}% +} + +\def\exploregroups{\let\xs_exploregroups\relax} +\def\noexploregroups{\def\xs_exploregroups{\let\xs_toks\relax}} +\def\saveexploremode{\let\xs_saveexploremode\xs_exploregroups} +\def\restoreexploremode{\let\xs_exploregroups\xs_saveexploremode} + +% Remplace les #1 premières occurences de la chaine #3 +% par la chaine #4 dans la chaine #2 +\xs_newmacro\StrSubstitute{0}{3}{1}{% + \def\xs_reserved_D{#2}\let\xs_reserved_C\empty\def\xs_reserved_E{#3}% + \decimalpart0 \integerpart0 \gdef\groupID{0}\def\xs_nestlevel{0}% + \def\xs_atoccurfound{% + \xs_ifnum{#1<1 } + {\def\xs_reserved_A{#4}} + {\xs_ifnum{\decimalpart>#1 } + {\def\xs_reserved_A{#3}} + {\def\xs_reserved_A{#4}}% + }% + \xs_eaddtomacro\xs_reserved_C{\xs_reserved_A}% + }% + \xs_ifempty{#3}% + {\xs_exparg\xs_assign_xstringresult{\xs_reserved_D}{#5}% + } + {\xs_read_reserved_D + \xs_exparg\xs_assign_xstringresult{\xs_reserved_C}{#5}% + }% +} + +% Supprime les #1 premières occurrences de #3 dans #2 +\xs_newmacro\StrDel{0}{2}{1}{\xs_StrSubstitute[#1]{#2}{#3}{}[#4]} + +\def\xs_exitallgroups{\ifnum\xs_nestlevel>0 \endgroup\expandafter\xs_exitallgroups\fi} + +% Compte combien d'unités syntaxiques contient la chaine #1 ? +\xs_newmacro\StrLen{}{1}{1}{% + \def\xs_reserved_C{#1}\decimalpart0 \def\xs_nestlevel{0}\gdef\groupID{0}% + \let\xs_atbegingroup\relax + \def\xs_atendofgroup{\expandafter\endgroup\expandafter\decimalpart\number\decimalpart\relax}% + \let\xs_atnextsyntaxunit\relax + \xs_read_reserved_C + \xs_exparg\xs_assign_xstringresult{\number\decimalpart}{#2}% +} + +% Macro interne fermant autant de groupes que nécessaire pour trouver une unité syntaxique derrière +\def\xs_continuetonext{% + \xs_exparg\xs_ifempty{\xs_reserved_C}% + {\ifnum\xs_nestlevel>0 + \xs_endgroup_eaddtomacro\xs_reserved_B{\expandafter{\xs_reserved_B}}% on concatène + \expandafter\xs_continuetonext% on recommence + \fi} + {}% +}% + +\def\xs_calc_grouIP{% + \begingroup\def\xs_reserved_A{0}% + \xs_ifx{\xs_reserved_A\groupID}% si on arrive du groupe de niveau 0 + {\endgroup\xdef\groupID{\number\integerpart}}% on met simplement le niveau + {\endgroup\xs_eearg{\gdef\groupID}{\expandafter\groupID\expandafter,\number\integerpart}}% +} + +% Cette macro coupe la chaine #1 après l'unité syntaxique n°#2 +\def\StrSplit{% + \xs_ifstar + {\let\xs_reserved_E\xs_continuetonext\StrSplit_i}% + {\let\xs_reserved_E\relax\StrSplit_i}% +} + +\xs_newmacro\StrSplit_i{}{2}{0}{\xs_StrSplit_ii{#2}{#1}\xs_StrSplit_iii} + +% Cette macro interne coupe la chaine #2 après l'unité syntaxique n°#1 +% Le début est assigné dans \xs_reserved_B et la fin dans \xs_reserved_C +\long\def\xs_StrSplit_ii#1#2{% + \let\xs_reserved_B\empty\def\xs_reserved_C{#2}\def\xs_reserved_D{#1}\gdef\groupID{}% + \ifnum#1>0 + \decimalpart0 \integerpart0 \gdef\groupID{0}\def\xs_nestlevel{0}% + \def\xs_atendofgroup{% + \edef\__temp{% + \endgroup + \noexpand\decimalpart=\number\decimalpart\relax + \unexpanded{\xs_addtomacro\xs_reserved_B}{{\unexpanded\expandafter{\xs_reserved_B}}}% + }% + \__temp + }% + \def\xs_atbegingroup{\let\xs_reserved_B\empty}% + \def\xs_atnextsyntaxunit{% + \xs_eaddtomacro\xs_reserved_B{\xs_reserved_A}% + \xs_ifnum{\decimalpart=\xs_reserved_D\relax} + {\ifx\xs_reserved_C\empty\xs_reserved_E\fi + \edef\__temp{\def\noexpand\xs_reserved_B{\unexpanded\expandafter{\xs_reserved_B}}\def\noexpand\xs_reserved_C{\unexpanded\expandafter{\xs_reserved_C}}}% + \expandafter\xs_exitallgroups\__temp + \xs_gobarg% mange l'appel récursif \xs_read_reserved_C dans \xs_read_reserved_C + } + {}% + }% + \xs_read_reserved_C + \fi +} + +\def\xs_StrSplit_iii#1#2{\let#1\xs_reserved_B\let#2\xs_reserved_C} + +% StrCut[n]{<texte>}{<motif>}\macroA\macroB +% \macroA reçoit ce qui se trouve avant la n ème occurrence <motif> dans <texte> +% \macroB reçoit ce qui est après cette n ème occurrence +\xs_newmacro*3\StrCut{1}{2}{0}{% + \xs_ifempty{#3}% + {\gdef\groupID{}\let\xs_reserved_C\empty\let\xs_reserved_E\empty + } + {\xs_ifnum{#1<1 } + {\xs_StrCut_ii{#2}{#3}1} + {\xs_StrCut_ii{#2}{#3}{#1}}% + }% + \xs_StrCut_iii +} + +\long\def\xs_StrCut_ii#1#2#3{% + \let\xs_reserved_C\empty\def\xs_reserved_D{#1}\def\xs_reserved_E{#2}% + \decimalpart0 \integerpart0 \gdef\groupID{0}\def\xs_nestlevel{0}% + \def\xs_atoccurfound{% + \xs_ifnum{\decimalpart=\numexpr(#3)\relax} + {\edef\__temp{% + \def\noexpand\xs_reserved_C{\unexpanded\expandafter{\xs_reserved_C}}% + \def\noexpand\xs_reserved_D{\unexpanded\expandafter{\xs_reserved_D}}% + \noexpand\decimalpart=\number\decimalpart\relax + }% + \expandafter\xs_exitallgroups\__temp + \xs_gobarg% stoppe la récursivité dans \xs_read_reserved_D + } + {\xs_eaddtomacro\xs_reserved_C{\xs_reserved_E}% + }% + }% + \xs_read_reserved_D + \let\xs_reserved_E\xs_reserved_D + \xs_exparg{\def\xs_reserved_D}{\xs_reserved_C#2}% +} + +\long\def\xs_StrCut_iii#1#2{\let#1\xs_reserved_C\let#2\xs_reserved_E} + +% De la chaine #1, renvoie ce qui se trouve entre les positions +% #2 et #3, unités syntaxiques aux positions compris ! +\xs_newmacro\StrMid{}{3}{1}{% + \begingroup + \noexploregroups + \let\xs_reserved_E\relax + \xs_StrSplit_ii{#3}{#1}% + \edef\xs_reserved_C{\number\numexpr#2-1}% + \let\xs_reserved_E\relax + \xs_exptwoargs\xs_StrSplit_ii\xs_reserved_C\xs_reserved_B + \expandafter\endgroup + \expandafter\xs_assign_xstringresult\expandafter{\xs_reserved_C}{#4}% + \gdef\groupID{}% +} + +% supprime #2 unités syntaxiques à gauche dans la chaine #1 +\xs_newmacro\StrGobbleLeft{}{2}{1}{% + \let\xs_reserved_E\relax + \xs_StrSplit_ii{#2}{#1}% + \xs_exparg\xs_assign_xstringresult{\xs_reserved_C}{#3}% +} + +% extrait de #1 la chaine à gauche de longueur #2 +\xs_newmacro\StrLeft{}{2}{1}{% + \let\xs_reserved_E\relax + \xs_StrSplit_ii{#2}{#1}% + \xs_exparg\xs_assign_xstringresult{\xs_reserved_B}{#3}% +} + +% supprime #2 unités syntaxiques à droite dans la chaine #1 +\xs_newmacro\StrGobbleRight{}{2}{1}{% + \xs_StrLen{#1}[\xs_reserved_D]% + \let\xs_reserved_E\relax + \xs_exparg\xs_StrSplit_ii{\number\numexpr\xs_reserved_D-#2}{#1}% + \xs_exparg\xs_assign_xstringresult{\xs_reserved_B}{#3}% +} + +% renvoie #2 unités syntaxiques à la droite de la chaine #1 +\xs_newmacro\StrRight{}{2}{1}{% + \xs_StrLen{#1}[\xs_reserved_D]% + \let\xs_reserved_E\relax + \xs_exparg\xs_StrSplit_ii{\number\numexpr\xs_reserved_D-#2}{#1}% + \xs_exparg\xs_assign_xstringresult{\xs_reserved_C}{#3}% +} + +\xs_newmacro\StrChar{}{2}{1}{% + \let\xs_reserved_B\empty\def\xs_reserved_C{#1}\def\xs_reserved_D{#2}% + \ifnum#2>0 + \def\groupID{0}\def\xs_nestlevel{0}\integerpart0 \decimalpart0 + \let\xs_atbegingroup\relax + \def\xs_atendofgroup{\expandafter\endgroup\expandafter\decimalpart\number\decimalpart\relax}% + \def\xs_atnextsyntaxunit{% + \ifnum\decimalpart=\xs_reserved_D% la n ième US est atteinte ? + \edef\__temp{\def\noexpand\xs_reserved_B{\unexpanded\expandafter{\xs_reserved_A}}}% on capture l'US en cours qui est celle cherchée + \expandafter\xs_exitallgroups\__temp + \expandafter\xs_gobarg% stoppe la récursivité dans \xs_read_reserved_C + \fi + }% + \xs_read_reserved_C + \fi + \xs_exparg\xs_ifempty{\xs_reserved_B}% + {\gdef\groupID{}} + {}% + \xs_exparg\xs_assign_xstringresult{\xs_reserved_B}{#3}% +} + +% Combien de fois compte t-on #2 dans #1 ? +\xs_newmacro\StrCount{}{2}{1}{% + \def\xs_reserved_D{#1}\def\xs_reserved_E{#2}\let\xs_reserved_C\empty + \xs_ifempty{#2}% + {\xs_assign_xstringresult{0}{#3}% + } + {\decimalpart0 \integerpart0 \gdef\groupID{0}\def\xs_nestlevel{0}% + \def\xs_atoccurfound{\let\xs_reserved_C\empty\xs_read_reserved_D}% + \xs_read_reserved_D + \xs_exparg\xs_assign_xstringresult{\number\decimalpart}{#3}% + }% +} + +% renvoie la position de l'occurrence #1 de la sous chaine #3 dans la chaine #2 +\xs_newmacro\StrPosition{1}{2}{1}{% + \xs_cutafteroccur{#2}{#3}{#1}% + \let\xs_reserved_E\groupID + \xs_ifx{\xs_reserved_C\xs_reserved_D} + {\xs_assign_xstringresult{0}{#4}% + \let\xs_reserved_E\empty + } + {\xs_exparg\xs_StrLen{\xs_reserved_C}[\xs_reserved_C]% + \xs_exparg\xs_assign_xstringresult{\number\numexpr\xs_reserved_C+1}{#4}% + }% + \global\let\groupID\xs_reserved_E +} + +\def\comparestrict{\def\xs_comparecoeff{1}} +\def\comparenormal{\def\xs_comparecoeff{0}} +\def\savecomparemode{\let\xs_saved_comparecoeff\xs_comparecoeff} +\def\restorecomparemode{\let\xs_comparecoeff\xs_saved_comparecoeff} + +% Compare les deux arguments #1 et #2 +% Renvoie 0 s'ils sont égaux et renvoie la +% position de la premiere unité syntaxiques différente sinon +\xs_newmacro*2\StrCompare{}{2}{1}{% + \def\xs_reserved_A{#1}% + \def\xs_reserved_B{#2}% + \xs_ifx{\xs_reserved_B\xs_reserved_A} + {\xs_assign_xstringresult{0}{#3}} + {\xs_StrCompare_i{#1}{#2}{#3}}% +} + +\long\def\xs_StrCompare_i#1#2#3{% + \def\xs_StrCompare_iii##1{% + \let\xs_reserved_A\empty + \xs_exparg\xs_ifempty{\xs_reserved_C}% + {\edef\xs_reserved_A{*\xs_comparecoeff}}% + {\xs_exparg\xs_ifempty{\xs_reserved_D}% + {\edef\xs_reserved_A{*\xs_comparecoeff}} + {}% + }% + \def\xs_next{\xs_exparg\xs_assign_xstringresult{\number\numexpr##1\xs_reserved_A\relax}{#3}}% + }% + \def\xs_StrCompare_ii##1{% ##1 est la position + \xs_exparg\xs_returnfirstsyntaxunit{\xs_reserved_C}\xs_reserved_A + \xs_exparg\xs_returnfirstsyntaxunit{\xs_reserved_D}\xs_reserved_B + \xs_ifx{\xs_reserved_B\xs_reserved_A} + {\xs_exparg\xs_ifempty{\xs_reserved_A}% + {\xs_StrCompare_iii{##1}% les 2 unités syntaxiques sont égales, on renvoie la position + } + {\def\xs_next{\xs_exparg\xs_StrCompare_ii{\number\numexpr##1+1}}% les 2 unités syntaxiques sont égales et non vides, on recommence + \xs_exparg\xs_removefirstsyntaxunit{\xs_reserved_C}\xs_reserved_C + \xs_exparg\xs_removefirstsyntaxunit{\xs_reserved_D}\xs_reserved_D + }% + }% les 2 unités syntaxiques sont différentes : on renvoie la position + {\xs_StrCompare_iii{##1}% + }% + \xs_next + }% + \def\xs_reserved_C{#1}\def\xs_reserved_D{#2}% + \xs_StrCompare_ii1% +} + +\xs_newmacro\StrFindGroup{}{2}{1}{% + \def\xs_reserved_A{#2}\def\xs_reserved_B{0}% + \xs_ifx{\xs_reserved_A\xs_reserved_B} + {\xs_assign_xstringresult{{#1}}{#3}} + {\xs_StrFindGroup_i{#1}{#2}[#3]}% +} + +\long\def\xs_StrFindGroup_i#1#2[#3]{% + \def\xs_StrFindGroup_ii{% + \xs_exparg\xs_ifempty{\xs_reserved_C}% + {\xs_assign_xstringresult{}{#3}% s'il ne reste plus rien, on renvoie vide + } + {\xs_exparg\xs_returnfirstsyntaxunit{\xs_reserved_C}\xs_reserved_D + \xs_ifx{\bgroup\xs_toks}% si la 1ère unité syntaxique est un groupe explicite + {\advance\decimalpart1 % on augmente le compteur + \xs_ifnum{\decimalpart=\xs_reserved_A\relax}% on est au groupe cherché lors de la profondeur courante ? + {\xs_ifx{\empty\xs_reserved_B}% on est à la profondeur maximale ? + {\xs_exparg\xs_assign_xstringresult{\xs_reserved_D}{#3}}% on renvoie ce groupe + {\xs_exparg{\expandafter\xs_StrFindGroup_i\xs_reserved_D}{\xs_reserved_B}[#3]}% on recommence avec ce groupe et les profondeurs de recherche restantes + } + {\xs_exparg\xs_removefirstsyntaxunit{\xs_reserved_C}\xs_reserved_C + \xs_StrFindGroup_ii + }% + } + {\xs_exparg\xs_removefirstsyntaxunit{\xs_reserved_C}\xs_reserved_C + \xs_StrFindGroup_ii + }% + }% + }% + \xs_extractgroupnumber{#2}\xs_reserved_A\xs_reserved_B + \decimalpart0 + \xs_ifnum{\xs_reserved_A>0 } + {\def\xs_reserved_C{#1}} + {\let\xs_reserved_C\empty}% + \xs_StrFindGroup_ii +} + +\def\xs_extractgroupnumber#1#2#3{% + \def\xs_extractgroupnumber_i##1,##2\_nil{\def#2{##1}\def#3{##2}}% + \xs_extractgroupnumber_i#1,\_nil + \ifx\empty#3\else\xs_extractgroupnumber_i#1\_nil\fi +} + +\def\expandingroups{\let\xs_expandingroups\exploregroups} + +\def\noexpandingroups{\let\xs_expandingroups\noexploregroups} + +\def\StrExpand{\xs_testopt{\xs_StrExpand}{1}} +\long\def\xs_StrExpand[#1]#2#3{% + \begingroup + \xs_expandingroups + \xs_ifnum{#1>0 } + {\integerpart#1 \decimalpart0 \gdef\groupID{0}\def\xs_nestlevel{0}% + \def\xs_atendofgroup{\xs_endgroup_eaddtomacro\xs_reserved_B{\expandafter{\xs_reserved_B}}}% + \def\xs_atbegingroup{\let\xs_reserved_B\empty}% + \def\xs_atnextsyntaxunit{\xs_eeaddtomacro\xs_reserved_B{\xs_reserved_A}}% + \def\xs_reserved_C{#2}% + \xs_StrExpand_i{#1}% Appel de la macro récursive + } + {\def\xs_reserved_B{#2}% + } + \expandafter + \endgroup + \expandafter\def\expandafter#3\expandafter{\xs_reserved_B}% + \gdef\groupID{}% +} + +\long\def\xs_StrExpand_i#1{% + \xs_ifnum{#1>0 } + {\let\xs_reserved_B\empty + \xs_read_reserved_C + \let\xs_reserved_C\xs_reserved_B + \def\xs_reserved_A{\xs_exparg\xs_StrExpand_i{\number\numexpr#1-1}}% + } + {\let\xs_reserved_A\relax + }% + \xs_reserved_A +} + +\def\scancs{\xs_testopt{\xs_scancs}{1}} +\long\def\xs_scancs[#1]#2#3{% + \xs_StrExpand[#1]{#3}{#2}% + \edef#2{\detokenize\expandafter{#2}}% +} + +\restorexstringcatcode + +\setverbdelim{|}% +\fullexpandarg\saveexpandmode +\comparenormal\savecomparemode +\noexploregroups\saveexploremode +\expandingroups + +\endinput + + H I S T O R I Q U E +------------------------------------------------------------------------------ +v1.0 4/7/2008 : - Package achevé. + 7/7/2008 : - Package publié sur CTAN. +------------------------------------------------------------------------------ +v1.1 15/8/2008 + - Le package ne nécessite plus LaTeX et est désormais utilisable sous + Plain eTeX. + - Ajout des macros \IfInteger et \IfDecimal. + Pour cette dernière, la partie entière et la partie décimale sont + récupérables dans les compteurs \integerpart et \decimalpart. Ce + qu'il reste après qu'un caractère non attendu soit rencontré est + dispo dans \xs_remainafterdecimal + - Correction d'un bug dans \tokenize : + suppression de l'expansion avec \normalexpandarg pour éviter le bug + avec les lettres accentuées dans l'exemple : \tokenize\aa{éù} + - Amélioration du code de la plupart des macros. + - écriture d'une routine \xs_newmacro définissant les macros. + - Suppression de tous les compteurs grace à \numexpr. + - Nouvelles fonctionnalités internes dans : + \IfSubStr + ajout des chaines se trouvant avant et après l'occurrence testée + dans les sc \xs_behind_IfSubStr et \xs_before_IfSubStr + \StrCount + a) ajout de ce qui se trouve après la dernière occurrence dans la + sc \xs_StrCount_afterlastocccur + b) la macro ne dépend plus d'aucune autre +------------------------------------------------------------------------------ +v1.2 23/8/2008 + - Amélioration du code de \StrMid \StrGobbleLeft, \StrLeft, + \StrGobbleRight et \StrRight à l'aide de la nouvelle macro + \xs_StrSplit_i + - Nouveau test \IfStrEq qui compare 2 chaines + - Nouveau test \IfEq qui compare 2 chaines (ou 2 nombres si les 2 chaines + contiennent un nombre) + - Correction d'un bug dans \xs_formatnumber. La macro n'envisageait pas le + cas où son argument était vide ce qui faiasait planter + \IfDecimal{}{V}{F} et \IfInteger{}{V}{F} +------------------------------------------------------------------------------ +v1.3 21/9/2008 + - Amélioration du code, mise en place de récursivités terminales dans + toutes les macros récursives, simplification de \xs_TestEqual en + utilisant \ifx + - Nouvelles macros \IfStrEqCase et \IfEqCase + Teste si une chaîne est égale à plusieurs chaines données et + exécute un code spécifique + - Création de la macro publique \StrSplit + Coupe la chaine en 2 à une position donnée + - Nouvelle macro \StrCompare + Compare 2 chaînes et renvoie la position du 1er caractère différent. + Renvoie 0 si elles sont égales. +------------------------------------------------------------------------------ +v1.3a 29/9/2008 + - Correction d'un bug : \expandafter#1 + dans les macros \IfSubStrBefore et \StrBetween qui buggue si #1 est un + nombre > 9 ! + - Ré écriture de \xs_returnfirstsyntaxunit et \xs_gobarg qui + deviennent purement développables. + - Ré écriture de \StrLen + - Nouvelle macro interne \xs_cutafteroccur + Coupe la chaine après la nième occurrence d'une sous chaine. + - Code amélioré de \StrMid, \StrLeft, \StrGobbleLeft, \StrRight, + \StrGobbleRight grace à \xs_cutafteroccur +------------------------------------------------------------------------------ +v1.4 4/11/2008 + - xstring traite ses arguments par unité syntaxique, et donc toutes les + macros internes ont été ré-écrites à cette fin. + - Le manuel a été ré-écrit, rendu plus clair et mieux structuré. + - Nouvelle fonctionnalité : \expandarg + le 1er lexème de chaque argument est 1-développé avant que la + macro ne soit appelée. Si un argument comporte plus qu'1 lexème, + il faut passer par \scancs*[1] pour 1-développer toutes les unités + syntaxiques. + - Correction de 2 erreurs dans le manuel anglais : 0 est la valeur par + défaut dans \StrSubstitute et \StrDel + - Cohérence dans les nom des séquences de contrôles temporaires qui + sont désormais : \xs_reserved_A à \xs_reserved_E +------------------------------------------------------------------------------ +v1.4a 12/11/2008 + - Correction d'un bug dans \xs_StrSplit dans le cas où l'argument + numérique est <1 : la 1ere coupure doit être vide et le seconde doit + être égale à l'argument. +------------------------------------------------------------------------------ +v1.4b 16/11/2008 + - Correction de 2 bugs dans \xs_returnfirstsyntaxunit +------------------------------------------------------------------------------ +v1.5 31/12/2008 + - Nouvelles fonctionnalités dans la recherche de groupes par un + identificateur caractérisant leur imbrication. Implémentation de : + 1) \StrFindGroup + 2) \groupID + - Ajout des nouvelles macros génériques \xs_read_reserved_C et + \xs_read_reserved_D + - Correction d'un bug dans \StrSplit : \StrSplit{{a}bc}{1}[\truc] faisait + que \truc contenait «a{a}». + - Correction d'un bug dans \xs_newmacro : l'argument optionnel était + détokénisé à tort dans les macros étoilées. + - Dans \xs_newmacro, on doit choisir le numéro du dernier argument devant + être détokénisé dans le cas d'une macro étoilée (sachant que + l'argument optionnel ne l'est jamais) +------------------------------------------------------------------------------ +v1.5a 09/2/2009 + - Nouvelle macro \StrExpand, sensible au mode d'exploration. La macro est + indépendante du mode d'exploration et dispose de ses propres commandes + d'exploration : \expandingroups et \noexpandingroups + - Ré-écriture de \scancs, qui devient triviale puisque dépendant de + \StrExpand. Il n'y a plus de version étoilée et désormais, \scancs + est sensible au mode d'exploration. + - Correction d'un bug dans \IfInteger : \IfInteger{2.0}{V}{F} affichait F + - Correction de bugs : mettre \let\xs_reserved_E\relax avant d'appeler + \xs_StrSplit_i + - Suppression des messages d'erreur, de warning et d'info. xstring devient + donc silencieux ;) + - Passage de 3 à 2 compteurs + - Le manuel est désormais plus coloré, en espérant qu'il sera un peu + plus agréable à lire ! +------------------------------------------------------------------------------ +v1.5b 13/3/2009 + - Modification d'un grand nombre de macros de telle sorte que vraiment + n'importe quel code peut désormais être placé dans les arguments des + macros (comme par exemple des \if, \ifx ou autre, même sans leur \fi, ce + qui n'était pas possible jusqu'alors) +------------------------------------------------------------------------------ +v1.5c 05/6/2009 + - Correction d'un bug dans \IfBeginWith : il faut appeler + \xs_returnfirstsyntaxunit pour l'argument #2 puis pour l'argument #1 et + non pas l'inverse pour que \xs_toks reflète ce qui se trouve dans #1 + - Correction d'un bug dans \xs_returnfirstsyntaxunit au cas où #1 commence + par un espace : mettre \xs_toks à 0 + - Correction d'un bug dans \xs_returnfirstsyntaxunit : + \xs_returnfirstsyntaxunit{{}}\truc + faisait que \truc se développait en un espace. + - Correction d'un bug dans \xs_removefirstsyntaxunit où le cas + \xs_removefirstsyntaxunit{ {b}}\truc + donnait \truc se développant en «b» au lieu de «{b}». +------------------------------------------------------------------------------ +v1.5d 28/3/2010 + - Correction d'un bug dans \IfInteger : \afterinteger ne donnait pas le + bon résultat. Par exemple avec 1.23 il renvoyait {} au lieu de {.23} + - \xs_formatnumber ne detokenize plus ses arguments (que m'est-il passé + par la tête pour que je code un truc comme ca ?), et donc + \afterinteger et \xs_afterdecimal ont des tokens ayant le bon + catcode +------------------------------------------------------------------------------ +v1.6 24/10/2012 + - Correction d'un bug dans \xs_cutafteroccur au cas où #3<1 + - \IfDecimal ne \detokenize plus l'argument. + - Nouvelle version de \tokenize qui enlevait les accolades si son argument + était entre accolades + - Nouvelle macro \StrCut + - \xs_cutafteroccur_i ne produit plus d'espace indésirable si #3 était + évalué par \numexpr +------------------------------------------------------------------------------ +v1.7 13/1/2013 + - Correction d'un manque de rigueur dans les assignations concernant + \groupID : elles sont toutes globales désormais + - Les macros de xstring sont \long +------------------------------------------------------------------------------ +v1.7a 28/2/2013 + - Correction d'un espace parasite dans \xs_removefirstsyntaxunit +------------------------------------------------------------------------------ +v1.7b 29/7/2013 + - La date contenue dans \xstringdate est désormais conforme +------------------------------------------------------------------------------ +v1.7c 13/10/2013 + - les macros impliquées dans \IfStrCase et \IfStrEqCase sont désormais \long +------------------------------------------------------------------------------ +v1.8 07/12/2018 + - affectations globales supprimées (sauf pour \groupID) afin de ne pas + surcharger la pile de sauvegarde + - nettoyage du code, corrections de lourdeurs et maladresses +------------------------------------------------------------------------------ +v1.81 09/12/2018 + - bug dans \IfInteger et \IfDecimal, la macro \xs_afterdecimal est indéfinie + et doit être remplacée par \afterdecimal +------------------------------------------------------------------------------ +v1.82 01/02/2019 + - \xs_testopt n'est pas longue et provoque un bug dans \xs_IfStrCase et + \xs_IfStrCase lorsque #1 contient \par : \xs_testopt reste courte et + \xs_IfStringCase a été modifiée pour que cela fonctionne. + ------------------------------------------------------------------------------ +v1.83 06/02/2019 + - mauvaise approche et mauvais fix dans la v1.82 : \xs_testopt devient + longue, pas le choix (et donc aussi \xs_ifnxttok)
\ No newline at end of file |