diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3regex.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3regex.dtx | 361 |
1 files changed, 266 insertions, 95 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx b/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx index 4962ca6fa2e..7f384c8d56d 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2021-05-11} +% \date{Released 2021-05-25} % % \maketitle % @@ -1574,7 +1574,7 @@ \tl_put_right:Nx \l_@@_internal_a_tl { \exp_after:wN \@@_escape_loop:N \g_@@_internal_tl - { break } \prg_break_point: + \scan_stop: \prg_break_point: } \exp_after:wN \group_end: @@ -1620,7 +1620,7 @@ % % \begin{macro} % { -% \@@_escape_break:w, \@@_escape_/break:w, +% \@@_escape_\scan_stop::w, \@@_escape_/\scan_stop::w, % \@@_escape_/a:w, \@@_escape_/e:w, \@@_escape_/f:w, % \@@_escape_/n:w, \@@_escape_/r:w, \@@_escape_/t:w % } @@ -1630,8 +1630,8 @@ % backslash. Spaces are ignored, and |\a|, |\e|, |\f|, |\n|, |\r|, % |\t| take their meaning here. % \begin{macrocode} -\cs_new_eq:NN \@@_escape_break:w \prg_break: -\cs_new:cpn { @@_escape_/break:w } +\cs_new_eq:cN { @@_escape_ \iow_char:N\\scan_stop: :w } \prg_break: +\cs_new:cpn { @@_escape_/ \iow_char:N\\scan_stop: :w } { \__kernel_msg_expandable_error:nn { regex } { trailing-backslash } \prg_break: @@ -1691,7 +1691,10 @@ % \begin{macrocode} \cs_new:Npn \@@_escape_x_test:N #1 { - \str_if_eq:nnTF {#1} { break } { ; } + \if_meaning:w \scan_stop: #1 + \exp_after:wN \use_i:nnn \exp_after:wN ; + \fi: + \use:n { \if_charcode:w \c_space_token #1 \exp_after:wN \@@_escape_x_test:N @@ -1719,7 +1722,10 @@ % \begin{macrocode} \cs_new:Npn \@@_escape_x:N #1 { - \str_if_eq:nnTF {#1} { break } { ; } + \if_meaning:w \scan_stop: #1 + \exp_after:wN \use_i:nnn \exp_after:wN ; + \fi: + \use:n { \@@_hexadecimal_use:NTF #1 { ; \@@_escape_loop:N } @@ -1736,7 +1742,10 @@ % \begin{macrocode} \cs_new:Npn \@@_escape_x_loop:N #1 { - \str_if_eq:nnTF {#1} { break } + \if_meaning:w \scan_stop: #1 + \exp_after:wN \use_ii:nnn + \fi: + \use_ii:nn { ; \@@_escape_x_loop_error:n { } {#1} } { \@@_hexadecimal_use:NTF #1 @@ -2251,7 +2260,7 @@ \prg_do_nothing: \prg_do_nothing: } { } - \if_int_compare:w \l_@@_group_level_int > 0 \exp_stop_f: + \if_int_compare:w \l_@@_group_level_int > \c_zero_int \__kernel_msg_error:nnx { regex } { missing-rparen } { \int_use:N \l_@@_group_level_int } \prg_replicate:nn @@ -3017,7 +3026,7 @@ } \cs_new_protected:Npn \@@_compile_group_end: { - \if_int_compare:w \l_@@_group_level_int > 0 \exp_stop_f: + \if_int_compare:w \l_@@_group_level_int > \c_zero_int \tl_build_put_right:Nn \l_@@_build_tl { \if_false: { \fi: } } \tl_build_end:N \l_@@_build_tl \exp_args:NNNx @@ -3597,7 +3606,7 @@ { \@@_class:NnnnN \c_true_bool { - \if_int_compare:w "##3 = 0 \exp_stop_f: + \if_int_compare:w "##3 = \c_zero_int \@@_item_exact_cs:n { \exp_after:wN \cs_to_str:N ##1 } \else: @@ -4314,7 +4323,7 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_class_repeat:nN #1#2 { - \if_int_compare:w #1 = 0 \exp_stop_f: + \if_int_compare:w #1 = \c_zero_int \@@_build_transitions_lazyness:NNNNN #2 \@@_action_free:n \l_@@_right_state_int \@@_tests_action_cost:n \l_@@_left_state_int @@ -4374,9 +4383,8 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_group_aux:nnnnN #1#2#3#4#5 { - \if_int_compare:w #3 = 0 \exp_stop_f: + \if_int_compare:w #3 = \c_zero_int \@@_build_new_state: -%<assert>\assert_int:n { \l_@@_max_state_int = \l_@@_right_state_int + 1 } \@@_build_transition_right:nNn \@@_action_free_group:n \l_@@_left_state_int \l_@@_right_state_int \fi: @@ -4479,7 +4487,7 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_group_repeat:nn #1#2 { - \if_int_compare:w #2 = 0 \exp_stop_f: + \if_int_compare:w #2 = \c_zero_int \int_set:Nn \l_@@_max_state_int { \l_@@_left_state_int - 1 } \@@_build_new_state: @@ -4499,7 +4507,7 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_group_submatches:nNN #1#2#3 { - \if_int_compare:w #1 > - 1 \exp_stop_f: + \if_int_compare:w #1 > - \c_one_int \@@_toks_put_left:Nx #2 { \@@_action_submatch:nN {#1} < } \@@_toks_put_left:Nx #3 { \@@_action_submatch:nN {#1} > } \fi: @@ -4523,7 +4531,7 @@ \l_@@_right_state_int \l_@@_max_state_int \int_set_eq:NN \l_@@_internal_a_int \l_@@_left_state_int \int_set_eq:NN \l_@@_internal_b_int \l_@@_max_state_int - \if_int_compare:w \int_eval:n {#1} > 1 \exp_stop_f: + \if_int_compare:w \int_eval:n {#1} > \c_one_int \int_set:Nn \l_@@_internal_c_int { ( #1 - 1 ) @@ -4562,7 +4570,7 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_group_repeat:nnN #1#2#3 { - \if_int_compare:w #2 = 0 \exp_stop_f: + \if_int_compare:w #2 = \c_zero_int \@@_group_submatches:nNN {#1} \l_@@_left_state_int \l_@@_right_state_int \int_set:Nn \l_@@_internal_a_int @@ -4633,7 +4641,7 @@ \@@_build_transition_right:nNn \@@_action_free:n \l_@@_right_state_int \l_@@_max_state_int } - \if_int_compare:w #2 = 0 \exp_stop_f: + \if_int_compare:w #2 = \c_zero_int \int_set:Nn \l_@@_right_state_int { \l_@@_left_state_int - 1 } \else: @@ -5588,7 +5596,7 @@ { \@@_replacement_normal:n ##1 } {#1} \prg_do_nothing: \prg_do_nothing: - \if_int_compare:w \l_@@_replacement_csnames_int > 0 \exp_stop_f: + \if_int_compare:w \l_@@_replacement_csnames_int > \c_zero_int \__kernel_msg_error:nnx { regex } { replacement-missing-rbrace } { \int_use:N \l_@@_replacement_csnames_int } \tl_build_put_right:Nx \l_@@_build_tl @@ -5747,7 +5755,7 @@ { \tl_build_put_right:Nn \l_@@_build_tl { \@@_query_submatch:n { \int_eval:n { #1 + ##1 } } } - \if_int_compare:w \l_@@_replacement_csnames_int = 0 \exp_stop_f: + \if_int_compare:w \l_@@_replacement_csnames_int = \c_zero_int \tl_put_right:Nn \l_@@_balance_tl { + \@@_submatch_balance:n @@ -5869,7 +5877,7 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_replacement_rbrace:N #1 { - \if_int_compare:w \l_@@_replacement_csnames_int > 0 \exp_stop_f: + \if_int_compare:w \l_@@_replacement_csnames_int > \c_zero_int \tl_build_put_right:Nn \l_@@_build_tl { \cs_end: } \int_decr:N \l_@@_replacement_csnames_int \else: @@ -5885,7 +5893,7 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_replacement_lbrace:N #1 { - \if_int_compare:w \l_@@_replacement_csnames_int > 0 \exp_stop_f: + \if_int_compare:w \l_@@_replacement_csnames_int > \c_zero_int \__kernel_msg_error:nnn { regex } { cu-lbrace } { u } \else: \@@_replacement_normal:n {#1} @@ -5990,7 +5998,7 @@ \char_set_catcode_group_begin:N \^^@ \cs_new_protected:Npn \@@_replacement_c_B:w { - \if_int_compare:w \l_@@_replacement_csnames_int = 0 \exp_stop_f: + \if_int_compare:w \l_@@_replacement_csnames_int = \c_zero_int \int_incr:N \l_@@_balance_int \fi: \@@_replacement_char:nNN @@ -6030,7 +6038,7 @@ \char_set_catcode_group_end:N \^^@ \cs_new_protected:Npn \@@_replacement_c_E:w { - \if_int_compare:w \l_@@_replacement_csnames_int = 0 \exp_stop_f: + \if_int_compare:w \l_@@_replacement_csnames_int = \c_zero_int \int_decr:N \l_@@_balance_int \fi: \@@_replacement_char:nNN @@ -6091,7 +6099,7 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_replacement_c_S:w #1#2 { - \if_int_compare:w `#2 = 0 \exp_stop_f: + \if_int_compare:w `#2 = \c_zero_int \__kernel_msg_error:nn { regex } { replacement-null-space } \fi: \tex_lccode:D `\ = `#2 \scan_stop: @@ -6298,8 +6306,8 @@ % \end{variable} % % \begin{variable}{@@_begin, @@_end} -% Those flags are raised to indicate extra begin-group -% or end-group tokens when extracting submatches. +% Those flags are raised to indicate begin-group or end-group tokens +% that had to be added when extracting submatches. % \begin{macrocode} \flag_new:n { @@_begin } \flag_new:n { @@_end } @@ -6340,6 +6348,15 @@ % \end{macrocode} % \end{variable} % +% \begin{variable}{\l_@@_added_begin_int, \l_@@_added_end_int} +% Keep track of the number of left/right braces to add when performing +% a regex operation such as a replacement. +% \begin{macrocode} +\int_new:N \l_@@_added_begin_int +\int_new:N \l_@@_added_end_int +% \end{macrocode} +% \end{variable} +% % \begin{macro}{\@@_return:} % This function triggers either \cs{prg_return_false:} or % \cs{prg_return_true:} as appropriate to whether a match was found or @@ -6512,39 +6529,47 @@ % % \begin{macro}{\@@_group_end_extract_seq:N} % The end-points of submatches are stored as entries of two arrays -% from \cs{l_@@_min_submatch_int} to -% \cs{l_@@_submatch_int} (exclusive). Extract the relevant ranges -% into \cs{l_@@_internal_a_tl}. We detect unbalanced results using -% the two flags \texttt{__regex_begin} and \texttt{__regex_end}, raised -% whenever we see too many begin-group or end-group tokens in a -% submatch. +% from \cs{l_@@_min_submatch_int} to \cs{l_@@_submatch_int} +% (exclusive). Extract the relevant ranges into \cs{g_@@_internal_tl}, +% separated by \cs{@@_tmp:w} |{}|. We keep track in the two flags +% \texttt{__regex_begin} and \texttt{__regex_end} of the number of +% begin-group or end-group tokens added to make each of these items +% overall balanced. At this step, |}{| is counted as being balanced +% (same number of begin-group and end-group tokens). This problem is +% caught by \cs{@@_extract_check:w}, explained later. After +% complaining about any begin-group or end-group tokens we had to add, +% we are ready to construct the user's sequence outside the group. % \begin{macrocode} \cs_new_protected:Npn \@@_group_end_extract_seq:N #1 { \flag_clear:n { @@_begin } \flag_clear:n { @@_end } - \seq_set_from_function:NnN \l_@@_internal_seq + \cs_set_eq:NN \@@_tmp:w \scan_stop: + \__kernel_tl_gset:Nx \g_@@_internal_tl { \int_step_function:nnN { \l_@@_min_submatch_int } - { \l_@@_submatch_int - 1 } - } - \@@_extract_seq_aux:n - \int_compare:nNnF - { - \flag_height:n { @@_begin } + - \flag_height:n { @@_end } + { \l_@@_submatch_int - 1 } \@@_extract_seq_aux:n + \@@_tmp:w } - = 0 + \int_set:Nn \l_@@_added_begin_int + { \flag_height:n { @@_begin } } + \int_set:Nn \l_@@_added_end_int + { \flag_height:n { @@_end } } + \tex_afterassignment:D \@@_extract_check:w + \__kernel_tl_gset:Nx \g_@@_internal_tl + { \g_@@_internal_tl \if_false: { \fi: } } + \int_compare:nNnT + { \l_@@_added_begin_int + \l_@@_added_end_int } > 0 { \__kernel_msg_error:nnxxx { regex } { result-unbalanced } { splitting~or~extracting~submatches } - { \flag_height:n { @@_end } } - { \flag_height:n { @@_begin } } + { \int_use:N \l_@@_added_begin_int } + { \int_use:N \l_@@_added_end_int } } - \seq_set_map_x:NNn \l_@@_internal_seq \l_@@_internal_seq {##1} - \exp_args:NNNo - \group_end: - \tl_set:Nn #1 { \l_@@_internal_seq } + \group_end: + \cs_set_eq:NN \@@_tmp:w \@@_extract_map_loop:w + \seq_set_from_function:NnN #1 + { \@@_extract_map:N } \exp_not:n } % \end{macrocode} % \end{macro} @@ -6557,25 +6582,134 @@ % \begin{macrocode} \cs_new:Npn \@@_extract_seq_aux:n #1 { + \@@_tmp:w { } \exp_after:wN \@@_extract_seq_aux:ww \int_value:w \@@_submatch_balance:n {#1} ; #1; } \cs_new:Npn \@@_extract_seq_aux:ww #1; #2; { - \if_int_compare:w #1 < 0 \exp_stop_f: - \flag_raise:n { @@_end } - \prg_replicate:nn {-#1} { \exp_not:n { { \if_false: } \fi: } } + \if_int_compare:w #1 < \c_zero_int + \prg_replicate:nn {-#1} + { + \flag_raise:n { @@_begin } + \exp_not:n { { \if_false: } \fi: } + } \fi: \@@_query_submatch:n {#2} - \if_int_compare:w #1 > 0 \exp_stop_f: - \flag_raise:n { @@_begin } - \prg_replicate:nn {#1} { \exp_not:n { \if_false: { \fi: } } } + \if_int_compare:w #1 > \c_zero_int + \prg_replicate:nn {#1} + { + \flag_raise:n { @@_end } + \exp_not:n { \if_false: { \fi: } } + } \fi: } % \end{macrocode} % \end{macro} % -% \begin{macro}{\@@_extract:} +% \begin{macro} +% { +% \@@_extract_check:w, \@@_extract_check:n, +% \@@_extract_check_loop:w, \@@_extract_check_end:w +% } +% In \cs{@@_group_end_extract_seq:N} we had to expand +% \cs{g_@@_internal_tl} to turn \cs{if_false:} constructions into +% actual begin-group and end-group tokens. This is done with a +% \cs{__kernel_tl_gset:Nx} assignment, and \cs{@@_extract_check:w} is +% run immediately after this assignment ends, thanks to the +% \tn{afterassignment} primitive. If all of the items were properly +% balanced (enough begin-group tokens before end-group tokens, so |}{| +% is not) then \cs{@@_extract_check:w} is called just before the +% closing brace of the \cs{__kernel_tl_gset:Nx} (thanks to our sneaky +% \cs{if_false:} |{| \cs{fi:} |}| construction), and finds that there +% is nothing left to expand. If any of the items is unbalanced, the +% assignment gets ended early by an extra end-group token, and our +% check finds more tokens needing to be expanded in a new +% \cs{__kernel_tl_gset:Nx} assignment. We need to add a begin-group +% and an end-group tokens to the unbalanced item, namely to the last +% item found so far, which we reach through a loop. +% \begin{macrocode} +\cs_new_protected:Npn \@@_extract_check:w + { + \exp_after:wN \@@_extract_check:n + \exp_after:wN { \if_false: } \fi: + } +\cs_new_protected:Npn \@@_extract_check:n #1 + { + \tl_if_empty:nF {#1} + { + \int_incr:N \l_@@_added_begin_int + \int_incr:N \l_@@_added_end_int + \tex_afterassignment:D \@@_extract_check:w + \__kernel_tl_gset:Nx \g_@@_internal_tl + { + \exp_after:wN \@@_extract_check_loop:w + \g_@@_internal_tl + \@@_tmp:w \@@_extract_check_end:w + #1 + } + } + } +\cs_new:Npn \@@_extract_check_loop:w #1 \@@_tmp:w #2 + { + #2 + \exp_not:o {#1} + \@@_tmp:w { } + \@@_extract_check_loop:w \prg_do_nothing: + } +% \end{macrocode} +% Arguments of \cs{@@_extract_check_end:w} are: |#1| is the part of +% the item before the extra end-group token; |#2| is junk; |#3| is +% \cs{prg_do_nothing:} followed by the not-yet-expanded part of the +% item after the extra end-group token. In the replacement text, the +% first brace and the \cs{if_false:} |{| \cs{fi:} |}| construction are +% the added begin-group and end-group tokens (the latter being not-yet +% expanded, just like~|#3|), while the closing brace after +% \cs{exp_not:o} |{#1}| replaces the extra end-group token that had +% ended the assignment early. In particular this means that the +% character code of that end-group token is lost. +% \begin{macrocode} +\cs_new:Npn \@@_extract_check_end:w + \exp_not:o #1#2 \@@_extract_check_loop:w #3 \@@_tmp:w + { + { \exp_not:o {#1} } + #3 + \if_false: { \fi: } + \@@_tmp:w + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP] +% { +% \@@_extract_map:N, +% \@@_extract_map_aux:NNn, +% \@@_extract_map_loop:w +% } +% This receives a |seq| internal function and maps it over all items +% in \cs{g_@@_internal_tl}. This token list takes the form +% \cs{@@_tmp:w} |{}| \meta{item_1} \cs{@@_tmp:w} |{}| \meta{item_2} +% \ldots{} \cs{@@_tmp:w}, and the calling code has set \cs{@@_tmp:w} +% equal to \cs{@@_extract_map_loop:w}. The loop is otherwise pretty +% standard, with \cs{prg_do_nothing:} to avoid losing braces. +% \begin{macrocode} +\cs_new:Npn \@@_extract_map:N #1 + { + \exp_after:wN \@@_extract_map_aux:NNn + \exp_after:wN #1 + \g_@@_internal_tl \use_none:nnn + } +\cs_new:Npn \@@_extract_map_aux:NNn #1#2#3 + { #3 #2 #1 \prg_do_nothing: } +\cs_new:Npn \@@_extract_map_loop:w #1#2 \@@_tmp:w #3 + { + \exp_after:wN #1 \exp_after:wN {#2} + #3 \@@_extract_map_loop:w #1 \prg_do_nothing: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_extract:, \@@_extract_aux:w} % Our task here is to store the list of end-points of submatches, and % store them in appropriate array entries, from % \cs{l_@@_zeroth_submatch_int} upwards. First, we store in @@ -6598,19 +6732,24 @@ \__kernel_intarray_gset:Nnn \g_@@_submatch_prev_intarray { \l_@@_zeroth_submatch_int } { \l_@@_start_pos_int } \int_zero:N \l_@@_internal_a_int - \clist_map_inline:Nn \l_@@_success_submatches_tl - { - \if_int_compare:w \l_@@_internal_a_int < \l_@@_capturing_group_int - \__kernel_intarray_gset:Nnn \g_@@_submatch_begin_intarray - { \@@_int_eval:w \l_@@_zeroth_submatch_int + \l_@@_internal_a_int } {##1} - \else: - \__kernel_intarray_gset:Nnn \g_@@_submatch_end_intarray - { \@@_int_eval:w \l_@@_zeroth_submatch_int + \l_@@_internal_a_int - \l_@@_capturing_group_int } {##1} - \fi: - \int_incr:N \l_@@_internal_a_int - } + \exp_after:wN \@@_extract_aux:w \l_@@_success_submatches_tl + \prg_break_point: \@@_use_none_delimit_by_q_recursion_stop:w , + \q_@@_recursion_stop \fi: } +\cs_new_protected:Npn \@@_extract_aux:w #1 , + { + \prg_break: #1 \prg_break_point: + \if_int_compare:w \l_@@_internal_a_int < \l_@@_capturing_group_int + \__kernel_intarray_gset:Nnn \g_@@_submatch_begin_intarray + { \@@_int_eval:w \l_@@_zeroth_submatch_int + \l_@@_internal_a_int } {#1} + \else: + \__kernel_intarray_gset:Nnn \g_@@_submatch_end_intarray + { \@@_int_eval:w \l_@@_zeroth_submatch_int + \l_@@_internal_a_int - \l_@@_capturing_group_int } {#1} + \fi: + \int_incr:N \l_@@_internal_a_int + \@@_extract_aux:w + } % \end{macrocode} % \end{macro} % @@ -6708,36 +6847,65 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}{\@@_group_end_replace:N} -% If the brace balance is not $0$, raise an error. Then set the user's -% variable |#1| to the \texttt{x}-expansion of -% \cs{l_@@_internal_a_tl}, adding the appropriate braces to produce -% a balanced result. And end the group. +% \begin{macro} +% { +% \@@_group_end_replace:N, \@@_group_end_replace_try:, +% \@@_group_end_replace_check:w, \@@_group_end_replace_check:n +% } +% At this stage \cs{l_@@_internal_a_tl} (|x|-expands to the desired +% result). Guess from \cs{l_@@_balance_int} the number of braces to +% add before or after the result then try expanding. The simplest +% case is when \cs{l_@@_internal_a_tl} together with the braces we +% insert via \cs{prg_replicate:nn} give a balanced result, and the +% assignment ends at the \cs{if_false:} |{| \cs{fi:} |}| construction: +% then \cs{@@_group_end_replace_check:w} sees that there is no +% material left and we successfully found the result. The harder case +% is that expanding \cs{l_@@_internal_a_tl} may produce extra closing +% braces and end the assignment early. Then we grab the remaining code +% using; importantly, what follows has not yet been expanded so that +% \cs{@@_group_end_replace_check:n} grabs everything until the last +% brace in \cs{@@_group_end_replace_try:}, letting us try again with +% an extra surrounding pair of braces. % \begin{macrocode} \cs_new_protected:Npn \@@_group_end_replace:N #1 { - \if_int_compare:w \l_@@_balance_int = 0 \exp_stop_f: - \else: - \__kernel_msg_error:nnxxx { regex } { result-unbalanced } - { replacing } - { \int_max:nn { - \l_@@_balance_int } { 0 } } - { \int_max:nn { \l_@@_balance_int } { 0 } } - \fi: - \use:x + \int_set:Nn \l_@@_added_begin_int + { \int_max:nn { - \l_@@_balance_int } { 0 } } + \int_set:Nn \l_@@_added_end_int + { \int_max:nn { \l_@@_balance_int } { 0 } } + \@@_group_end_replace_try: + \int_compare:nNnT { \l_@@_added_begin_int + \l_@@_added_end_int } > 0 { - \group_end: - \tl_set:Nn \exp_not:N #1 - { - \if_int_compare:w \l_@@_balance_int < 0 \exp_stop_f: - \prg_replicate:nn { - \l_@@_balance_int } - { { \if_false: } \fi: } - \fi: - \l_@@_internal_a_tl - \if_int_compare:w \l_@@_balance_int > 0 \exp_stop_f: - \prg_replicate:nn { \l_@@_balance_int } - { \if_false: { \fi: } } - \fi: - } + \__kernel_msg_error:nnxxx { regex } { result-unbalanced } + { replacing } { \int_use:N \l_@@_added_begin_int } + { \int_use:N \l_@@_added_end_int } + } + \group_end: + \tl_set_eq:NN #1 \g_@@_internal_tl + } +\cs_new_protected:Npn \@@_group_end_replace_try: + { + \tex_afterassignment:D \@@_group_end_replace_check:w + \__kernel_tl_gset:Nx \g_@@_internal_tl + { + \prg_replicate:nn { \l_@@_added_begin_int } { { \if_false: } \fi: } + \l_@@_internal_a_tl + \prg_replicate:nn { \l_@@_added_end_int } { \if_false: { \fi: } } + \if_false: { \fi: } + } + } +\cs_new_protected:Npn \@@_group_end_replace_check:w + { + \exp_after:wN \@@_group_end_replace_check:n + \exp_after:wN { \if_false: } \fi: + } +\cs_new_protected:Npn \@@_group_end_replace_check:n #1 + { + \tl_if_empty:nF {#1} + { + \int_incr:N \l_@@_added_begin_int + \int_incr:N \l_@@_added_end_int + \@@_group_end_replace_try: } } % \end{macrocode} @@ -7551,6 +7719,7 @@ %^^A recursion condition %^^A (?(DEFINE)... define subpattern for reference %^^A (?(assert)... assertion condition +%^^A (?(?=..)..|..) positive/negative look ahead/behind condition %^^A (*ACCEPT) force successful match %^^A (*FAIL) force backtrack; synonym (*F) %^^A (*COMMIT) overall failure, no advance of starting point @@ -7567,8 +7736,10 @@ %^^A + possessive quantifiers %^^A (?>...) atomic, non-capturing group %^^A (?#....) comment (not nestable) -%^^A (?JmsUx) options (duplicate names; multiline; single line; -%^^A ungreedy; extended) +%^^A (?Jms-UxX) options (duplicate names; multiline; single line; +%^^A unset what follows; ungreedy; extended; +%^^A error on bad escapes) +%^^A (?i:...|...) convenient shorthand for (?:(?i)...|...) %^^A (*NO_START_OPT) no start-match optimization (PCRE_NO_START_OPTIMIZE) %^^A (*UTF8) set UTF-8 mode (PCRE_UTF8) %^^A (*UCP) set PCRE_UCP (use Unicode properties for \d etc) |