diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3str.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3str.dtx | 448 |
1 files changed, 429 insertions, 19 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3str.dtx b/Master/texmf-dist/source/latex/l3kernel/l3str.dtx index 6b29004467d..5823e3c5c8e 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3str.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3str.dtx @@ -41,7 +41,7 @@ % }^^A % } % -% \date{Released 2017/09/18} +% \date{Released 2017/11/14} % % \maketitle % @@ -76,10 +76,6 @@ % This data type simplifies comparison of variables since there are no concerns % about expansion of their contents. % -% Note that as string variables are a special case of token list variables -% the coverage of \cs[no-index]{str_\ldots{}:N} functions is somewhat smaller than -% \cs[no-index]{tl_\ldots{}:N}. -% % The functions \cs{cs_to_str:N}, \cs{tl_to_str:n}, \cs{tl_to_str:N} and % \cs{token_to_str:N} (and variants) generate strings from the appropriate % input: these are documented in \pkg{l3basics}, \pkg{l3tl} and \pkg{l3token}, @@ -148,6 +144,19 @@ % \meta{str~var_2}. % \end{function} % +% \begin{function}[added = 2017-10-08] +% { +% \str_concat:NNN, \str_concat:ccc, +% \str_gconcat:NNN, \str_gconcat:ccc +% } +% \begin{syntax} +% \cs{str_concat:NNN} \meta{str~var_1} \meta{str~var_2} \meta{str~var_3} +% \end{syntax} +% Concatenates the content of \meta{str~var_2} and \meta{str~var_3} +% together and saves the result in \meta{str~var_1}. The \meta{str~var_2} +% is placed at the left side of the new string variable. +% \end{function} +% % \section{Adding data to string variables} % % \begin{function}[added = 2015-09-18] @@ -192,6 +201,72 @@ % var} are not automatically converted to a string. % \end{function} % +% \subsection{Modifying string variables} +% +% \begin{function}[added = 2017-10-08] +% { +% \str_replace_once:Nnn, \str_replace_once:cnn, +% \str_greplace_once:Nnn, \str_greplace_once:cnn +% } +% \begin{syntax} +% \cs{str_replace_once:Nnn} \meta{str~var} \Arg{old} \Arg{new} +% \end{syntax} +% Converts the \meta{old} and \meta{new} token lists to strings, then +% replaces the first (leftmost) occurrence of \meta{old string} in the +% \meta{str~var} with \meta{new string}. +% \end{function} +% +% \begin{function}[added = 2017-10-08] +% { +% \str_replace_all:Nnn, \str_replace_all:cnn, +% \str_greplace_all:Nnn, \str_greplace_all:cnn +% } +% \begin{syntax} +% \cs{str_replace_all:Nnn} \meta{str~var} \Arg{old} \Arg{new} +% \end{syntax} +% Converts the \meta{old} and \meta{new} token lists to strings, then +% replaces all occurrences of \meta{old string} in the +% \meta{str~var} with \meta{new string}. +% As this function +% operates from left to right, the pattern \meta{old string} +% may remain after the replacement (see \cs{str_remove_all:Nn} +% for an example). +% \end{function} +% +% \begin{function}[added = 2017-10-08] +% { +% \str_remove_once:Nn, \str_remove_once:cn, +% \str_gremove_once:Nn, \str_gremove_once:cn +% } +% \begin{syntax} +% \cs{str_remove_once:Nn} \meta{str~var} \Arg{token list} +% \end{syntax} +% Converts the \meta{token list} to a \meta{string} then +% removes the first (leftmost) occurrence of \meta{string} from the +% \meta{str~var}. +% \end{function} +% +% \begin{function}[added = 2017-10-08] +% { +% \str_remove_all:Nn, \str_remove_all:cn, +% \str_gremove_all:Nn, \str_gremove_all:cn +% } +% \begin{syntax} +% \cs{str_remove_all:Nn} \meta{str~var} \Arg{token list} +% \end{syntax} +% Converts the \meta{token list} to a \meta{string} then +% removes all occurrences of \meta{string} from the +% \meta{str~var}. +% As this function +% operates from left to right, the pattern \meta{string} +% may remain after the removal, for instance, +% \begin{quote} +% \cs{str_set:Nn} \cs{l_tmpa_str} |{abbccd}| +% \cs{str_remove_all:Nn} \cs{l_tmpa_str} |{bc}| +% \end{quote} +% results in \cs{l_tmpa_str} containing \texttt{abcd}. +% \end{function} +% % \subsection{String conditionals} % % \begin{function}[EXP, pTF, added = 2015-09-18] @@ -221,7 +296,8 @@ % \cs{str_if_eq:NNTF} \meta{str~var_1} \meta{str~var_2} \Arg{true code} \Arg{false code} % \end{syntax} % Compares the content of two \meta{str variables} and -% is logically \texttt{true} if the two contain the same characters. +% is logically \texttt{true} if the two contain the same characters +% in the same order. % \end{function} % % \begin{function}[EXP,pTF] @@ -234,7 +310,8 @@ % \cs{str_if_eq:nnTF} \Arg{tl_1} \Arg{tl_2} \Arg{true code} \Arg{false code} % \end{syntax} % Compares the two \meta{token lists} on a character by character -% basis, and is \texttt{true} if the two lists contain the same +% basis (namely after converting them to strings), +% and is \texttt{true} if the two \meta{strings} contain the same % characters in the same order. Thus for example % \begin{verbatim} % \str_if_eq_p:no { abc } { \tl_to_str:n { abc } } @@ -247,8 +324,9 @@ % \cs{str_if_eq_x_p:nn} \Arg{tl_1} \Arg{tl_2} % \cs{str_if_eq_x:nnTF} \Arg{tl_1} \Arg{tl_2} \Arg{true code} \Arg{false code} % \end{syntax} -% Compares the full expansion of two \meta{token lists} on a character by -% character basis, and is \texttt{true} if the two lists contain the same +% Fully expands the two \meta{token lists} and converts them to \meta{strings}, then +% compares these on a character by character basis: +% it is \texttt{true} if the two \meta{strings} contain the same % characters in the same order. Thus for example % \begin{verbatim} % \str_if_eq_x_p:nn { abc } { \tl_to_str:n { abc } } @@ -256,6 +334,23 @@ % is logically \texttt{true}. % \end{function} % +% \begin{function}[TF, added = 2017-10-08]{\str_if_in:Nn, \str_if_in:cn} +% \begin{syntax} +% \cs{str_if_in:NnTF} \meta{str~var} \Arg{token list} \Arg{true code} \Arg{false code} +% \end{syntax} +% Converts the \meta{token list} to a \meta{string} and +% tests if that \meta{string} is found in the content of the +% \meta{str~var}. +% \end{function} +% +% \begin{function}[TF, added = 2017-10-08]{\str_if_in:nn} +% \begin{syntax} +% \cs{str_if_in:nnTF} \meta{tl_1} \Arg{tl_2} \Arg{true code} \Arg{false code} +% \end{syntax} +% Converts both \meta{token lists} to \meta{strings} and +% tests whether \meta{string_2} is found inside \meta{string_1}. +% \end{function} +% % \begin{function}[added = 2013-07-24, updated = 2015-02-28, EXP, noTF] % {\str_case:nn, \str_case:on, \str_case:nV, \str_case:nv} % \begin{syntax} @@ -269,8 +364,9 @@ % ~~\Arg{true code} % ~~\Arg{false code} % \end{syntax} -% This function compares the \meta{test string} in turn with each -% of the \meta{string cases}. If the two are equal (as described for +% Compares the \meta{test string} in turn with each +% of the \meta{string cases} (all token lists are converted to strings). +% If the two are equal (as described for % \cs{str_if_eq:nnTF}) then the associated \meta{code} is left in the % input stream and other cases are discarded. If any of the % cases are matched, the \meta{true code} is also inserted into the @@ -292,8 +388,9 @@ % ~~\Arg{true code} % ~~\Arg{false code} % \end{syntax} -% This function compares the full expansion of the \meta{test string} -% in turn with the full expansion of the \meta{string cases}. If the two +% Compares the full expansion of the \meta{test string} +% in turn with the full expansion of the \meta{string cases} +% (all token lists are converted to strings). If the two % full expansions are equal (as described for \cs{str_if_eq:nnTF}) then the % associated \meta{code} is left in the input stream % and other cases are discarded. If any of the @@ -307,6 +404,126 @@ % not be used within this string. % \end{function} % +% \section{Mapping to strings} +% +% \begin{function}[added = 2017-10-08, rEXP] +% {\str_map_function:NN, \str_map_function:cN} +% \begin{syntax} +% \cs{str_map_function:NN} \meta{str~var} \meta{function} +% \end{syntax} +% Applies \meta{function} to every \meta{character} in the \meta{str~var}. +% See also \cs{str_map_function:nN}. +% \end{function} +% +% \begin{function}[added = 2017-10-08, rEXP] +% {\str_map_function:nN} +% \begin{syntax} +% \cs{str_map_function:nN} \Arg{token list} \meta{function} +% \end{syntax} +% Converts the \meta{token list} to a \meta{string} then +% applies \meta{function} to every \meta{character} in the \meta{string}. +% See also \cs{str_map_function:NN}. +% \end{function} +% +% \begin{function}[added = 2017-10-08] +% {\str_map_inline:Nn, \str_map_inline:cn} +% \begin{syntax} +% \cs{str_map_inline:Nn} \meta{str~var} \Arg{inline function} +% \end{syntax} +% Applies the \meta{inline function} to every \meta{character} in the +% \meta{str~var}. The \meta{inline function} should consist of code which +% receives the \meta{character} as |#1|. One in line mapping can be nested +% inside another. See also \cs{str_map_function:NN}. +% \end{function} +% +% \begin{function}[added = 2017-10-08] +% {\str_map_inline:nn} +% \begin{syntax} +% \cs{str_map_inline:nn} \Arg{token list} \Arg{inline function} +% \end{syntax} +% Converts the \meta{token list} to a \meta{string} then +% applies the \meta{inline function} to every \meta{character} in the +% \meta{string}. The \meta{inline function} should consist of code which +% receives the \meta{character} as |#1|. One in line mapping can be nested +% inside another. See also \cs{str_map_function:NN}. +% \end{function} +% +% \begin{function}[added = 2017-10-08] +% {\str_map_variable:NNn, \str_map_variable:cNn} +% \begin{syntax} +% \cs{str_map_variable:NNn} \meta{str~var} \meta{variable} \Arg{function} +% \end{syntax} +% Applies the \meta{function} to every \meta{character} in +% the \meta{str~var}. The \meta{function} should consist of code +% which receives the \meta{character} stored in the \meta{variable}. +% One variable mapping can be nested inside another. See also +% \cs{str_map_inline:Nn}. +% \end{function} +% +% \begin{function}[added = 2017-10-08] +% {\str_map_variable:nNn} +% \begin{syntax} +% \cs{str_map_variable:nNn} \Arg{token list} \meta{variable} \Arg{function} +% \end{syntax} +% Converts the \meta{token list} to a \meta{string} then +% applies the \meta{function} to every \meta{character} in the \meta{string}. +% The \meta{function} should consist of code +% which receives the \meta{character} stored in the \meta{variable}. +% One variable mapping can be nested inside another. See also +% \cs{str_map_inline:Nn}. +% \end{function} +% +% \begin{function}[added = 2017-10-08, rEXP]{\str_map_break:} +% \begin{syntax} +% \cs{str_map_break:} +% \end{syntax} +% Used to terminate a \cs[no-index]{str_map_\ldots} function before all +% characters in the \meta{string} have been processed. This +% normally takes place within a conditional statement, for example +% \begin{verbatim} +% \str_map_inline:Nn \l_my_str +% { +% \str_if_eq:nnT { #1 } { bingo } { \str_map_break: } +% % Do something useful +% } +% \end{verbatim} +% See also \cs{str_map_break:n}. +% Use outside of a \cs[no-index]{str_map_\ldots} scenario leads to low +% level \TeX{} errors. +% \begin{texnote} +% When the mapping is broken, additional tokens may be inserted by the +% internal macro \cs{__prg_break_point:Nn} before continuing with the +% code that follows the loop. +% This depends on the design of the mapping function. +% \end{texnote} +% \end{function} +% +% \begin{function}[added = 2017-10-08, rEXP]{\str_map_break:n} +% \begin{syntax} +% \cs{str_map_break:n} \Arg{tokens} +% \end{syntax} +% Used to terminate a \cs[no-index]{str_map_\ldots} function before all +% characters in the \meta{string} have been processed, inserting +% the \meta{tokens} after the mapping has ended. This +% normally takes place within a conditional statement, for example +% \begin{verbatim} +% \str_map_inline:Nn \l_my_str +% { +% \str_if_eq:nnT { #1 } { bingo } +% { \str_map_break:n { <tokens> } } +% % Do something useful +% } +% \end{verbatim} +% Use outside of a \cs[no-index]{str_map_\ldots} scenario leads to low +% level \TeX{} errors. +% \begin{texnote} +% When the mapping is broken, additional tokens may be inserted by the +% internal macro \cs{__prg_break_point:Nn} before the \meta{tokens} are +% inserted into the input stream. +% This depends on the design of the mapping function. +% \end{texnote} +% \end{function} +% % \section{Working with the content of strings} % % \begin{function}[EXP, added = 2015-09-18]{\str_use:N, \str_use:c} @@ -465,7 +682,7 @@ % These functions should \emph{not} be used for % \begin{itemize} % \item Caseless comparisons: use \cs{str_fold_case:n} for this -% situation (case folding is district from lower casing). +% situation (case folding is distinct from lower casing). % \item Case changing text for typesetting: see the % \cs[index=tl_lower_case:n]{tl_lower_case:n(n)}, % \cs[index=tl_upper_case:n]{tl_upper_case:n(n)} and @@ -672,6 +889,8 @@ % \str_set_eq:NN, \str_set_eq:cN, \str_set_eq:Nc, \str_set_eq:cc, % \str_gset_eq:NN, \str_gset_eq:cN, \str_gset_eq:Nc, \str_gset_eq:cc % } +% \begin{macro} +% {\str_concat:NNN, \str_concat:ccc, \str_gconcat:NNN, \str_gconcat:ccc} % A string is simply a token list. The full mapping system isn't set up % yet so do things by hand. % \begin{macrocode} @@ -698,9 +917,14 @@ \cs_new_eq:NN \str_gset_eq:NN \tl_gset_eq:NN \cs_generate_variant:Nn \str_set_eq:NN { c , Nc , cc } \cs_generate_variant:Nn \str_gset_eq:NN { c , Nc , cc } +\cs_new_eq:NN \str_concat:NNN \tl_concat:NNN +\cs_new_eq:NN \str_gconcat:NNN \tl_gconcat:NNN +\cs_generate_variant:Nn \str_concat:NNN { ccc } +\cs_generate_variant:Nn \str_gconcat:NNN { ccc } % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} % % \begin{macro} % { @@ -745,6 +969,103 @@ % \end{macrocode} % \end{macro} % +% \subsection{Modifying string variables} +% +% \begin{macro} +% { +% \str_replace_all:Nnn, \str_replace_all:cnn, +% \str_greplace_all:Nnn, \str_greplace_all:cnn, +% \str_replace_once:Nnn, \str_replace_once:cnn, +% \str_greplace_once:Nnn, \str_greplace_once:cnn +% } +% \begin{macro}[aux]{\@@_replace:NNNnn} +% \begin{macro}[aux]{\@@_replace_aux:NNNnnn} +% \begin{macro}[aux]{\@@_replace_next:w} +% Start by applying \cs{tl_to_str:n} to convert the old and new token +% lists to strings, and also apply \cs{tl_to_str:N} to avoid any +% issues if we are fed a token list variable. Then the code is a much +% simplified version of the token list code because neither the +% delimiter nor the replacement can contain macro parameters or +% braces. The delimiter \cs{q_mark} cannot appear in the string to +% edit so it is used in all cases. Some |x|-expansion is unnecessary. +% There is no need to avoid losing braces nor to protect against +% expansion. The ending code is much simplified and does not need to +% hide in braces. +% \begin{macrocode} +\cs_new_protected:Npn \str_replace_once:Nnn + { \@@_replace:NNNnn \prg_do_nothing: \tl_set:Nx } +\cs_new_protected:Npn \str_greplace_once:Nnn + { \@@_replace:NNNnn \prg_do_nothing: \tl_gset:Nx } +\cs_new_protected:Npn \str_replace_all:Nnn + { \@@_replace:NNNnn \@@_replace_next:w \tl_set:Nx } +\cs_new_protected:Npn \str_greplace_all:Nnn + { \@@_replace:NNNnn \@@_replace_next:w \tl_gset:Nx } +\cs_generate_variant:Nn \str_replace_once:Nnn { c } +\cs_generate_variant:Nn \str_greplace_once:Nnn { c } +\cs_generate_variant:Nn \str_replace_all:Nnn { c } +\cs_generate_variant:Nn \str_greplace_all:Nnn { c } +\cs_new_protected:Npn \@@_replace:NNNnn #1#2#3#4#5 + { + \tl_if_empty:nTF {#4} + { + \__msg_kernel_error:nnx { kernel } { empty-search-pattern } {#5} + } + { + \use:x + { + \exp_not:n { \@@_replace_aux:NNNnnn #1 #2 #3 } + { \tl_to_str:N #3 } + { \tl_to_str:n {#4} } { \tl_to_str:n {#5} } + } + } + } +\cs_new_protected:Npn \@@_replace_aux:NNNnnn #1#2#3#4#5#6 + { + \cs_set:Npn \@@_replace_next:w ##1 #5 { ##1 #6 #1 } + #2 #3 + { + \@@_replace_next:w + #4 + \use_none_delimit_by_q_stop:w + #5 + \q_stop + } + } +\cs_new_eq:NN \@@_replace_next:w ? +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\str_remove_once:Nn, \str_remove_once:cn} +% \begin{macro}{\str_gremove_once:Nn, \str_gremove_once:cn} +% Removal is just a special case of replacement. +% \begin{macrocode} +\cs_new_protected:Npn \str_remove_once:Nn #1#2 + { \str_replace_once:Nnn #1 {#2} { } } +\cs_new_protected:Npn \str_gremove_once:Nn #1#2 + { \str_greplace_once:Nnn #1 {#2} { } } +\cs_generate_variant:Nn \str_remove_once:Nn { c } +\cs_generate_variant:Nn \str_gremove_once:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\str_remove_all:Nn, \str_remove_all:cn} +% \begin{macro}{\str_gremove_all:Nn, \str_gremove_all:cn} +% Removal is just a special case of replacement. +% \begin{macrocode} +\cs_new_protected:Npn \str_remove_all:Nn #1#2 + { \str_replace_all:Nnn #1 {#2} { } } +\cs_new_protected:Npn \str_gremove_all:Nn #1#2 + { \str_greplace_all:Nnn #1 {#2} { } } +\cs_generate_variant:Nn \str_remove_all:Nn { c } +\cs_generate_variant:Nn \str_gremove_all:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% % \subsection{String comparisons} % % \begin{macro}[pTF, EXP] @@ -871,6 +1192,30 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}[TF]{\str_if_in:Nn, \str_if_in:cn \str_if_in:nn} +% Everything here needs to be detokenized but beyond that it is a +% simple token list test. It would be faster to fine-tune the |T|, +% |F|, |TF| variants by calling the appropriate variant of +% \cs{tl_if_in:nnTF} directly but that takes more code. +% \begin{macrocode} +\prg_new_protected_conditional:Npnn \str_if_in:Nn #1#2 { T , F , TF } + { + \use:x + { \tl_if_in:nnTF { \tl_to_str:N #1 } { \tl_to_str:n {#2} } } + { \prg_return_true: } { \prg_return_false: } + } +\cs_generate_variant:Nn \str_if_in:NnT { c } +\cs_generate_variant:Nn \str_if_in:NnF { c } +\cs_generate_variant:Nn \str_if_in:NnTF { c } +\prg_new_protected_conditional:Npnn \str_if_in:nn #1#2 { T , F , TF } + { + \use:x + { \tl_if_in:nnTF { \tl_to_str:n {#1} } { \tl_to_str:n {#2} } } + { \prg_return_true: } { \prg_return_false: } + } +% \end{macrocode} +% \end{macro} +% % \begin{macro}[EXP, noTF] % {\str_case:nn, \str_case:on, \str_case:nV, \str_case:nv, \str_case_x:nn} % \begin{macro}[EXP, aux]{\@@_case:nnTF, \@@_case_x:nnTF} @@ -945,6 +1290,71 @@ % \end{macro} % \end{macro} % +% \subsection{Mapping to strings} +% +% \begin{macro}[rEXP]{\str_map_function:NN, \str_map_function:cN} +% \begin{macro}{\str_map_inline:Nn, \str_map_inline:cn} +% \begin{macro}{\str_map_variable:NNn, \str_map_variable:cNn} +% \begin{macro}{\str_map_break:} +% \begin{macro}{\str_map_break:n} +% Slightly awkward as we need to ensure detokenization: beyond that +% just the usual token list mappings. +% \begin{macrocode} +\cs_new:Npn \str_map_function:nN #1#2 + { + \exp_after:wN \@@_map_function:Nn \exp_after:wN #2 + \etex_detokenize:n {#1} + \q_recursion_tail + \__prg_break_point:Nn \str_map_break: { } + } +\cs_new:Npn \str_map_function:NN + { \exp_args:No \str_map_function:nN } +\cs_new:Npn \@@_map_function:Nn #1#2 + { + \__quark_if_recursion_tail_break:nN {#2} \str_map_break: + #1 {#2} \@@_map_function:Nn #1 + } +\cs_generate_variant:Nn \str_map_function:NN { c } +\cs_new_protected:Npn \str_map_inline:nn #1#2 + { + \int_gincr:N \g__prg_map_int + \cs_gset_protected:cpn + { __prg_map_ \int_use:N \g__prg_map_int :w } ##1 {#2} + \exp_args:Nc \@@_map_function:Nn + { __prg_map_ \int_use:N \g__prg_map_int :w } + #1 \q_recursion_tail + \__prg_break_point:Nn \str_map_break: { \int_gdecr:N \g__prg_map_int } + } +\cs_new_protected:Npn \str_map_inline:Nn + { \exp_args:No \str_map_inline:nn } +\cs_generate_variant:Nn \str_map_inline:Nn { c } +\cs_new_protected:Npn \str_map_variable:nNn #1#2#3 + { + \@@_map_variable:Nnn #2 {#3} #1 + \q_recursion_tail + \__prg_break_point:Nn \str_map_break: { } + } +\cs_new_protected:Npn \str_map_variable:NNn + { \exp_args:No \str_map_variable:nNn } +\cs_new_protected:Npn \@@_map_variable:Nnn #1#2#3 + { + \str_set:Nn #1 {#3} + \__quark_if_recursion_tail_break:NN #1 \str_map_break: + \use:n {#2} + \@@_map_variable:Nnn #1 {#2} + } +\cs_generate_variant:Nn \str_map_variable:NNn { c } +\cs_new:Npn \str_map_break: + { \__prg_map_break:Nn \str_map_break: { } } +\cs_new:Npn \str_map_break:n + { \__prg_map_break:Nn \str_map_break: } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% % \subsection{Accessing specific characters in a string} % % \begin{macro}[EXP, int]{\@@_to_other:n} @@ -965,7 +1375,7 @@ } \group_begin: \tex_lccode:D `\* = `\ % -\tex_lccode:D `\A = `\A +\tex_lccode:D `\A = `\A % \tex_lowercase:D { \group_end: @@ -998,7 +1408,7 @@ } \group_begin: \tex_lccode:D `\* = `\ % -\tex_lccode:D `\A = `\A +\tex_lccode:D `\A = `\A % \tex_lowercase:D { \group_end: @@ -1632,7 +2042,7 @@ \tex_catcode:D `\# = 12 \scan_stop: \tex_catcode:D `\ = 10 \scan_stop: \tex_openin:D \g_@@_data_ior = #1 \scan_stop: - \cs_if_exist:NT \utex_char:D + \cs_if_exist:NT \utex_char:D { \@@_map_loop: } \tex_closein:D \g_@@_data_ior \group_end: @@ -1688,7 +2098,7 @@ { \utex_char:D "#5 } } } -% \end{macrocode} +% \end{macrocode} % Parse the main Unicode data file for title case exceptions (the one-to-one % lower and upper case mappings it contains are all be covered by the \TeX{} % data). @@ -1710,7 +2120,7 @@ } } \@@_map_inline:n { UnicodeData.txt } -% \end{macrocode} +% \end{macrocode} % The set up for case folding is in two parts. For the basic (core) mappings, % folding is the same as lower casing in most positions so only store % the differences. For the more complex foldings, always store the result, |