% \iffalse % %\NeedsTeXFormat{LaTeX2e}[1999/12/01] %\ProvidesPackage{coolstr} % [2023/05/03 v2.2 COntent Oriented LaTeX Strings] %\RequirePackage{ifthen} %\RequirePackage{amsmath} %\RequirePackage{amssymb} % % Update on 2023/05/03 purely to clarify the license; no code changes. % This package is released under the GNU LGPL. % %<*driver> \documentclass{ltxdoc} \usepackage{coolstr} \usepackage{url} \usepackage{pdflscape} \EnableCrossrefs \CodelineIndex \RecordChanges \begin{document} \DocInput{coolstr.dtx} \end{document} % % \fi % % % \CheckSum{314} % % %% \CharacterTable %% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z %% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z %% Digits \0\1\2\3\4\5\6\7\8\9 %% Exclamation \! Double quote \" Hash (number) \# %% Dollar \$ Percent \% Ampersand \& %% Acute accent \' Left paren \( Right paren \) %% Asterisk \* Plus \+ Comma \, %% Minus \- Point \. Solidus \/ %% Colon \: Semicolon \; Less than \< %% Equals \= Greater than \> Question mark \? %% Commercial at \@ Left bracket \[ Backslash \\ %% Right bracket \] Circumflex \^ Underscore \_ %% Grave accent \` Left brace \{ Vertical bar \| %% Right brace \} Tilde \~} % % \changes{v1.0}{2006/09/17}{Initial Release} % \changes{v2.0}{2006/12/29}{Added three new commands: \texttt{ifstrchareq}, \texttt{ifstrleneq}, \texttt{strlen}} % % \GetFileInfo{coolstr.sty} % % \DoNotIndex{\#,\$,\%,\&,\@,\\,\{,\},\^,\_,\~,\ ,\!,\(,\),\,} % \DoNotIndex{\@ne,\expandafter} % \DoNotIndex{\advance,\begingroup,\catcode,\closein} % \DoNotIndex{\newcommand,\renewcommand,\providecommand} % \DoNotIndex{\closeout,\day,\def,\edef,\gdef,\xdef,\let,\empty,\endgroup} % \DoNotIndex{\newcounter,\providecounter,\addtocounter,\setcounter,\stepcounter,\value,\arabic} % \DoNotIndex{\if,\fi,\ifthenelse,\else,\setboolean,\boolean,\newboolean,\provideboolean,\equal,\AND,\OR,\NOT,\whiledo} % \DoNotIndex{\ifcase,\ifcat,\or,\else} % \DoNotIndex{\par,\parbox,\mbox,\hbox,\begin,\end,\nabla,\partial} % \DoNotIndex{\overline,\bar,\small,\tiny,\mathchoice,\scriptsize,\textrm,\texttt} % \DoNotIndex{\alpha,\beta,\gamma,\epsilon,\varepsilon,\delta,\zeta,\eta,\theta,\vartheta,\iota,\kappa,\lambda,\mu,\nu} % \DoNotIndex{\xi,\omicron,\pi,\varpi,\rho,\varrho,\sigma,\tau,\upsilon,\phi,\varphi,\chi,\psi,\omega} % \DoNotIndex{\Delta,\Gamma,\Theta,\Lambda,\Xi,\Pi,\Sigma,\Phi,\Psi,\Omega} % \DoNotIndex{\digamma,\lceil,\rceil,\lfloor,\rfloor,\left,\right,\inp,\inb,\inbr,\inap,\nop} % \DoNotIndex{\sum,\prod,\int,\log,\ln,\exp,\sin,\cos,\tan,\csc,\sec,\cot,\arcsin,\arccos,\arctan,\det} % \DoNotIndex{\sinh,\cosh,\tanh,\csch,\sech,\coth,\arcsinh,\arccosh,\arctanh} % \DoNotIndex{\mod,\max,\min,\gcd,\lcm,\wp,\arg,\dots,\infty,} % \DoNotIndex{\frac,\binom,\braket,\@@atop} % \DoNotIndex{\cdot,\ldots,\tilde,\times,\dagger,\relax} % \DoNotIndex{\mathbb,\roman,\bf,\mathord,\cal,\DeclareMathOperator,\PackageError,\PackageWarning} % \DoNotIndex{\csname,\endcsname,\ifx,\ifnum} % \DoNotIndex{\COOL@Hypergeometric@pq,\COOL@Hypergeometric@pq@ab@value,\hideOnSF,\COOL@decide@paren} % \DoNotIndex{\COOL@decide@indicies} % \DoNotIndex{\mod,\bmod,\pmod,\pod,\operatorname} % % \title{The \textsf{coolstr} package\thanks{This document % corresponds to \textsf{cool}~\fileversion, % dated~\filedate.}} % \author{nsetzer} % % \maketitle % % \setcounter{IndexColumns}{2} % \StopEventually{\PrintChanges\PrintIndex} % % The \textsf{coolstr} package is a ``sub" package of the \textsf{cool} package that seemed appropriate to publish % independently since it may occur that one wishes to include the ability to check strings without having to accept % all the overhead of the \textsf{cool} package itself. % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %\section{Basics} % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Strings are defined as a sequence of characters (not \TeX{} tokens). The main purpose behind treating strings as % characters rather than tokens is that one can then do some text manipulation on them. % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %\section{Descriptions} % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % \DescribeMacro{\substr} |\substr|\marg{string}\marg{start index}\marg{num char} gives at most $\|$\meta{num char}$\|$ % characters from \meta{string}. % % if \meta{start index} is greater than zero, and \meta{num char} is greater than zero, |\substr| gives at most % \meta{num char} starting with index \meta{start index} and going to the end of the string. % % if \meta{start index} is greater than zero, and \meta{num char} is less than zero, |\substr| gives at most % $-$\meta{num char} characters and going to the beginning of the string % % if \meta{start index} is less than zero, and \meta{num char} is greater than zero, |\substr| gives at most % \meta{num char} characters starting at the $-$\meta{start index} character from the end of the string and going % to the end of the string % % if \meta{start index} is less than zero, and \meta{num char} is less than zero, |\substr| gives at most % $-$\meta{num char} characters starting at the $-$\meta{start index} character from the end of the string and going % to the beginning of the string % % There are two special, non-numeric values that \meta{char num} may take. They are |end| or |beg|, and they will always % go to the end or begining of the string, respectively % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %\section{Test Cases} % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %\subsection{\texttt{$\backslash$substr}} % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % \DescribeMacro{\substr} % % \begin{tabular}{ll} % \hline % |\substr{12345}{1}{2}| & \substr{12345}{1}{2} \\ % |\substr{12345}{3}{5}| & \substr{12345}{3}{5} \\ % |\substr{12345}{3}{end}| & \substr{12345}{3}{end} \\ % |\substr{12345}{3}{beg}| & \substr{12345}{3}{beg} \\ % |\substr{12345}{-2}{1}| & \substr{12345}{-2}{1} \\ % |\substr{12345}{3}{-2}| & \substr{12345}{3}{-2} \\ % |\substr{12345}{-2}{-2}| & \substr{12345}{-2}{-2} \\ % |\substr{12345}{0}{5}| & \substr{12345}{0}{5} (the null string) \\ % |\substr{12345}{2}{0}| & \substr{12345}{2}{0} (the null string) \\ % \hline % \end{tabular} % % % \newboolean{t} % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %\subsection{\texttt{$\backslash$isdecimal}} % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % \begin{tabular}{ll} % (null str) & \isdecimal{}{t} \ifthenelse{ \boolean{t} }{is decimal}{not a decimal} \\ % \textvisiblespace & \isdecimal{ }{t} \ifthenelse{ \boolean{t} }{is decimal}{not a decimal} \\ % \textvisiblespace\textvisiblespace % & \isdecimal{ }{t} \ifthenelse{ \boolean{t} }{is decimal}{not a decimal} \\ % |2.345| & \isdecimal{2.345}{t} \ifthenelse{ \boolean{t} }{is decimal}{not a decimal} \\ % |2.4.5| & \isdecimal{2.4.5}{t} \ifthenelse{ \boolean{t} }{is decimal}{not a decimal} \\ % |+-2.45| & \isdecimal{+-2.45}{t} \ifthenelse{ \boolean{t} }{is decimal}{not a decimal} \\ % |+2.345| & \isdecimal{+2.345}{t} \ifthenelse{ \boolean{t} }{is decimal}{not a decimal} \\ % |-2.345| & \isdecimal{-2.345}{t} \ifthenelse{ \boolean{t} }{is decimal}{not a decimal} \\ % |2.345-| & \isdecimal{2.345-}{t} \ifthenelse{ \boolean{t} }{is decimal}{not a decimal} \\ % |2.4+4.| & \isdecimal{2.4+4.5}{t} \ifthenelse{ \boolean{t} }{is decimal}{not a decimal} \\ % |+4.| & \isdecimal{+4.}{t} \ifthenelse{ \boolean{t} }{is decimal}{not a decimal} \\ % |4.| & \isdecimal{4.}{t} \ifthenelse{ \boolean{t} }{is decimal}{not a decimal} \\ % |+.7| & \isdecimal{+.7}{t} \ifthenelse{ \boolean{t} }{is decimal}{not a decimal} \\ % |.3| & \isdecimal{.3}{t} \ifthenelse{ \boolean{t} }{is decimal}{not a decimal} \\ % |4| & \isdecimal{4}{t} \ifthenelse{ \boolean{t} }{is decimal}{not a decimal} \\ % & |\newcommand{\numberstore}{4.5}| \\ % |\numberstore| & \newcommand{\numberstore}{4.5} \isdecimal{\numberstore}{t} \ifthenelse{ \boolean{t} }{is decimal}{not a decimal} % \end{tabular} % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %\subsection{\texttt{$\backslash$isnumeric}} % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % \begin{tabular}{ll} % (null str) & \isnumeric{}{t} \ifthenelse{ \boolean{t} }{is numeric}{not numeric} \\ % \textvisiblespace & \isnumeric{ }{t} \ifthenelse{ \boolean{t} }{is numeric}{not numeric} \\ % \textvisiblespace\textvisiblespace % & \isnumeric{ }{t} \ifthenelse{ \boolean{t} }{is numeric}{not numeric} \\ % |4.5| & \isnumeric{4.5}{t} \ifthenelse{ \boolean{t} }{is numeric}{not numeric} \\ % |4.5e5| & \isnumeric{4.5e5}{t} \ifthenelse{ \boolean{t} }{is numeric}{not numeric} \\ % |+4.5e5| & \isnumeric{+4.5e5}{t} \ifthenelse{ \boolean{t} }{is numeric}{not numeric} \\ % |4.5e+5| & \isnumeric{4.5e+5}{t} \ifthenelse{ \boolean{t} }{is numeric}{not numeric} \\ % |+4.5e+5| & \isnumeric{+4.5e+5}{t} \ifthenelse{ \boolean{t} }{is numeric}{not numeric} \\ % |4.5E5| & \isnumeric{4.5E5}{t} \ifthenelse{ \boolean{t} }{is numeric}{not numeric} \\ % |-4.5E5| & \isnumeric{-4.5E5}{t} \ifthenelse{ \boolean{t} }{is numeric}{not numeric} \\ % |4.5E-5| & \isnumeric{4.5E-5}{t} \ifthenelse{ \boolean{t} }{is numeric}{not numeric} \\ % |-4.5E-5| & \isnumeric{-4.5E-5}{t} \ifthenelse{ \boolean{t} }{is numeric}{not numeric} \\ % |4.5.E-5| & \isnumeric{4.5.E-5}{t} \ifthenelse{ \boolean{t} }{is numeric}{not numeric} \\ % |abcdefg| & \isnumeric{abcdefg}{t} \ifthenelse{ \boolean{t} }{is numeric}{not numeric} \\ % |abcE-5| & \isnumeric{abcE-5}{t} \ifthenelse{ \boolean{t} }{is numeric}{not numeric} % \end{tabular} % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %\subsection{\texttt{$\backslash$isint}} % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % \begin{tabular}{ll} % (null str) & \isint{}{t} \ifthenelse{ \boolean{t} }{is integer}{not integer} \\ % \textvisiblespace & \isint{ }{t} \ifthenelse{ \boolean{t} }{is integer}{not integer} \\ % \textvisiblespace\textvisiblespace % & \isint{ }{t} \ifthenelse{ \boolean{t} }{is integer}{not integer} \\ % |4| & \isint{4}{t} \ifthenelse{ \boolean{t} }{is integer}{not integer} \\ % |+4| & \isint{+4}{t} \ifthenelse{ \boolean{t} }{is integer}{not integer} \\ % |4.5| & \isint{4.5}{t} \ifthenelse{ \boolean{t} }{is integer}{not integer} \\ % |4.5e5| & \isint{4.5e5}{t} \ifthenelse{ \boolean{t} }{is integer}{not integer} \\ % |+4.5e5| & \isint{+4.5e5}{t} \ifthenelse{ \boolean{t} }{is integer}{not integer} \\ % |4.5e+5| & \isint{4.5e+5}{t} \ifthenelse{ \boolean{t} }{is integer}{not integer} \\ % |+4.5e+5| & \isint{+4.5e+5}{t} \ifthenelse{ \boolean{t} }{is integer}{not integer} \\ % |4.5E5| & \isint{4.5E5}{t} \ifthenelse{ \boolean{t} }{is integer}{not integer} \\ % |-4.5E5| & \isint{-4.5E5}{t} \ifthenelse{ \boolean{t} }{is integer}{not integer} \\ % |4.5E-5| & \isint{4.5E-5}{t} \ifthenelse{ \boolean{t} }{is integer}{not integer} \\ % |-4.5E-5| & \isint{-4.5E-5}{t} \ifthenelse{ \boolean{t} }{is integer}{not integer} \\ % |4.5.E-5| & \isint{4.5.E-5}{t} \ifthenelse{ \boolean{t} }{is integer}{not integer} \\ % |abcdefg| & \isint{abcdefg}{t} \ifthenelse{ \boolean{t} }{is integer}{not integer} \\ % |abcE-5| & \isint{abcE-5}{t} \ifthenelse{ \boolean{t} }{is integer}{not integer} \\ % & |\renewcommand{\numberstore}{4}| \\ % |\numberstore| & \newcommand{\numberstore}{4} \isint{\numberstore}{t} \ifthenelse{ \boolean{t} }{is integer}{not integer} % \end{tabular} % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %\section{Acknowledgments} % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Thanks to J.~J.~Weimer for the comments and aid in coding. % % \noindent Thanks goes to Abraham Weishaus for pointing out a bug in |\strlenstore| % % \noindent Thanks to Daniel Kucerovsky for pointing the `blank-space' bug of |\isnumeric| (and consequently |\isdecimal|). % % % \begin{landscape} % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %\section{Implementation} % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % This is just an internal counter for dealing with the strings; most often used for the length % % \begin{macrocode} \newcounter{COOL@strlen}% % \end{macrocode} % % \begin{macro}{\setstrEnd} % % |\setstrEnd{|\meta{string}|}| allows the user to set the end of a string `character' % in the rare event that the default value actually appears in the string. % The default value is % % \begin{macrocode} \newcommand{\COOL@strEnd}{\%\%\%} \newcommand{\COOL@intEnd}{\%@\%@\%@} \let\COOL@strStop=\relax % \end{macrocode} % % and may be changed by the following command (which utilizes the |\renewcommand|): % % \begin{macrocode} \newcommand{\setstrEnd}[1]{\renewcommand{\COOL@strEnd}{#1}} % \end{macrocode} % % \end{macro} % % % This area defines the core technology behind the \textsf{coolstr} package: the string ``gobbler". % % \begin{macrocode} \newcounter{COOL@strpointer} % \end{macrocode} % % Now we come to ``the gobbler"---a recursive function that eats up a string. % It must be written in \TeX{} primatives. % % The idea behind this is that ``the gobbler" eats up everything before the desired character and everything % after the desired character. % % \begin{macrocode} \def\COOL@strgobble[#1]#2#3{% \ifthenelse{\equal{#3}{\COOL@strEnd}}% {% \ifthenelse{\value{COOL@strpointer}=#1}% {% #2% }% % Else {% }% }% % Else {% \ifthenelse{\value{COOL@strpointer}=#1}% {% #2% }% % Else {% }% \stepcounter{COOL@strpointer}% \COOL@strgobble[#1]#3% }% } % \end{macrocode} % % \begin{macro}{\strchar} % |\strchar|\marg{index} gives the \meta{index} character of the string. Strings start indexing at $1$. % % \begin{macrocode} \newcommand{\strchar}[2]{% \setcounter{COOL@strpointer}{1}% \COOL@strgobble[#2]#1\COOL@strEnd% } % \end{macrocode} % % \end{macro} % % % \begin{macro}{\strlen} % \changes{v2.0}{2006/12/29}{added to package} % \changes{v2.1}{2007/01/08}{added ifthenelse to return $0$ for empty string} % |\strlen|\marg{string} gives the length of the string. It is better to use |\strlenstore| to record the length % % |\strlen{abc}| \strlen{abc} % % \begin{macrocode} \newcommand{\strlen}[1]{% \ifthenelse{\equal{#1}{}}% {% 0% }% % Else {% \strchar{#1}{0}% \arabic{COOL@strpointer}% }% } % \end{macrocode} % % \end{macro} % % % \begin{macro}{\strlenstore} % \changes{v2.0}{2006/12/29}{added to package} % \changes{v2.1}{2007/01/08}{corrected error in setting counter} % \changes{v2.1}{2007/01/08}{added ifthenelse to return $0$ for empty string} % |\strlenstore|\marg{string}\marg{counter} stores the length of \meta{string} in \meta{counter} % % \begin{macrocode} \newcommand{\strlenstore}[2]{% \ifthenelse{\equal{#1}{}}% {% \setcounter{#2}{0}% }% % Else {% \strchar{#1}{0}% \setcounter{#2}{\value{COOL@strpointer}}% }% } % \end{macrocode} % % \end{macro} % % % % % \begin{macro}{\substr} % \changes{v2.1}{2007/01/08}{added to package} % |\substr|\marg{string}\marg{index}\marg{numchar} % % a special value of |end| for \meta{numchar} gives from \meta{index} to the end of the string; |beg| gives from \meta{index} to the beginning of the string % % \begin{macrocode} \newcounter{COOL@str@index} \newcounter{COOL@str@start} \newcounter{COOL@str@end} \newcommand{\substr}[3]{% \strlenstore{#1}{COOL@strlen}% \ifthenelse{#2 < 0 \AND \NOT #2 < -\value{COOL@strlen}}% {% % \end{macrocode} % The starting index is less than zero, so start that many characters back from the end. This means mapping the index to \meta{index}${} + {}$\meta{string length}${} + 1$ % \begin{macrocode} \setcounter{COOL@str@index}{\value{COOL@strlen}}% \addtocounter{COOL@str@index}{#2}% \addtocounter{COOL@str@index}{1}% }% % ElseIf {\ifthenelse{#2 > 0 \AND \NOT #2 > \value{COOL@strlen}}% {% % \end{macrocode} % The starting index is greater than zero, and within the appropriate range; record it % \begin{macrocode} \setcounter{COOL@str@index}{#2}% }% % Else {% % \end{macroccode} % The \meta{index} value is invalid. Set it to zero for returning the null string % \begin{macrocode} \setcounter{COOL@str@index}{0}% }}% % \end{macrocode} % Now deal with the \meta{numchar} (which can also be negative) % \begin{macrocode} \ifthenelse{\equal{#3}{beg}}% {% \setcounter{COOL@str@start}{1}% \setcounter{COOL@str@end}{\value{COOL@str@index}}% }% % ElseIf {\ifthenelse{\equal{#3}{end}}% {% \setcounter{COOL@str@start}{\value{COOL@str@index}}% \setcounter{COOL@str@end}{\value{COOL@strlen}}% }% % ElseIf {\ifthenelse{#3 < 0}% {% % \end{macrocode} % This means to take that many characters to the \emph{left} of the starting index. % \begin{macrocode} \setcounter{COOL@str@start}{\value{COOL@str@index}}% \addtocounter{COOL@str@start}{#3}% \addtocounter{COOL@str@start}{1}% \ifthenelse{\NOT \value{COOL@str@start} > 0}{\setcounter{COOL@str@start}{1}}{}% \setcounter{COOL@str@end}{\value{COOL@str@index}}% }% % ElseIf {\ifthenelse{#3 > 0}% {% \setcounter{COOL@str@start}{\value{COOL@str@index}}% \setcounter{COOL@str@end}{\value{COOL@str@index}}% \addtocounter{COOL@str@end}{#3}% \addtocounter{COOL@str@end}{-1}% \ifthenelse{\value{COOL@str@end} > \value{COOL@strlen}}{\setcounter{COOL@str@end}{\value{COOL@strlen}}}{}% }% % Else {% % \end{macrocode} % nonsense submitted, so return the null string % \begin{macrocode} \setcounter{COOL@str@index}{0}% }}}}% % \end{macrocode} % Now send back the appropriate thing % \begin{macrocode} \ifthenelse{ \value{COOL@str@index} = 0 }% {% }% % Else {% \setcounter{COOL@strpointer}{1}% \COOL@substrgobbler#1\COOL@strStop\COOL@strEnd% }% } % \end{macrocode} % Now define the ``gobbler" % \begin{macrocode} \def\COOL@substrgobbler#1#2\COOL@strEnd{% \ifthenelse{\equal{#2}{\COOL@strStop}}% {% \ifthenelse{ \value{COOL@strpointer} < \value{COOL@str@start} \OR \value{COOL@strpointer} > \value{COOL@str@end} }% {}% % Else {% #1% }% }% % Else {% \ifthenelse{ \value{COOL@strpointer} < \value{COOL@str@start} \OR \value{COOL@strpointer} > \value{COOL@str@end} }% {}% % Else {% #1% }% \stepcounter{COOL@strpointer}% \COOL@substrgobbler#2\COOL@strEnd% }% } % \end{macrocode} % % \end{macro} % % % Define a new boolean for comparing characters % % \begin{macrocode} \newboolean{COOL@charmatch} % \end{macrocode} % % \begin{macro}{\COOL@strcomparegobble} % This ``gobbler" does character comparison % \changes{v2.0}{2006/12/29}{added to package for single character comparisons} % % \begin{macrocode} \def\COOL@strcomparegobble[#1]<#2>#3#4{% \ifthenelse{\equal{#4}{\COOL@strEnd}}% {% \ifthenelse{\value{COOL@strpointer}=#1 \AND \equal{#2}{#3} }% {% \setboolean{COOL@charmatch}{true}% }% % Else {% }% }% % Else {% \ifthenelse{\value{COOL@strpointer}=#1 \AND \equal{#2}{#3} }% {% \setboolean{COOL@charmatch}{true}% }% % Else {% }% \stepcounter{COOL@strpointer}% \COOL@strcomparegobble[#1]<#2>#4% }% } % \end{macrocode} % \end{macro} % % \begin{macro}{\ifstrchareq} % |\ifstrchareq|\marg{string}\marg{char index}\marg{comparison char}\marg{do if true}\marg{do if false} % \changes{v2.0}{2006/12/29}{added to package to do character comparing} % % \begin{macrocode} \newcommand{\ifstrchareq}[5]{% \setboolean{COOL@charmatch}{false}% \setcounter{COOL@strpointer}{1}% \COOL@strcomparegobble[#2]<#3>#1\COOL@strEnd\relax% \ifthenelse{ \boolean{COOL@charmatch} }% {% #4% }% % Else {% #5% }% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\ifstrleneq} % |\ifstrleneq|\marg{string}\marg{number}\marg{do if true}\marg{do if false} % % \noindent |\ifstrleneq{abc}{3}{length is $3$}{length is not $3$}| \ifstrleneq{abc}{3}{length is $3$}{length is not $3$} % % \noindent |\ifstrleneq{abcde}{3}{length is $3$}{length is not $3$}| \ifstrleneq{abcde}{3}{length is $3$}{length is not $3$} % % \changes{v2.0}{2006/12/29}{added to package to do length comparison} % \changes{v2.1}{2007/01/08}{altered function to use \texttt{strlenstore}} % % \begin{macrocode} \newcommand{\ifstrleneq}[4]{% \strlenstore{#1}{COOL@strlen}% \ifthenelse{ \value{COOL@strlen} = #2 }% {% #3% }% % Else {% #4% }% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\COOL@decimalgobbler} % % This ``gobbler" is used to determine if the submitted string is a rational number (satisfies $d_n d_{n-1} \cdots d_1 d_0 . d_{-1} d_{-2} \cdots d_{-m}$). The idea behind the macro is that it assumes the string is rational until it encounters a non-numeric object % \changes{v2.0}{2006/12/29}{added this ``gobbler'' to complete \texttt{isnumeric}} % % \begin{macrocode} \newboolean{COOL@decimalfound} \newboolean{COOL@decimal} % \end{macrocode} % % |COOL@decimalfound| is a boolean indicating if the first decimal point is found % % |COOL@decimal| is the flag that tells if the string contains numeric data % % \begin{macrocode} \def\COOL@decimalgobbler#1#2\COOL@strEnd{% % \end{macrocode} % \changes{v2.2}{2009/09/09}{fixed blank space bug (blank space causes code to `crash')} % \begin{macrocode} \ifthenelse{\equal{#1}{\COOL@strStop}}% {% % \end{macrocode} % user submitted a null string, which can not be numeric % \begin{macrocode} \setboolean{COOL@decimal}{false}% }% {\ifthenelse{\equal{#2}{\COOL@strStop}}% % \end{macrocode} % this indicates we are at the end of the string. We only need to perform the check to see if the digit is a number or the first decimal point % \begin{macrocode} {% \ifthenelse{`#1 < `0 \OR `#1 > `9}% {% \ifthenelse{ `#1 = `. \AND \NOT \value{COOL@strpointer} = 1 \AND \NOT \boolean{COOL@decimalfound} }% {% }% % Else {% \setboolean{COOL@decimal}{false}% }% }% % Else {% }% }% % Else {% \ifthenelse{ `#1 < `0 \OR `#1 > `9 }% {% % \end{macrocode} % not at the end of a string, and have encountered a non-digit. If it is a number, then this non digit must be the first decimal point or it may be the first character and a $+$ or $-$ sign % \begin{macrocode} \ifthenelse{ `#1 = `. \AND \NOT \boolean{COOL@decimalfound} }% {% \setboolean{COOL@decimalfound}{true}% }% {\ifthenelse{ \(`#1 = `+ \OR `#1 = `-\) \AND \value{COOL@strpointer} = 1 }% {% }% % Else {% \setboolean{COOL@decimal}{false}% }}% }% % Else {}% \stepcounter{COOL@strpointer}% \COOL@decimalgobbler#2\COOL@strEnd% }}% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\isdecimal} % |isdecimal|\marg{string}\marg{boolean} % \changes{v2.0}{2006/12/29}{added} % % \begin{macrocode} \newcommand{\isdecimal}[2]{% \setcounter{COOL@strpointer}{1}% \setboolean{COOL@decimalfound}{false}% \setboolean{COOL@decimal}{true}% \expandafter\COOL@decimalgobbler#1\COOL@strStop\COOL@strEnd% \ifthenelse{ \boolean{COOL@decimal} }% {% \setboolean{#2}{true}% }% % Else {% \setboolean{#2}{false}% }% }% % \end{macrocode} % \end{macro} % % \begin{macro}{\isnumeric} % |\isnumeric|\marg{string}\marg{boolean} stores |true| in \meta{boolean} if \meta{string} is numeric % \changes{v2.0}{2006/12/29}{added extra mandatory argument for storing return boolean} % % \begin{macrocode} \newboolean{COOL@numeric}% \def\COOL@eparser#1e#2\COOL@strEnd{% \xdef\COOL@num@magnitude{#1}% \xdef\COOL@num@exponent{#2}% } \def\COOL@ecorrector#1e\COOL@strStop{% \xdef\COOL@num@exponent{#1}% } \def\COOL@Eparser#1E#2\COOL@strEnd{% \xdef\COOL@num@magnitude{#1}% \xdef\COOL@num@exponent{#2}% } \def\COOL@Ecorrector#1E\COOL@strStop{% \xdef\COOL@num@exponent{#1}% } \newcommand{\isnumeric}[2]{% \COOL@eparser#1e\COOL@strStop\COOL@strEnd% \ifthenelse{ \equal{\COOL@num@exponent}{\COOL@strStop} }% {% \COOL@Eparser#1E\COOL@strStop\COOL@strEnd% \ifthenelse{ \equal{\COOL@num@exponent}{\COOL@strStop} }% {% \gdef\COOL@num@exponent{0}% }% % Else {% \expandafter\COOL@Ecorrector\COOL@num@exponent% }% } % Else {% \expandafter\COOL@ecorrector\COOL@num@exponent% }% \isdecimal{\COOL@num@magnitude}{COOL@numeric}% \ifthenelse{ \boolean{COOL@numeric} }% {% \isdecimal{\COOL@num@exponent}{COOL@numeric}% \ifthenelse{ \boolean{COOL@numeric} }% {% \setboolean{#2}{true}% }% % Else {% \setboolean{#2}{false}% }% }% % Else {% \setboolean{#2}{false}% }% } % \end{macrocode} % % \end{macro} % % In addition to identifying numeric data, it is useful to know if integers are present, thus another ``gobbler" is % needed % % \begin{macrocode} \newboolean{COOL@isint} \def\COOL@intgobbler#1#2\COOL@strEnd{% \ifcat#11% \ifthenelse{\equal{#2}{\COOL@strStop}}% {% \ifthenelse{`#1 < `0 \OR `#1 > `9}% {% \setboolean{COOL@isint}{false}% }% % Else {% }% }% % Else {% \ifthenelse{ `#1 < `0 \OR `#1 > `9 }% {% \ifthenelse{ `#1 = `+ \OR `#1 = `- \AND \value{COOL@strpointer} = 1 }% {}% % Else {% \setboolean{COOL@isint}{false}% }% }% % Else {% }% \stepcounter{COOL@strpointer}% \COOL@intgobbler#2\COOL@strEnd% }% \else% \setboolean{COOL@isint}{false}% \fi% } % \end{macrocode} % % \begin{macro}{\isint} % \changes{v2.0}{2006/12/29}{added extra mandatory argument for storing return boolean} % \changes{v2.0a}{2006/12/30}{modified internals slightly to work with \textsf{cool} package} % \changes{v2.1b}{2007/10/10}{added expandafter before COOL@intgobbler to expand macros before evaluating} % |\isint|\marg{string}\marg{boolean} sets the \meta{boolean} to |true| if \meta{string} is an integer or |false| otherwise % % \begin{macrocode} \newcommand{\isint}[2]{% \setcounter{COOL@strpointer}{1}% \setboolean{COOL@isint}{true}% \expandafter\COOL@intgobbler#1\COOL@strStop\COOL@strEnd% \ifthenelse{ \boolean{COOL@isint} }% {% \setboolean{#2}{true}% }% % Else {% \setboolean{#2}{false}% }% } % \end{macrocode} % % \end{macro} % % \end{landscape} % % % % \Finale \endinput