%% %% This is file `l3regex.sty', %% generated with the docstrip utility. %% %% The original source files were: %% %% l3regex.dtx (with options: `package') %% %% EXPERIMENTAL CODE %% %% Do not distribute this file without also distributing the %% source files specified above. %% %% Do not distribute a modified version of this file. %% %% File: l3regex.dtx Copyright (C) 2011-2012 The LaTeX3 Project %% %% It may be distributed and/or modified under the conditions of the %% LaTeX Project Public License (LPPL), either version 1.3c of this %% license or (at your option) any later version. The latest version %% of this license is in the file %% %% http://www.latex-project.org/lppl.txt %% %% This file is part of the "l3experimental bundle" (The Work in LPPL) %% and all files in that bundle must be distributed together. %% %% The released version of this bundle is available from CTAN. %% %% ----------------------------------------------------------------------- %% %% The development version of the bundle can be found at %% %% http://www.latex-project.org/svnroot/experimental/trunk/ %% %% for those people who are interested. %% %%%%%%%%%%% %% NOTE: %% %%%%%%%%%%% %% %% Snapshots taken from the repository represent work in progress and may %% not work or may contain conflicting material! We therefore ask %% people _not_ to put them into distributions, archives, etc. without %% prior consultation with the LaTeX3 Project. %% %% ----------------------------------------------------------------------- \RequirePackage{expl3} \GetIdInfo$Id: l3regex.dtx 3326 2012-02-07 00:39:44Z bruno $ {L3 Experimental Regular Expressions} \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \RequirePackage{l3str, l3tl-analysis, l3flag} \cs_new:Npn \regex_tmp:w { } \tl_new:N \l_regex_internal_a_tl \tl_new:N \l_regex_internal_b_tl \int_new:N \l_regex_internal_a_int \int_new:N \l_regex_internal_b_int \int_new:N \l_regex_internal_c_int \tl_new:N \g_regex_internal_tl \tl_const:Nn \c_regex_d_tl { \regex_item_range:nn \c_forty_eight { 57 } } % 0--9 \tl_const:Nn \c_regex_h_tl { \regex_item_equal:n \c_thirty_two % space \regex_item_equal:n \c_nine % tab } \tl_const:Nn \c_regex_s_tl { \regex_item_equal:n \c_thirty_two % space \regex_item_equal:n \c_nine % tab \regex_item_equal:n \c_ten % lf \regex_item_equal:n \c_twelve % ff \regex_item_equal:n \c_thirteen % cr } \tl_const:Nn \c_regex_v_tl { \regex_item_range:nn \c_ten \c_thirteen } % lf, vtab, ff, cr \tl_const:Nn \c_regex_w_tl { \regex_item_range:nn \c_ninety_seven { 122 } % a--z \regex_item_range:nn \c_sixty_five { 90 } % A--Z \regex_item_range:nn \c_forty_eight { 57 } % 0--9 \regex_item_equal:n { 95 } % _ } \tl_const:Nn \c_regex_D_tl { \c_regex_d_tl \regex_break_point:TF { } \regex_break_true:w } \tl_const:Nn \c_regex_H_tl { \c_regex_h_tl \regex_break_point:TF { } \regex_break_true:w } \tl_const:Nn \c_regex_S_tl { \c_regex_s_tl \regex_break_point:TF { } \regex_break_true:w } \tl_const:Nn \c_regex_V_tl { \c_regex_v_tl \regex_break_point:TF { } \regex_break_true:w } \tl_const:Nn \c_regex_W_tl { \c_regex_w_tl \regex_break_point:TF { } \regex_break_true:w } \tl_const:Nn \c_regex_N_tl { \regex_item_equal:n \c_ten \regex_break_point:TF { } { \regex_break_true:w } } \tl_const:cn { c_regex_._tl } { \if_num:w \l_regex_current_char_int > - \c_two \exp_after:wN \regex_break_true:w \fi: } \int_new:N \l_regex_build_mode_int \int_new:N \l_regex_max_state_int \int_new:N \l_regex_left_state_int \int_new:N \l_regex_right_state_int \seq_new:N \l_regex_left_state_seq \seq_new:N \l_regex_right_state_seq \seq_new:N \l_regex_end_group_seq \seq_new:N \l_regex_end_alternation_seq \int_new:N \l_regex_capturing_group_int \seq_new:N \l_regex_capturing_group_seq \int_new:N \l_regex_capturing_group_max_int \tl_new:N \l_regex_one_or_group_tl \int_new:N \l_regex_catcodes_int \int_new:N \l_regex_catcodes_default_int \int_const:Nn \c_regex_catcode_C_int { "1 } \int_const:Nn \c_regex_catcode_B_int { "4 } \int_const:Nn \c_regex_catcode_E_int { "10 } \int_const:Nn \c_regex_catcode_M_int { "40 } \int_const:Nn \c_regex_catcode_T_int { "100 } \int_const:Nn \c_regex_catcode_P_int { "1000 } \int_const:Nn \c_regex_catcode_U_int { "4000 } \int_const:Nn \c_regex_catcode_D_int { "10000 } \int_const:Nn \c_regex_catcode_S_int { "100000 } \int_const:Nn \c_regex_catcode_L_int { "400000 } \int_const:Nn \c_regex_catcode_O_int { "1000000 } \int_const:Nn \c_regex_catcode_A_int { "4000000 } \int_const:Nn \c_regex_catcodes_all_int { "5515155 } \bool_new:N \l_regex_catcodes_bool \bool_new:N \l_regex_tests_bool \tl_new:N \l_regex_tests_tl \bool_new:N \l_regex_tests_saved_bool \tl_new:N \l_regex_tests_saved_tl \int_new:N \l_regex_catcodes_saved_int \int_new:N \l_regex_min_index_int \int_new:N \l_regex_max_index_int \int_new:N \l_regex_nesting_int \int_new:N \l_regex_current_index_int \int_new:N \l_regex_start_index_int \int_new:N \l_regex_success_index_int \int_new:N \l_regex_current_char_int \int_new:N \l_regex_current_catcode_int \tl_new:N \l_regex_current_token_tl \int_new:N \l_regex_last_char_int \int_new:N \l_regex_case_changed_char_int \bool_new:N \l_regex_caseless_bool \int_new:N \l_regex_current_state_int \prop_new:N \l_regex_current_submatches_prop \prop_new:N \l_regex_success_submatches_prop \int_new:N \l_regex_step_int \int_new:N \l_regex_max_active_int \tl_new:N \l_regex_every_match_tl \bool_new:N \l_regex_fresh_thread_bool \bool_new:N \l_regex_success_empty_bool \cs_new_eq:NN \regex_if_two_empty_matches:F \use:n \bool_new:N \g_regex_success_bool \bool_new:N \l_regex_saved_success_bool \bool_new:N \l_regex_success_match_bool \tl_const:Nn \c_regex_no_match_regex { \regex_nfa:Nw \c_regex_no_match_regex \l_regex_max_state_int = \c_one \l_regex_capturing_group_int = \c_zero \tex_toks:D \c_zero { \s_stop } \s_stop } \cs_new_protected:Npn \regex_new:N #1 { \chk_if_free_cs:N #1 \cs_gset_eq:NN #1 \c_regex_no_match_regex } \regex_new:N \l_regex_internal_regex \int_new:N \l_regex_replacement_csnames_int \int_new:N \l_regex_replacement_int \int_new:N \l_regex_submatch_int \int_new:N \l_regex_submatch_start_int \int_new:N \l_regex_match_count_int \flag_new:n { regex_begin } \flag_new:n { regex_end } \cs_new_protected:Npn \regex_toks_put_left:Nx #1#2 { \cs_set_nopar:Npx \regex_tmp:w \s_stop { \s_stop #2 } \tex_toks:D #1 \exp_after:wN \exp_after:wN \exp_after:wN { \exp_after:wN \regex_tmp:w \tex_the:D \tex_toks:D #1 } } \cs_new_protected:Npn \regex_toks_put_right:Nx #1#2 { \cs_set_nopar:Npx \regex_tmp:w {#2} \tex_toks:D #1 \exp_after:wN { \tex_the:D \tex_toks:D \exp_after:wN #1 \regex_tmp:w } } \cs_new:Npn \regex_toks_range:nn #1#2 { \exp_after:wN \regex_toks_range:ww \int_use:N \int_eval:w #1 \exp_after:wN ; \int_use:N \int_eval:w #2 ; \prg_break_point:n { } } \cs_new:Npn \regex_toks_range:ww #1 ; #2 ; { \if_num:w #1 < #2 \exp_stop_f: \else: \exp_after:wN \prg_map_break: \fi: \tex_the:D \tex_toks:D #1 \exp_stop_f: \exp_after:wN \regex_toks_range:ww \int_use:N \int_eval:w #1 + \c_one ; #2 ; } \cs_new:Npn \regex_query_submatch:nn #1#2 { \if_num:w #1 < \l_regex_capturing_group_int \exp_after:wN \regex_query_submatch:w \int_use:N \int_eval:w #1 + #2 ; \fi: } \cs_new:Npn \regex_query_submatch:w #1 ; { \regex_toks_range:nn { \tex_skip:D #1 } { \etex_gluestretch:D \tex_skip:D #1 } } \cs_new_protected:Npn \regex_seq_pop_int:NN #1#2 { \seq_pop:NN #1 \l_regex_internal_a_tl \int_set:Nn #2 \l_regex_internal_a_tl } \cs_new_protected:Npn \regex_seq_get_int:NN #1#2 { \seq_get:NN #1 \l_regex_internal_a_tl \int_set:Nn #2 \l_regex_internal_a_tl } \cs_new_protected:Npn \regex_seq_push_int:NN #1#2 { \seq_push:No #1 { \int_use:N #2 } } \cs_new_protected:Npn \regex_seq_pop_use:N #1 { \seq_pop:NN #1 \l_regex_internal_a_tl \l_regex_internal_a_tl } \cs_new_protected:Npn \regex_seq_get_use:N #1 { \seq_get:NN #1 \l_regex_internal_a_tl \l_regex_internal_a_tl } \cs_new_protected:Npn \regex_get_digits:nw #1 { \tex_afterassignment:D \regex_tmp:w \cs_set_nopar:Npx \regex_tmp:w { \exp_not:n {#1} { \if_false: } } \fi: \regex_get_digits_aux:NN } \cs_new:Npn \regex_get_digits_aux:NN #1#2 { \if_meaning:w \regex_build_raw:N #1 \if_num:w 9 < 1 \exp_not:N #2 \exp_stop_f: #2 \else: \regex_get_digits_end:w #1 #2 \fi: \else: \regex_get_digits_end:w #1 #2 \fi: \regex_get_digits_aux:NN } \cs_new:Npn \regex_get_digits_end:w #1 \fi: #2 \regex_get_digits_aux:NN { \fi: #2 \if_false: { { \fi: } } #1 } \cs_new_protected:Npn \regex_break_true:w #1 \regex_break_point:TF #2 #3 {#2} \cs_new_protected:Npn \regex_break_point:TF #1 #2 { #2 } \cs_new_protected:Npn \regex_item_caseful_equal:n #1 { \if_num:w #1 = \l_regex_current_char_int \exp_after:wN \regex_break_true:w \fi: } \cs_new_protected:Npn \regex_item_caseful_range:nn #1 #2 { \reverse_if:N \if_num:w #1 > \l_regex_current_char_int \reverse_if:N \if_num:w #2 < \l_regex_current_char_int \exp_after:wN \exp_after:wN \exp_after:wN \regex_break_true:w \fi: \fi: } \cs_new_protected:Npn \regex_item_caseful_geq:n #1 { \reverse_if:N \if_num:w #1 > \l_regex_current_char_int \exp_after:wN \regex_break_true:w \fi: } \cs_new_protected:Npn \regex_item_caseless_equal:n #1 { \if_num:w #1 = \l_regex_current_char_int \exp_after:wN \regex_break_true:w \fi: \if_num:w #1 = \l_regex_case_changed_char_int \exp_after:wN \regex_break_true:w \fi: } \cs_new_protected:Npn \regex_item_caseless_range:nn #1 #2 { \reverse_if:N \if_num:w #1 > \l_regex_current_char_int \reverse_if:N \if_num:w #2 < \l_regex_current_char_int \exp_after:wN \exp_after:wN \exp_after:wN \regex_break_true:w \fi: \fi: \reverse_if:N \if_num:w #1 > \l_regex_case_changed_char_int \reverse_if:N \if_num:w #2 < \l_regex_case_changed_char_int \exp_after:wN \exp_after:wN \exp_after:wN \regex_break_true:w \fi: \fi: } \cs_new_protected:Npn \regex_item_caseless_geq:n #1 { \reverse_if:N \if_num:w #1 > \l_regex_current_char_int \exp_after:wN \regex_break_true:w \fi: \reverse_if:N \if_num:w #1 > \l_regex_case_changed_char_int \exp_after:wN \regex_break_true:w \fi: } \cs_new:Npn \regex_item_equal:n { \regex_item_caseful_equal:n } \cs_new:Npn \regex_item_range:nn { \regex_item_caseful_range:nn } \cs_new:Npn \regex_item_geq:n { \regex_item_caseful_geq:n } \cs_new_protected_nopar:Npn \regex_build_caseless: { \bool_set_true:N \l_regex_caseless_bool \cs_set:Npn \regex_item_equal:n { \regex_item_caseless_equal:n } \cs_set:Npn \regex_item_range:nn { \regex_item_caseless_range:nn } \cs_set:Npn \regex_item_geq:n { \regex_item_caseless_geq:n } } \cs_new_protected_nopar:Npn \regex_build_caseful: { \bool_set_false:N \l_regex_caseless_bool \cs_set:Npn \regex_item_equal:n { \regex_item_caseful_equal:n } \cs_set:Npn \regex_item_range:nn { \regex_item_caseful_range:nn } \cs_set:Npn \regex_item_geq:n { \regex_item_caseful_geq:n } } \cs_new_protected:Npn \regex_item_catcode_aux: { " \if_case:w \l_regex_current_catcode_int 1 \or: 4 \or: 10 \or: 40 \or: 100 \or: \or: 1000 \or: 4000 \or: 10000 \or: \or: 100000 \or: 400000 \or: 1000000 \or: 4000000 \else: 1*\c_zero \fi: } \cs_new_protected:Npn \regex_item_catcode:nT #1 { \if_int_odd:w \int_eval:w #1 / \regex_item_catcode_aux: \int_eval_end: \exp_after:wN \use:n \else: \exp_after:wN \use_none:n \fi: } \cs_new_protected:Npn \regex_item_cs:n #1 { \int_compare:nNnT \l_regex_current_catcode_int = \c_zero { \tl_set:Nn \l_regex_internal_regex {#1} \bool_set_eq:NN \l_regex_saved_success_bool \g_regex_success_bool \exp_args:NNx \regex_match:NnTF \l_regex_internal_regex { \exp_after:wN \exp_after:wN \exp_after:wN \cs_to_str:N \l_regex_current_token_tl } { \bool_gset_eq:NN \g_regex_success_bool \l_regex_saved_success_bool \regex_break_true:w } { \bool_gset_eq:NN \g_regex_success_bool \l_regex_saved_success_bool } } } \cs_new_protected:Npn \regex_escape_use:nnnn #1#2#3#4 { \group_begin: \cs_set_nopar:Npn \regex_escape_unescaped:N ##1 { #1 } \cs_set_nopar:Npn \regex_escape_escaped:N ##1 { #2 } \cs_set_nopar:Npn \regex_escape_raw:N ##1 { #3 } \int_set:Nn \tex_escapechar:D { 92 } \str_gset_other:Nn \g_regex_internal_tl {#4} \int_zero:N \l_regex_internal_a_int \tl_set:Nx \l_regex_internal_a_tl { \exp_after:wN \regex_escape_loop:N \g_regex_internal_tl { break } \prg_break_point:n { } } \use:x { \group_end: \regex_toks_range:nn \c_zero \l_regex_internal_a_int \exp_not:o \l_regex_internal_a_tl } } \cs_new:Npn \regex_escape_loop:N #1 { \cs_if_exist_use:cF { regex_escape_\token_to_str:N #1:w } { \regex_escape_unescaped:N #1 } \regex_escape_loop:N } \cs_new_nopar:cpn { regex_escape_ \c_backslash_str :w } \regex_escape_loop:N #1 { \cs_if_exist_use:cF { regex_escape_/\token_to_str:N #1:w } { \regex_escape_escaped:N #1 } \regex_escape_loop:N } \cs_new_eq:NN \regex_escape_unescaped:N ? \cs_new_eq:NN \regex_escape_escaped:N ? \cs_new_eq:NN \regex_escape_raw:N ? \cs_new_eq:NN \regex_escape_break:w \prg_map_break: \cs_new_nopar:cpn { regex_escape_/break:w } { \if_false: { \fi: } \msg_kernel_error:nn { regex } { trailing-backslash } \exp_after:wN \use_none:n \exp_after:wN { \if_false: } \fi: } \cs_new_nopar:cpn { regex_escape_~:w } { } \cs_new_nopar:cpx { regex_escape_/a:w } { \exp_not:N \regex_escape_raw:N \iow_char:N \^^G } \cs_new_nopar:cpx { regex_escape_/t:w } { \exp_not:N \regex_escape_raw:N \iow_char:N \^^I } \cs_new_nopar:cpx { regex_escape_/n:w } { \exp_not:N \regex_escape_raw:N \iow_char:N \^^J } \cs_new_nopar:cpx { regex_escape_/f:w } { \exp_not:N \regex_escape_raw:N \iow_char:N \^^L } \cs_new_nopar:cpx { regex_escape_/r:w } { \exp_not:N \regex_escape_raw:N \iow_char:N \^^M } \cs_new_nopar:cpx { regex_escape_/e:w } { \exp_not:N \regex_escape_raw:N \iow_char:N \^^[ } \cs_new_nopar:cpn { regex_escape_/x:w } \regex_escape_loop:N { \if_false: { \fi: } \tex_toks:D \l_regex_internal_a_int \exp_after:wN { \l_regex_internal_a_tl } \int_incr:N \l_regex_internal_a_int \int_zero:N \l_regex_current_char_int \regex_escape_x_test:N } \cs_new_protected:Npx \regex_escape_x_test:N #1 { \exp_not:N \token_if_eq_charcode:NNTF \c_space_token #1 { \exp_not:N \regex_escape_x_test:N } { \l_regex_current_char_int = "0 \exp_not:N \token_if_eq_charcode:NNTF \c_lbrace_str #1 { \exp_not:N \regex_escape_x_braced_loop:N } { \exp_not:N \regex_escape_x_unbraced_i:N #1 } } } \cs_new:Npn \regex_escape_x_unbraced_i:N #1 { \str_aux_hexadecimal_use:NTF #1 { \regex_escape_x_unbraced_ii:N } { \exp_stop_f: \regex_escape_x_end: #1 } } \cs_new:Npn \regex_escape_x_unbraced_ii:N #1 { \token_if_eq_charcode:NNTF \c_space_token #1 { \regex_escape_x_unbraced_ii:N } { \str_aux_hexadecimal_use:NTF #1 { \exp_stop_f: \regex_escape_x_end: } { \exp_stop_f: \regex_escape_x_end: #1 } } } \cs_new:Npn \regex_escape_x_braced_loop:N #1 { \token_if_eq_charcode:NNTF \c_space_token #1 { \regex_escape_x_braced_loop:N } { \str_aux_hexadecimal_use:NTF #1 { \regex_escape_x_braced_loop:N } { \exp_stop_f: \regex_escape_x_braced_end:N #1 } } } \cs_new_protected:Npx \regex_escape_x_braced_end:N #1 { \exp_not:N \token_if_eq_charcode:NNTF \c_rbrace_str #1 { \exp_not:N \regex_escape_x_end: } { \msg_kernel_error:nnx { regex } { x-missing-rbrace } { \int_use:N \l_regex_current_char_int } \exp_not:N \regex_escape_x_end: #1 } } \group_begin: \char_set_catcode_other:N \^^@ \cs_new_protected_nopar:Npn \regex_escape_x_end: { \if_num:w \l_regex_current_char_int > \c_max_char_int \msg_kernel_error:nnx { regex } { x-overflow } { \int_use:N \l_regex_current_char_int } \exp_after:wN \use:n \else: \tex_lccode:D \c_zero \l_regex_current_char_int \exp_after:wN \tl_to_lowercase:n \fi: { \tl_set:Nx \l_regex_internal_a_tl { \if_false: } \fi: \regex_escape_raw:N ^^@ \regex_escape_loop:N } } \group_end: \prg_new_conditional:Npnn \regex_char_if_special:N #1 { TF } { \if_num:w `#1 < \c_ninety_one \if_num:w `#1 < \c_fifty_eight \if_num:w `#1 < \c_forty_eight \if_num:w `#1 < \c_thirty_two \prg_return_false: \else: \prg_return_true: \fi: \else: \prg_return_false: \fi: \else: \if_num:w `#1 < \c_sixty_five \prg_return_true: \else: \prg_return_false: \fi: \fi: \else: \if_num:w `#1 < \c_one_hundred_twenty_three \if_num:w `#1 < \c_ninety_seven \prg_return_true: \else: \prg_return_false: \fi: \else: \if_num:w `#1 < \c_one_hundred_twenty_seven \prg_return_true: \else: \prg_return_false: \fi: \fi: \fi: } \prg_new_conditional:Npnn \regex_char_if_alphanumeric:N #1 { TF } { \if_num:w `#1 < \c_ninety_one \if_num:w `#1 < \c_fifty_eight \if_num:w `#1 < \c_forty_eight \prg_return_false: \else: \prg_return_true: \fi: \else: \if_num:w `#1 < \c_sixty_five \prg_return_false: \else: \prg_return_true: \fi: \fi: \else: \if_num:w `#1 < \c_one_hundred_twenty_three \if_num:w `#1 < \c_ninety_seven \prg_return_false: \else: \prg_return_true: \fi: \else: \prg_return_false: \fi: \fi: } \cs_new_nopar:Npn \regex_build_if_in_class:TF { \if_int_odd:w \l_regex_build_mode_int \exp_after:wN \use_i:nn \else: \exp_after:wN \use_ii:nn \fi: } \cs_new_nopar:Npn \regex_build_if_assertions_forbidden:TF { \if_int_odd:w \l_regex_build_mode_int \exp_after:wN \use_i:nn \else: \if_int_compare:w \l_regex_build_mode_int > \c_zero \exp_after:wN \exp_after:wN \exp_after:wN \use_i:nn \else: \exp_after:wN \exp_after:wN \exp_after:wN \use_ii:nn \fi: \fi: } \cs_new_protected_nopar:Npn \regex_build_new_state: { \tex_toks:D \l_regex_max_state_int { \s_stop } \int_set_eq:NN \l_regex_left_state_int \l_regex_right_state_int \int_set_eq:NN \l_regex_right_state_int \l_regex_max_state_int \int_incr:N \l_regex_max_state_int } \cs_new_protected:Npn \regex_build_transition:NN #1#2 { \regex_build_new_state: \regex_toks_put_right:Nx \l_regex_left_state_int { #1 { \int_eval:n { #2 - \l_regex_left_state_int } } } } \cs_new_protected:Npn \regex_build_transitions:NNNN #1#2#3#4 { \regex_build_new_state: \regex_toks_put_right:Nx \l_regex_left_state_int { #1 { \int_eval:n { #2 - \l_regex_left_state_int } } #3 { \int_eval:n { #4 - \l_regex_left_state_int } } } } \cs_new_protected_nopar:Npn \regex_build:w { \int_set_eq:NN \l_regex_catcodes_default_int \c_regex_catcodes_all_int \int_set_eq:NN \l_regex_catcodes_int \l_regex_catcodes_default_int \int_set_eq:NN \l_regex_capturing_group_int \c_zero \seq_clear:N \l_regex_capturing_group_seq \tl_clear:N \l_regex_tests_tl \bool_set_true:N \l_regex_tests_bool \int_zero:N \l_regex_max_state_int \regex_build_new_state: } \cs_new_protected_nopar:Npn \regex_build_end: { \regex_build_exit_class: \regex_build_exit_groups: \regex_toks_put_right:Nx \l_regex_right_state_int { \regex_action_success: } \int_incr:N \l_regex_capturing_group_int } \cs_new_protected_nopar:Npn \regex_build_exit_class: { \regex_build_if_in_class:TF { \msg_kernel_error:nn { regex } { missing-rbrack } \use:c { regex_build_]: } } { } } \cs_new_protected_nopar:Npn \regex_build_exit_groups: { \seq_if_empty:NF \l_regex_capturing_group_seq { \msg_kernel_error:nnx { regex } { missing-rparen } { \seq_length:N \l_regex_capturing_group_seq } \prg_replicate:nn { \seq_length:N \l_regex_capturing_group_seq } { \regex_build_close_aux: \regex_build_group_: } } } \cs_new_protected:Npn \regex_build:n #1 { \regex_build:w \int_set_eq:NN \l_regex_build_mode_int \c_zero \regex_build_new_state: \regex_toks_put_right:Nx \l_regex_left_state_int { \regex_action_start_wildcard: } \regex_build_open_aux: \regex_escape_use:nnnn { \regex_char_if_special:NTF ##1 \regex_build_special:N \regex_build_raw:N ##1 } { \regex_char_if_alphanumeric:NTF ##1 \regex_build_escaped:N \regex_build_raw:N ##1 } { \regex_build_raw:N ##1 } { #1 } \prg_do_nothing: \prg_do_nothing: \prg_do_nothing: \prg_do_nothing: \int_compare:nNnT \l_regex_build_mode_int < \c_zero { \msg_kernel_error:nn { regex } { c-missing-rbrace } \exp_after:wN \regex_build_special:N \c_rbrace_str } \seq_put_right:Nn \l_regex_capturing_group_seq {0} \regex_build_close_aux: \regex_build_group_: \regex_build_end: } \cs_new_protected:Npn \regex_build_special:N #1 { \cs_if_exist_use:cF { regex_build_#1: } { \regex_build_raw:N #1 } } \cs_new_protected:Npn \regex_build_escaped:N #1 { \cs_if_exist_use:cF { regex_build_/#1: } { \regex_build_raw:N #1 } } \cs_new_protected:Npn \regex_build_one:n #1 { \regex_build_one:x { \exp_not:n {#1} } } \cs_new_protected:Npn \regex_build_one:x #1 { \tl_put_right:Nx \l_regex_tests_tl { \if_num:w \l_regex_catcodes_int < \c_regex_catcodes_all_int \regex_item_catcode:nT { \int_use:N \l_regex_catcodes_int } \else: \exp_after:wN \use:n \fi: {#1} } \int_set_eq:NN \l_regex_catcodes_int \l_regex_catcodes_default_int \if_num:w \l_regex_build_mode_int = \c_two \l_regex_build_mode_int = \c_zero \else: \if_num:w \l_regex_build_mode_int = \c_six \l_regex_build_mode_int = \c_three \fi: \fi: \if_int_odd:w \l_regex_build_mode_int \else: \exp_after:wN \regex_build_one_quantifier: \fi: } \cs_new:Npn \regex_tests_action_cost:n #1 { \exp_not:o \l_regex_tests_tl \bool_if:NTF \l_regex_tests_bool { \regex_break_point:TF { \regex_action_cost:n {#1} } { } } { \regex_break_point:TF { } { \regex_action_cost:n {#1} } } } \cs_new_protected:Npn \regex_build_raw_error:N #1 { \if_int_odd:w \l_regex_build_mode_int \msg_kernel_error:nnx { regex } { class-bad-escape } {#1} \else: \msg_kernel_error:nnx { regex } { catcode-bad-escape } {#1} \fi: \regex_build_raw:N #1 } \cs_new_protected:Npn \regex_build_raw:N #1#2#3 { \regex_build_if_in_class:TF { \str_if_eq:nnTF {#2#3} { \regex_build_special:N - } } { \use_ii:nn } { \regex_class_range:Nw #1 } { \regex_build_one:x { \regex_item_equal:n { \int_value:w `#1 ~ } } #2 #3 } } \cs_new_protected:Npn \regex_class_range:Nw #1#2#3 { \token_if_eq_meaning:NNTF #2 \regex_build_escaped:N % [ { \use_i:nn } { \str_if_eq:nnTF { #2#3 } { \regex_build_special:N ] } } { \msg_kernel_warning:nnxx { regex } { range-missing-end } % [ {#1} { \token_if_eq_charcode:NNF #3 ] { \c_backslash_str } #3 } \tl_put_right:Nx \l_regex_tests_tl { \regex_item_equal:n { \int_value:w `#1 ~ } \regex_item_equal:n { \int_value:w `- ~ } } #2#3 } { \if_num:w `#1 > `#3 \exp_stop_f: \msg_kernel_error:nnxx { regex } { range-backwards } {#1} {#3} \else: \tl_put_right:Nx \l_regex_tests_tl { \if_num:w `#1 = `#3 \exp_stop_f: \regex_item_equal:n \else: \regex_item_range:nn { \int_value:w `#1 ~ } \fi: { \int_value:w `#3 ~ } } \fi: } } \cs_new_protected_nopar:cpx { regex_build_.: } { \exp_not:N \regex_build_if_in_class:TF { \regex_build_raw:N . } { \regex_build_one:n \exp_not:c { c_regex_._tl } } } \tl_map_inline:nn { dDhHsSvVwWN } { \cs_new_protected_nopar:cpx { regex_build_/#1: } { \regex_build_one:n \exp_not:c { c_regex_#1_tl } } } \cs_new_protected:Npn \regex_build_simple_assertion:nn #1#2 { \regex_build_if_assertions_forbidden:TF {#1} { \regex_build_new_state: \regex_toks_put_right:Nx \l_regex_left_state_int { \exp_not:n {#2} { \regex_action_free:n { \int_eval:n { \l_regex_right_state_int - \l_regex_left_state_int } } } } %^^A todo: add \regex_assertion_quantifier: } } \cs_new_protected_nopar:cpn { regex_build_^: } { \regex_build_simple_assertion:nn { \regex_build_raw:N ^ } { \int_compare:nNnT \l_regex_min_index_int = \l_regex_current_index_int } } \cs_new_protected_nopar:cpn { regex_build_/A: } { \regex_build_simple_assertion:nn { \regex_build_raw_error:N A } { \int_compare:nNnT \l_regex_min_index_int = \l_regex_current_index_int } } \cs_new_protected_nopar:cpn { regex_build_/G: } { \regex_build_simple_assertion:nn { \regex_build_raw_error:N G } { \int_compare:nNnT \l_regex_start_index_int = \l_regex_current_index_int } } \group_begin: \char_set_catcode_other:N \$ \cs_new_protected_nopar:cpn { regex_build_$: } % $ { \regex_build_simple_assertion:nn { \regex_build_raw:N $ } % $ { \int_compare:nNnT \l_regex_current_char_int < \c_minus_one } } \group_end: \cs_new_protected_nopar:cpn { regex_build_/Z: } { \regex_build_simple_assertion:nn { \regex_build_raw_error:N Z } { \int_compare:nNnT \l_regex_current_char_int < \c_minus_one } } \cs_new_protected_nopar:cpn { regex_build_/z: } { \regex_build_simple_assertion:nn { \regex_build_raw_error:N z } { \int_compare:nNnT \l_regex_current_char_int < \c_minus_one } } \cs_new_protected_nopar:cpn { regex_build_/b: } { \regex_build_simple_assertion:nn { \regex_build_raw_error:N b } { \regex_if_word_boundary:T } } \cs_new_protected_nopar:cpn { regex_build_/B: } { \regex_build_simple_assertion:nn { \regex_build_raw_error:N B } { \regex_if_word_boundary:TF { } } } \cs_new_protected_nopar:Npn \regex_if_word_boundary:TF { \group_begin: \int_set_eq:NN \l_regex_current_char_int \l_regex_last_char_int \c_regex_w_tl \regex_break_point:TF { \group_end: \c_regex_W_tl \regex_item_equal:n { -2 } } { \group_end: \c_regex_w_tl } \regex_break_point:TF } \cs_new_protected_nopar:Npn \regex_if_word_boundary:T { \regex_if_word_boundary:TF \use:n \use_none:n } \cs_new_protected_nopar:cpn { regex_build_[: } { \regex_build_if_in_class:TF { \regex_build_raw:N [ } { \regex_class_first:NNNN } } \cs_new_protected:cpn { regex_build_]: } { \regex_build_if_in_class:TF { \if_num:w \l_regex_build_mode_int > \c_sixteen \tl_set:Nx \l_regex_tests_tl { \exp_not:o \l_regex_tests_saved_tl \if_num:w \l_regex_catcodes_saved_int < \c_regex_catcodes_all_int \regex_item_catcode:nT { \int_use:N \l_regex_catcodes_saved_int } \else: \exp_after:wN \use:n \fi: { \exp_not:o \l_regex_tests_tl \bool_if:NF \l_regex_tests_bool { \regex_break_point:TF { } \regex_break_true:w } } } \bool_set_eq:NN \l_regex_tests_bool \l_regex_tests_saved_bool \fi: \tex_advance:D \l_regex_build_mode_int - \c_fifteen \tex_divide:D \l_regex_build_mode_int \c_thirteen \if_int_odd:w \l_regex_build_mode_int \else: \exp_after:wN \regex_build_one_quantifier: \fi: } { \regex_build_raw:N ] } } \cs_new_protected:Npn \regex_class_first:NNNN #1#2#3#4 { \l_regex_build_mode_int = \int_value:w \l_regex_build_mode_int 3 ~ % \if_num:w \l_regex_build_mode_int > \c_sixteen \tl_set_eq:NN \l_regex_tests_saved_tl \l_regex_tests_tl \bool_set_eq:NN \l_regex_tests_saved_bool \l_regex_tests_bool \int_set_eq:NN \l_regex_catcodes_saved_int \l_regex_catcodes_int \int_set_eq:NN \l_regex_catcodes_int \c_regex_catcodes_all_int \fi: \token_if_eq_meaning:NNTF #1 \regex_build_special:N { \token_if_eq_charcode:NNTF #2 ^ { \bool_set_false:N \l_regex_tests_bool % [ \str_if_eq:nnTF {#3#4} { \regex_build_special:N ] } { \regex_build_raw:N } } { % [ \token_if_eq_charcode:NNTF #2 ] { \regex_build_raw:N #2 } { #1 #2 } } } { #1 #2 } #3 #4 } \cs_new_protected:cpn { regex_build_/c: } { \if_case:w \l_regex_build_mode_int \exp_after:wN \regex_build_c_aux:wNN \or: \or: \or: \exp_after:wN \regex_build_c_aux:wNN \fi: \msg_kernel_error:nn { regex } { c-bad-mode } \s_stop } \cs_new_protected:Npn \regex_build_c_aux:wNN #1 \s_stop #2#3 { \token_if_eq_meaning:NNTF #2 \regex_build_raw:N { \cs_if_exist:cTF { c_regex_catcode_#3_int } { \int_set_eq:Nc \l_regex_catcodes_int { c_regex_catcode_#3_int } \l_regex_build_mode_int = \if_case:w \l_regex_build_mode_int \c_two \else: \c_six \fi: } } { \cs_if_exist_use:cF { regex_build_c_#3: } } { \msg_kernel_error:nnx { regex } { c-missing-category } {#3} #2 #3 } } \cs_new_protected:cpn { regex_build_c_ \c_lbrace_str : } { \group_begin: \l_regex_build_mode_int = - \if_case:w \l_regex_build_mode_int \c_two \else: \c_six \fi: \regex_build:w } \cs_new_protected:cpn { regex_build_c_[: } #1#2 { \int_zero:N \l_regex_catcodes_int \str_if_eq:nnTF { #1 #2 } { \regex_build_special:N ^ } { \bool_set_false:N \l_regex_catcodes_bool \regex_build_c_lbrack_loop:NN } { \bool_set_true:N \l_regex_catcodes_bool \regex_build_c_lbrack_loop:NN #1#2 } } \cs_new_protected:Npn \regex_build_c_lbrack_loop:NN #1#2 { \token_if_eq_meaning:NNTF #1 \regex_build_raw:N { \cs_if_exist:cTF { c_regex_catcode_#2_int } { \exp_args:Nc \regex_build_c_lbrack_add:N { c_regex_catcode_#2_int } \regex_build_c_lbrack_loop:NN } } { % [ \token_if_eq_charcode:NNTF #2 ] { \regex_build_c_lbrack_end: } } { \msg_kernel_error:nnx { regex } { c-missing-rbrack } {#2} \regex_build_c_lbrack_end: } } \cs_new_protected_nopar:Npn \regex_build_c_lbrack_end: { \l_regex_build_mode_int = \if_case:w \l_regex_build_mode_int \c_two \else: \c_six \fi: \if_meaning:w \c_false_bool \l_regex_catcodes_bool \int_set:Nn \l_regex_catcodes_int { \c_regex_catcodes_all_int - \l_regex_catcodes_int } \fi: } \cs_new_protected:Npn \regex_build_c_lbrack_add:N #1 { \if_int_odd:w \int_eval:w \l_regex_catcodes_int / #1 \int_eval_end: \else: \tex_advance:D \l_regex_catcodes_int #1 \fi: } \cs_new_protected:cpn { regex_build_ \c_rbrace_str : } { \int_compare:nNnTF \l_regex_build_mode_int < \c_zero { \regex_build_exit_class: \regex_build_exit_groups: \regex_build_escaped:N Z \regex_build_end: \use:x { \group_end: \regex_build_one:n { \regex_item_cs:n { \regex_set_aux:N \l_regex_internal_regex } } } } { \exp_after:wN \regex_build_raw:N \c_rbrace_str } } \cs_new_protected:Npn \regex_build_quantifier:w #1#2 { \token_if_eq_meaning:NNTF #1 \regex_build_special:N { \cs_if_exist_use:cF { regex_build_quantifier_#2:w } { \regex_build_quantifier_end:nn { } { } #1 #2 } } { \regex_build_quantifier_end:nn { } { } #1 #2 } } \cs_new_protected_nopar:cpn { regex_build_quantifier_?:w } { \regex_build_quantifier_aux:nnNN { } { ? } } \cs_new_protected_nopar:cpn { regex_build_quantifier_*:w } { \regex_build_quantifier_aux:nnNN { } { * } } \cs_new_protected_nopar:cpn { regex_build_quantifier_+:w } { \regex_build_quantifier_aux:nnNN { } { + } } \cs_new_protected:Npn \regex_build_quantifier_aux:nnNN #1#2#3#4 { \str_if_eq:nnTF { #3 #4 } { \regex_build_special:N ? } { \regex_build_quantifier_end:nn { #2 #4 } {#1} } { \regex_build_quantifier_end:nn { #2 } {#1} #3 #4 } } \cs_new_protected_nopar:cpn { regex_build_quantifier_ \c_lbrace_str :w } { \regex_get_digits:nw { \regex_build_quantifier_lbrace:n } } \cs_new_protected:Npn \regex_build_quantifier_lbrace:n #1 { \tl_if_empty:nTF {#1} { \regex_build_quantifier_end:nn { } { } \exp_after:wN \regex_build_raw:N \c_lbrace_str } { \regex_build_quantifier_lbrace:nw {#1} } } \cs_new_protected:Npx \regex_build_quantifier_lbrace:nw #1#2#3 { \exp_not:N \prg_case_str:nnn { #2 #3 } { { \exp_not:N \regex_build_special:N , } { \exp_not:N \regex_get_digits:nw { \exp_not:N \regex_build_quantifier_lbrace:nnw {#1} } } { \exp_not:N \regex_build_special:N \c_rbrace_str } { \exp_not:N \regex_build_quantifier_end:nn {n} { {#1} } } } { \exp_not:N \regex_build_quantifier_end:nn { } { } \exp_not:N \regex_build_raw:N \c_lbrace_str #1#2 } } \cs_new_protected:Npn \regex_build_quantifier_lbrace:nnw #1#2#3#4 { \str_if_eq:xxTF { \exp_not:n {#3#4} } { \exp_not:N \regex_build_special:N \c_rbrace_str } { \tl_if_empty:nTF {#2} { \regex_build_quantifier_aux:nnNN { {#1} } { n* } } { \regex_build_quantifier_aux:nnNN { {#1} {#2} } { nn } } } { \regex_build_quantifier_end:nn { } { } \use:x { \exp_args:No \tl_map_function:nN { \c_lbrace_str #1 , #2 } \regex_build_raw:N } #3 #4 } } \cs_new_protected:Npn \regex_build_quantifier_end:nn #1#2 { \use:c { regex_build_ \l_regex_one_or_group_tl _ #1 : } #2 \tl_clear:N \l_regex_tests_tl \bool_set_true:N \l_regex_tests_bool } \cs_new_protected_nopar:Npn \regex_build_one_quantifier: { \tl_set:Nx \l_regex_one_or_group_tl { one } \regex_build_quantifier:w } \cs_new_protected:Npn \regex_build_one_n: #1 { \prg_replicate:nn {#1} { \regex_build_transition:NN \regex_tests_action_cost:n \l_regex_right_state_int } } \cs_new_eq:cN { regex_build_one_n?: } \regex_build_one_n: \cs_new_protected_nopar:Npn \regex_build_one_: { \regex_build_one_n: \c_one } \cs_new_protected:cpn { regex_build_one_n*: } #1 { \int_compare:nNnTF {#1} = \c_zero { \regex_build_transitions:NNNN \regex_tests_action_cost:n \l_regex_left_state_int \regex_action_free:n \l_regex_right_state_int } { \regex_build_one_n: {#1} \int_set_eq:NN \l_regex_internal_a_int \l_regex_left_state_int \regex_build_transitions:NNNN \regex_action_free:n \l_regex_internal_a_int \regex_action_free:n \l_regex_right_state_int } } \cs_new_protected:cpn { regex_build_one_n*?: } #1 { \int_compare:nNnTF {#1} = \c_zero { \regex_build_transitions:NNNN \regex_action_free:n \l_regex_right_state_int \regex_tests_action_cost:n \l_regex_left_state_int } { \regex_build_one_n: {#1} \int_set_eq:NN \l_regex_internal_a_int \l_regex_left_state_int \regex_build_transitions:NNNN \regex_action_free:n \l_regex_right_state_int \regex_action_free:n \l_regex_internal_a_int } } \cs_new_protected_nopar:cpx { regex_build_one_*: } { \exp_not:c { regex_build_one_n*: } \c_zero } \cs_new_protected_nopar:cpx { regex_build_one_*?: } { \exp_not:c { regex_build_one_n*?: } \c_zero } \cs_new_protected_nopar:cpx { regex_build_one_+: } { \exp_not:c { regex_build_one_n*: } \c_one } \cs_new_protected_nopar:cpx { regex_build_one_+?: } { \exp_not:c { regex_build_one_n*?: } \c_one } \cs_new_protected_nopar:Npn \regex_build_one_nn: { \regex_build_one_nn_aux:nnnn { } { \regex_build_transitions:NNNN \regex_tests_action_cost:n \l_regex_right_state_int \regex_action_free:n \l_regex_internal_a_int } } \cs_new_protected_nopar:cpn { regex_build_one_nn?: } { \regex_build_one_nn_aux:nnnn {?} { \regex_build_transitions:NNNN \regex_action_free:n \l_regex_internal_a_int \regex_tests_action_cost:n \l_regex_right_state_int } } \cs_new_protected:Npn \regex_build_one_nn_aux:nnnn #1#2#3#4 { \regex_build_one_n: {#3} \int_compare:nNnTF {#3} > {#4} { \msg_kernel_error:nnxxx { regex } { quantifier-backwards } {#3} {#4} {#1} } { \int_set:Nn \l_regex_internal_a_int { \l_regex_right_state_int + #4 - #3 } \prg_replicate:nn { #4 - #3 } { #2 } } } \cs_new_protected_nopar:cpn { regex_build_one_?: } { \regex_build_one_nn: \c_zero \c_one } \cs_new_protected_nopar:cpx { regex_build_one_??: } { \exp_not:c { regex_build_one_nn?: } \c_zero \c_one } \cs_new_protected:cpn { regex_build_(: } #1#2 { \regex_build_if_in_class:TF { \regex_build_raw:N ( #1 #2 } { \str_if_eq:nnTF { #1 #2 } { \regex_build_special:N ? } { \regex_build_special_group:NN } { \int_incr:N \l_regex_capturing_group_int \regex_seq_push_int:NN \l_regex_capturing_group_seq \l_regex_capturing_group_int \regex_build_open_aux: #1 #2 } } } \cs_new_protected_nopar:Npn \regex_build_open_aux: { \regex_build_new_state: \regex_seq_push_int:NN \l_regex_left_state_seq \l_regex_left_state_int \regex_seq_push_int:NN \l_regex_right_state_seq \l_regex_right_state_int \bool_if:NTF \l_regex_caseless_bool { \seq_push:Nn \l_regex_end_group_seq \regex_build_caseless: } { \seq_push:Nn \l_regex_end_group_seq \regex_build_caseful: } \seq_push:Nn \l_regex_end_alternation_seq { } \regex_build_begin_alternation: } \cs_new_protected_nopar:cpn { regex_build_|: } { \regex_build_if_in_class:TF { \regex_build_raw:N | } { \regex_build_end_alternation: \regex_build_begin_alternation: } } \cs_new_protected_nopar:cpn { regex_build_): } { \regex_build_if_in_class:TF { \regex_build_raw:N ) } { \seq_if_empty:NTF \l_regex_capturing_group_seq { \msg_kernel_error:nn { regex } { extra-rparen } } { \regex_build_close_aux: \regex_build_group_quantifier: } } } \cs_new_protected_nopar:Npn \regex_build_close_aux: { \regex_build_end_alternation: \regex_seq_pop_int:NN \l_regex_left_state_seq \l_regex_left_state_int \regex_seq_pop_int:NN \l_regex_right_state_seq \l_regex_right_state_int \regex_seq_pop_use:N \l_regex_end_group_seq \seq_pop:NN \l_regex_end_alternation_seq \l_regex_internal_a_tl } \cs_new_protected_nopar:Npn \regex_build_begin_alternation: { \regex_build_new_state: \regex_seq_get_int:NN \l_regex_left_state_seq \l_regex_left_state_int \regex_toks_put_right:Nx \l_regex_left_state_int { \regex_action_free:n { \int_eval:n { \l_regex_right_state_int - \l_regex_left_state_int } } } } \cs_new_protected_nopar:Npn \regex_build_end_alternation: { \int_set_eq:NN \l_regex_left_state_int \l_regex_right_state_int \regex_seq_get_int:NN \l_regex_right_state_seq \l_regex_right_state_int \regex_toks_put_right:Nx \l_regex_left_state_int { \regex_action_free:n { \int_eval:n { \l_regex_right_state_int - \l_regex_left_state_int } } } \regex_seq_get_use:N \l_regex_end_alternation_seq } \cs_new_protected:Npn \regex_build_special_group:NN #1#2 { \cs_if_exist_use:cF { regex_build_special_group_\token_to_str:N #2 : } { \msg_kernel_error:nnx { regex } { special-group-unknown } { (? \token_to_str:N #2 } %) \regex_build_special:N ( % ) \regex_build_raw:N ? #1 #2 } } \cs_new_protected_nopar:cpn { regex_build_special_group_:: } { \regex_seq_push_int:NN \l_regex_capturing_group_seq \c_minus_one \regex_build_open_aux: } \cs_new_protected_nopar:cpn { regex_build_special_group_|: } { \regex_seq_push_int:NN \l_regex_capturing_group_seq \c_minus_one \regex_build_new_state: \regex_seq_push_int:NN \l_regex_left_state_seq \l_regex_left_state_int \regex_seq_push_int:NN \l_regex_right_state_seq \l_regex_right_state_int \seq_push:Nx \l_regex_end_alternation_seq { \exp_not:N \int_compare:nNnT \l_regex_capturing_group_int > \l_regex_capturing_group_max_int { \int_set_eq:NN \l_regex_capturing_group_max_int \l_regex_capturing_group_int } \int_set:Nn \l_regex_capturing_group_int { \int_use:N \l_regex_capturing_group_int } } \seq_push:Nx \l_regex_end_group_seq { \bool_if:NTF \l_regex_caseless_bool \regex_build_caseless: \regex_build_caseful: \int_set_eq:NN \l_regex_capturing_group_int \l_regex_capturing_group_max_int } \regex_build_begin_alternation: } \cs_new_protected_nopar:Npn \regex_build_special_group_i: { \regex_build_options:NNN + \regex_build_raw:N i } \cs_new_protected_nopar:cpn { regex_build_special_group_-: } { \regex_build_options:NNN - } \cs_new_protected:Npn \regex_build_options:NNN #1#2#3 { \token_if_eq_meaning:NNTF \regex_build_raw:N #2 { \cs_if_exist_use:cF { regex_build_option_#1#3: } { \msg_kernel_error:nnx { regex } { unknown-option } { #3 } } \regex_build_options:NNN #1 } { \prg_case_str:nnn { #3 } { % ( { ) } { } { - } { \regex_build_options:NNN - } } { \msg_kernel_error:nnx { regex } { invalid-in-option } { #3 } } } } \cs_new_protected_nopar:cpn { regex_build_option_+i: } { \regex_build_caseless: \cs_set_eq:NN \regex_match_loop_case_hook: \regex_match_loop_caseless_hook: } \cs_new_protected_nopar:cpn { regex_build_option_-i: } { \regex_build_caseful: } \cs_new_protected_nopar:Npn \regex_build_group_quantifier: { \tl_set:Nn \l_regex_one_or_group_tl { group } \regex_build_quantifier:w } \cs_new_protected:Npn \regex_build_group_submatches:NN #1#2 { \seq_pop:NN \l_regex_capturing_group_seq \l_regex_internal_a_tl \int_compare:nNnF { \l_regex_internal_a_tl } < \c_zero { \regex_toks_put_left:Nx #1 { \regex_action_submatch:n { \l_regex_internal_a_tl < } } \regex_toks_put_left:Nx #2 { \regex_action_submatch:n { \l_regex_internal_a_tl > } } } } \cs_new_protected_nopar:Npn \regex_build_group_qs_aux: { \int_set_eq:NN \l_regex_internal_a_int \l_regex_left_state_int \regex_build_new_state: \tex_toks:D \l_regex_right_state_int = \tex_toks:D \l_regex_internal_a_int \regex_toks_put_left:Nx \l_regex_right_state_int { \int_sub:Nn \l_regex_current_state_int { \int_eval:n % ^^A here we lie! { \l_regex_right_state_int - \l_regex_internal_a_int } } } \use:x { \tex_toks:D \l_regex_internal_a_int { \s_stop \regex_action_free:n { \int_eval:n { \l_regex_right_state_int - \l_regex_internal_a_int } } } } \regex_build_group_submatches:NN \l_regex_right_state_int \l_regex_left_state_int } \cs_new_protected:Npn \regex_build_group_qs_aux:NN #1#2 { \regex_build_group_qs_aux: \int_set_eq:NN \l_regex_right_state_int \l_regex_left_state_int \regex_build_transition:NN \regex_action_free:n #1 #2 \l_regex_internal_a_int { \regex_action_free:n { \int_eval:n { \l_regex_right_state_int - \l_regex_internal_a_int } } } } \cs_new_protected_nopar:cpn { regex_build_group_?: } { \regex_build_group_qs_aux:NN \l_regex_right_state_int \regex_toks_put_right:Nx } \cs_new_protected_nopar:cpn { regex_build_group_??: } { \regex_build_group_qs_aux:NN \l_regex_right_state_int \regex_toks_put_left:Nx } \cs_new_protected:Npn \regex_build_group_transition_right_max: { \regex_toks_put_right:Nx \l_regex_right_state_int { \regex_action_free:n { \int_eval:n { \l_regex_max_state_int - \l_regex_right_state_int } } } } \cs_new_protected:Npn \regex_build_group_n_aux:n #1 { \int_set_eq:NN \l_regex_internal_a_int \l_regex_left_state_int \int_set_eq:NN \l_regex_internal_b_int \l_regex_max_state_int \int_add:Nn \l_regex_right_state_int { ( #1 - 1 ) * ( \l_regex_max_state_int - \l_regex_left_state_int ) } \int_set:Nn \l_regex_max_state_int { \l_regex_left_state_int + (#1) * ( \l_regex_max_state_int - \l_regex_left_state_int ) } \int_while_do:nNnn \l_regex_internal_b_int < \l_regex_max_state_int { \tex_toks:D \l_regex_internal_b_int = \tex_toks:D \l_regex_internal_a_int \int_incr:N \l_regex_internal_a_int \int_incr:N \l_regex_internal_b_int } } \cs_new_protected:Npn \regex_build_group_n: #1 { \regex_build_group_transition_right_max: \regex_build_group_n_aux:n {#1} \regex_build_new_state: \int_compare:nNnF {#1} = \c_zero { \regex_build_group_submatches:NN \l_regex_internal_a_int \l_regex_left_state_int } } \cs_new_eq:cN { regex_build_group_n?: } \regex_build_group_n: \cs_new_protected_nopar:Npn \regex_build_group_: { \regex_build_group_n: \c_one } \cs_new_protected_nopar:cpn { regex_build_group_n*: } { \regex_build_group_n_star_aux:NNn \regex_toks_put_right:Nx \regex_toks_put_left:Nx } \cs_new_protected_nopar:cpn { regex_build_group_n*?: } { \regex_build_group_n_star_aux:NNn \regex_toks_put_left:Nx \regex_toks_put_right:Nx } \cs_new_protected:Npn \regex_build_group_n_star_aux:NNn #1#2#3 { \int_compare:nNnTF {#3} = \c_zero { \regex_build_group_qs_aux:NN \l_regex_internal_a_int #1 } { \regex_build_group_transition_right_max: \regex_build_group_n_aux:n {#3} \regex_build_new_state: #2 \l_regex_left_state_int { \regex_action_free:n { \int_eval:n { \l_regex_internal_a_int - \l_regex_left_state_int } } } \regex_build_group_submatches:NN \l_regex_internal_a_int \l_regex_left_state_int } } \cs_new_protected_nopar:cpx { regex_build_group_*: } { \exp_not:c { regex_build_group_n*: } \c_zero } \cs_new_protected_nopar:cpx { regex_build_group_*?: } { \exp_not:c { regex_build_group_n*?: } \c_zero } \cs_new_protected_nopar:cpx { regex_build_group_+: } { \exp_not:c { regex_build_group_n*: } \c_one } \cs_new_protected_nopar:cpx { regex_build_group_+?: } { \exp_not:c { regex_build_group_n*?: } \c_one } \cs_new_protected_nopar:Npn \regex_build_group_nn: { \regex_build_group_nn_aux:nnnn { } \regex_build_group_transition_right_max: } \cs_new_protected_nopar:cpn { regex_build_group_nn?: } { \regex_build_group_nn_aux:nnnn { } { \use:x { \tex_toks:D \l_regex_right_state_int { \exp_after:wN \regex_build_group_nn_aux_ii:w \tex_the:D \tex_toks:D \l_regex_right_state_int } } } } \cs_new_protected:Npn \regex_build_group_nn_aux:nnnn #1#2#3#4 { \int_compare:nNnTF {#3} > {#4} { \msg_kernel_error:nnxxx { regex } { quantifier-backwards } {#3} {#4} {#1} } { \int_compare:nNnTF {#3} = \c_zero { \regex_build_group_qs_aux: \int_set_eq:NN \l_regex_right_state_int \l_regex_left_state_int \int_set_eq:NN \l_regex_left_state_int \l_regex_internal_a_int \regex_build_group_transition_right_max: \regex_build_group_n_aux:n { #4 - #3 } \int_set_eq:NN \l_regex_internal_c_int \l_regex_right_state_int \int_set_eq:NN \l_regex_right_state_int \l_regex_left_state_int \prg_replicate:nn { #4 - #3 } { #2 \int_add:Nn \l_regex_right_state_int { \l_regex_internal_b_int - \l_regex_internal_a_int } } \int_set_eq:NN \l_regex_right_state_int \l_regex_internal_c_int \int_set_eq:NN \l_regex_left_state_int \l_regex_internal_a_int \regex_build_new_state: } { \regex_build_group_transition_right_max: \regex_build_group_n_aux:n {#3} \int_set_eq:NN \l_regex_left_state_int \l_regex_internal_a_int \regex_build_group_submatches:NN \l_regex_left_state_int \l_regex_right_state_int \regex_build_group_n_aux:n { #4 - #3 + \c_one } \int_sub:Nn \l_regex_right_state_int { \l_regex_internal_a_int - \l_regex_left_state_int } \prg_replicate:nn { #4 - #3 } { #2 \int_add:Nn \l_regex_right_state_int { \l_regex_internal_b_int - \l_regex_internal_a_int } } \int_set_eq:NN \l_regex_left_state_int \l_regex_internal_a_int \regex_build_new_state: } } } \cs_new_protected:Npn \regex_build_group_nn_aux_ii:w #1 \regex_action_free:n { #1 \regex_action_free:n { \int_eval:n { \l_regex_max_state_int - \l_regex_right_state_int } } \regex_action_free:n } \cs_new_protected:cpn { regex_build_/u: } #1#2 { \regex_build_if_assertions_forbidden:TF { \regex_build_raw_error:N u #1#2 } { \str_if_eq:xxTF {#1#2} { \regex_build_special:N \c_lbrace_str } { \tl_set:Nx \l_regex_internal_a_tl { \if_false: } \fi: \regex_build_u_loop:NN } { \msg_kernel_error:nn { regex } { u-missing-lbrace } #1#2 } } } \cs_new:Npn \regex_build_u_loop:NN #1#2 { \token_if_eq_meaning:NNTF #1 \regex_build_raw:N { #2 \regex_build_u_loop:NN } { \token_if_eq_meaning:NNTF #1 \regex_build_special:N { \exp_after:wN \token_if_eq_charcode:NNTF \c_rbrace_str #2 { \if_false: { \fi: } \regex_build_u_end: } { #2 \regex_build_u_loop:NN } } { \if_false: { \fi: } \msg_kernel_error:nnx { regex } { u-missing-rbrace } {#2} \regex_build_u_end: #1#2 } } } \cs_new_protected:Npn \regex_build_u_end: { \tl_set:Nv \l_regex_internal_a_tl \l_regex_internal_a_tl \if_num:w \l_regex_build_mode_int = \c_zero \regex_build_u_not_cs: \else: \regex_build_u_in_cs: \fi: \tl_clear:N \l_regex_tests_tl } \cs_new_protected:Npn \regex_build_u_in_cs: { \exp_args:NNo \str_gset_other:Nn \g_regex_internal_tl { \l_regex_internal_a_tl } \tl_map_inline:Nn \g_regex_internal_tl { \tl_set:Nx \l_regex_tests_tl { \regex_item_equal:n { `##1 } } \regex_build_one_: } } \cs_new_protected:Npn \regex_build_u_not_cs: { \exp_args:No \tl_analysis_map_inline:nn { \l_regex_internal_a_tl } { \tl_set:Nx \l_regex_tests_tl { \exp_not:N \int_compare:nNnT \l_regex_current_catcode_int = { \int_value:w "##2 } { \int_compare:nNnTF { "##2 } = \c_zero { \exp_not:n { \str_if_eq:xxT { \l_regex_current_token_tl } {##1} } { \regex_break_true:w } } { \regex_item_equal:n {##3} } } } \regex_build_one_: } } \cs_new_protected:Npn \regex_store_state:n #1 { \int_incr:N \l_regex_max_active_int \tex_skip:D \l_regex_max_active_int #1 sp \scan_stop: \regex_store_submatches:n {#1} } \cs_new_protected_nopar:Npn \regex_state_use_with_submatches: { \regex_state_use_aux:n { } } \cs_new_protected_nopar:Npn \regex_state_use: { \regex_state_use_aux:n { \exp_after:wN \use_none_delimit_by_s_stop:w } } \cs_new_protected:Npn \regex_state_use_aux:n #1 { \if_num:w \tex_dimen:D \l_regex_current_state_int < \l_regex_step_int \tex_dimen:D \l_regex_current_state_int = \l_regex_step_int sp \scan_stop: #1 \tex_the:D \tex_toks:D \exp_after:wN \l_regex_current_state_int \fi: \scan_stop: } \cs_new_protected_nopar:Npn \regex_disable_submatches: { \cs_set_eq:NN \regex_state_use_with_submatches: \regex_state_use: \cs_set_eq:NN \regex_store_submatches:n \regex_protected_use_none:n \cs_set_eq:NN \regex_action_submatches:n \regex_protected_use_none:n } \cs_new_protected:Npn \regex_protected_use_none:n #1 { } \cs_new_protected:Npn \regex_store_submatches:n #1 { \tex_toks:D #1 \exp_after:wN { \tex_romannumeral:D \exp_after:wN \regex_store_submatches_aux:w \tex_the:D \tex_toks:D #1 } } \cs_new_protected:Npn \regex_store_submatches_aux:w #1 \s_stop { \regex_store_submatches_aux_ii:Nnnw #1 \regex_state_submatches:nn \c_minus_one \q_prop \s_stop } \cs_new_protected:Npn \regex_store_submatches_aux_ii:Nnnw \regex_state_submatches:nn #1 #2 #3 \s_stop { \exp_after:wN \c_zero \exp_after:wN \regex_state_submatches:nn \exp_after:wN { \int_value:w \int_eval:w \l_regex_step_int + \c_one \exp_after:wN } \exp_after:wN { \l_regex_current_submatches_prop } \regex_state_submatches:nn {#1} {#2} \s_stop } \cs_new_protected:Npn \regex_state_submatches:nn #1#2 { \if_num:w #1 = \l_regex_step_int \tl_set:Nn \l_regex_current_submatches_prop { #2 } \fi: } \cs_new_protected:Npn \regex_match:n #1 { \int_zero:N \l_regex_nesting_int \int_set_eq:NN \l_regex_current_index_int \l_regex_max_state_int \regex_query_set:nnn { } { -1 } { -2 } \int_set_eq:NN \l_regex_min_index_int \l_regex_current_index_int \tl_analysis_map_inline:nn {#1} { \regex_query_set:nnn {##1} {"##2} {##3} \if_case:w "##2 \exp_stop_f: \or: \int_incr:N \l_regex_nesting_int \or: \int_decr:N \l_regex_nesting_int \fi: } \int_set_eq:NN \l_regex_max_index_int \l_regex_current_index_int \regex_query_set:nnn { } { -1 } { -2 } \regex_match_initial_setup: \regex_match_once: } \cs_new_protected:Npn \regex_query_set:nnn #1#2#3 { \tex_muskip:D \l_regex_current_index_int = \etex_gluetomu:D #3 sp plus #2 sp minus \l_regex_nesting_int sp \scan_stop: \tex_toks:D \l_regex_current_index_int {#1} \int_incr:N \l_regex_current_index_int } \cs_new_protected_nopar:Npn \regex_query_get: { \tl_set:Nx \l_regex_current_token_tl { \tex_the:D \tex_toks:D \l_regex_current_index_int } \l_regex_current_char_int = \etex_mutoglue:D \tex_muskip:D \l_regex_current_index_int \l_regex_current_catcode_int = \etex_gluestretch:D \etex_mutoglue:D \tex_muskip:D \l_regex_current_index_int } \cs_new_protected_nopar:Npn \regex_match_once: { \regex_match_setup: \regex_query_get: \regex_match_loop: \prg_break_point:n { } \bool_if:NT \l_regex_success_match_bool { \bool_gset_true:N \g_regex_success_bool \l_regex_every_match_tl } } \cs_new_protected_nopar:Npn \regex_match_initial_setup: { \int_set_eq:NN \l_regex_step_int \c_minus_one \prg_stepwise_inline:nnnn \c_zero \c_one { \l_regex_max_state_int - \c_one } { \tex_dimen:D ##1 \l_regex_step_int sp } \int_set:Nn \l_regex_start_index_int { \l_regex_min_index_int - \c_one } \int_set_eq:NN \l_regex_current_index_int \l_regex_min_index_int \int_set_eq:NN \l_regex_success_index_int \l_regex_min_index_int \int_set_eq:NN \l_regex_submatch_int \l_regex_max_state_int \bool_set_false:N \l_regex_success_empty_bool \bool_gset_false:N \g_regex_success_bool } \cs_new_protected_nopar:Npn \regex_match_setup: { \prop_clear:N \l_regex_current_submatches_prop \bool_if:NTF \l_regex_success_empty_bool { \cs_set_eq:NN \regex_if_two_empty_matches:F \regex_if_match_empty:F } { \cs_set_eq:NN \regex_if_two_empty_matches:F \use:n } \int_set_eq:NN \l_regex_start_index_int \l_regex_success_index_int \int_set:Nn \l_regex_current_index_int { \l_regex_start_index_int - \c_one } \bool_set_false:N \l_regex_success_match_bool \int_zero:N \l_regex_max_active_int \regex_store_state:n {0} %^^A _state_int! } \cs_new_protected_nopar:Npn \regex_match_loop: { \int_incr:N \l_regex_current_index_int \int_incr:N \l_regex_step_int \bool_set_false:N \l_regex_fresh_thread_bool \int_set_eq:NN \l_regex_last_char_int \l_regex_current_char_int \regex_query_get: \regex_match_loop_case_hook: \use:x { \int_zero:N \l_regex_max_active_int \regex_match_one_active:w 1 ; \prg_break_point:n { } \exp_not:N \prg_break_point:n { } } \if_num:w \l_regex_current_char_int < \c_minus_one \exp_after:wN \prg_map_break: \fi: \if_num:w \l_regex_max_active_int = \c_zero \exp_after:wN \prg_map_break: \fi: \regex_match_loop: } \cs_new:Npn \regex_match_one_active:w #1; { \if_num:w #1 > \l_regex_max_active_int \exp_after:wN \prg_map_break: \fi: \regex_match_one_active_aux:n { \int_value:w \tex_skip:D #1 } \exp_after:wN \regex_match_one_active:w \int_use:N \int_eval:w #1 + \c_one ; } \cs_new_protected:Npn \regex_match_one_active_aux:n #1 { \int_set:Nn \l_regex_current_state_int {#1} \prop_clear:N \l_regex_current_submatches_prop \regex_state_use_with_submatches: } \cs_new_protected_nopar:Npn \regex_match_loop_case_hook: { } \cs_new_protected_nopar:Npn \regex_match_loop_caseless_hook: { \int_set_eq:NN \l_regex_case_changed_char_int \l_regex_current_char_int \if_num:w \l_regex_current_char_int < \c_ninety_one \if_num:w \l_regex_current_char_int < \c_sixty_five \else: \int_add:Nn \l_regex_case_changed_char_int { \c_thirty_two } \fi: \else: \if_num:w \l_regex_current_char_int < \c_one_hundred_twenty_three \if_num:w \l_regex_current_char_int < \c_ninety_seven \else: \int_sub:Nn \l_regex_case_changed_char_int { \c_thirty_two } \fi: \fi: \fi: } \cs_new_protected_nopar:Npn \regex_action_start_wildcard: { \bool_set_true:N \l_regex_fresh_thread_bool \regex_action_free:n {1} \bool_set_false:N \l_regex_fresh_thread_bool \regex_action_cost:n {0} } \cs_new_protected:Npn \regex_action_cost:n #1 { \exp_args:Nf \regex_store_state:n { \int_eval:n { \l_regex_current_state_int + #1 } } } \cs_new_protected_nopar:Npn \regex_action_success: { \regex_if_two_empty_matches:F { \bool_set_true:N \l_regex_success_match_bool \bool_set_eq:NN \l_regex_success_empty_bool \l_regex_fresh_thread_bool \int_set_eq:NN \l_regex_success_index_int \l_regex_current_index_int \prop_set_eq:NN \l_regex_success_submatches_prop \l_regex_current_submatches_prop \prg_map_break: } } \cs_new_protected:Npn \regex_action_free:n #1 { \use:x { \int_add:Nn \l_regex_current_state_int {#1} \regex_state_use: \int_set:Nn \l_regex_current_state_int { \int_use:N \l_regex_current_state_int } \tl_set:Nn \exp_not:N \l_regex_current_submatches_prop { \exp_not:o \l_regex_current_submatches_prop } } } \cs_new_protected:Npn \regex_action_submatch:n #1 { \prop_put:Nno \l_regex_current_submatches_prop {#1} { \int_use:N \l_regex_current_index_int } } \cs_new:Npn \regex_if_match_empty:T { \int_compare:nNnT \l_regex_start_index_int = \l_regex_current_index_int } \cs_new:Npn \regex_if_match_empty:F { \int_compare:nNnF \l_regex_start_index_int = \l_regex_current_index_int } \cs_new_protected:Npn \regex_submatch_nesting_aux:n #1 { + \etex_glueshrink:D \etex_mutoglue:D \etex_muexpr:D \tex_muskip:D \etex_gluestretch:D \tex_skip:D #1 - \tex_muskip:D \tex_skip:D #1 \scan_stop: } \cs_new:Npn \regex_nesting:n #1 { } %^^A move. Rename? \tl_new:N \l_regex_nesting_tl \cs_new_protected:Npn \regex_replacement:n #1 { \int_zero:N \l_regex_replacement_int \int_zero:N \l_regex_nesting_int \tl_clear:N \l_regex_nesting_tl \regex_escape_use:nnnn { \regex_replacement_unescaped:N ##1 } { \regex_replacement_escaped:N ##1 } { \regex_replacement_raw:N ##1 } {#1} \prg_do_nothing: \prg_do_nothing: \cs_set:Npx \regex_nesting:n ##1 { + \int_use:N \l_regex_nesting_int \l_regex_nesting_tl - \regex_submatch_nesting_aux:n {##1} } \use:x { \exp_not:n { \cs_set:Npn \regex_replacement_tl:n ##1 } { \regex_toks_range:nn \c_zero \l_regex_replacement_int } } % ^^A rename! } \cs_new_protected:Npn \regex_replacement_raw:N #1 { \regex_replacement_put:n {#1} } \cs_new_protected:Npn \regex_replacement_put:n #1 { \tex_toks:D \l_regex_replacement_int {#1} \int_incr:N \l_regex_replacement_int } \cs_new_protected:Npn \regex_replacement_unescaped:N #1 { \if_charcode:w \c_rbrace_str #1 \if_num:w \l_regex_replacement_csnames_int > \c_zero \regex_replacement_put:n \cs_end: \else: \regex_replacement_put:n #1 \fi: \else: \regex_replacement_put:n #1 \fi: } \cs_new_protected:Npn \regex_replacement_escaped:N #1 { \cs_if_exist_use:cF { regex_replacement_#1:w } { \if_num:w \c_one < 1#1 \exp_stop_f: \regex_replacement_put_submatch:n {#1} \else: \regex_replacement_put:n #1 \fi: } } \cs_new_protected:Npn \regex_replacement_put_submatch:n #1 { \regex_replacement_put:n { \regex_query_submatch:nn {#1} {##1} } \if_num:w \l_regex_replacement_csnames_int = \c_zero \tl_put_right:Nn \l_regex_nesting_tl { \exp_not:N \if_num:w #1 < \l_regex_capturing_group_int \regex_submatch_nesting_aux:n { \int_eval:w #1+##1 \int_eval_end: } \exp_not:N \fi: } \fi: } \cs_new_protected:Npn \regex_replacement_error:NNN #1#2#3 { \msg_kernel_error:nnxx { regex } { #1-command } { replacement~text } {#3} #2 #3 } \cs_new_protected:Npn \regex_replacement_g:w #1#2 { \str_if_eq:xxTF { \exp_not:n { #1#2 } } { \regex_replacement_unescaped:N \c_lbrace_str } { \int_zero:N \l_regex_internal_a_int \regex_replacement_g_digits:NN } { \regex_replacement_error:NNN g #1 #2 } } \cs_new_protected:Npn \regex_replacement_g_digits:NN #1#2 { \token_if_eq_meaning:NNTF #1 \regex_replacement_unescaped:N { \if_num:w \c_one < 1#2 \exp_stop_f: \int_set:Nn \l_regex_internal_a_int { \c_ten * \l_regex_internal_a_int + #2 } \exp_after:wN \use_i:nnn \exp_after:wN \regex_replacement_g_digits:NN \else: \if_charcode:w \c_rbrace_str #2 \exp_args:No \regex_replacement_put_submatch:n { \int_use:N \l_regex_internal_a_int } \exp_after:wN \exp_after:wN \exp_after:wN \use_none:nn \else: \exp_after:wN \exp_after:wN \exp_after:wN \regex_replacement_error:NNN \exp_after:wN \exp_after:wN \exp_after:wN g \fi: \fi: } { \regex_replacement_error:NNN g } #1 #2 } \cs_new_protected:Npn \regex_replacement_u:w #1#2 { \str_if_eq:xxTF { #1#2 } { \regex_replacement_unescaped:N \c_lbrace_str } { \int_incr:N \l_regex_replacement_csnames_int \regex_replacement_put:n { \exp_not:n { \exp_after:wN \exp_not:V \cs:w } } } { \regex_replacement_error:NNN u #1#2 } } \cs_new_protected:Npn \regex_replacement_c:w #1#2 { \token_if_eq_meaning:NNTF #1 \regex_replacement_unescaped:N { \cs_if_exist_use:cF { regex_replacement_c_#2:w } { \regex_replacement_error:NNN c #1#2 } } { \regex_replacement_error:NNN c #1#2 } } \cs_new_protected_nopar:cpn { regex_replacement_c_ \c_lbrace_str :w } { \int_incr:N \l_regex_replacement_csnames_int \regex_replacement_put:n { \exp_not:n { \exp_after:wN \regex_replacement_exp_not:N \cs:w } } } \cs_new:Npn \regex_replacement_exp_not:N #1 { \exp_not:n {#1} } \group_begin: \char_set_catcode_math_superscript:N \^^@ \cs_new_protected_nopar:Npn \regex_replacement_c_U:w { \regex_replacement_char:nNN { ^^@ } } \char_set_catcode_alignment:N \^^@ \cs_new_protected_nopar:Npn \regex_replacement_c_T:w { \regex_replacement_char:nNN { ^^@ } } \cs_new_protected:Npn \regex_replacement_c_S:w #1#2 { \int_compare:nNnTF { `#2 } = \c_zero { \regex_replacement_error:NNN c #1#2 } { \char_set_lccode:nn {32} { `#2 } \tl_to_lowercase:n { \regex_replacement_put:n {~} } } } \char_set_catcode_parameter:N \^^@ \cs_new_protected_nopar:Npn \regex_replacement_c_P:w { \regex_replacement_char:nNN { ^^@^^@^^@^^@^^@^^@^^@^^@ } } \char_set_catcode_other:N \^^@ \cs_new_protected_nopar:Npn \regex_replacement_c_O:w { \regex_replacement_char:nNN { ^^@ } } \char_set_catcode_math_toggle:N \^^@ \cs_new_protected_nopar:Npn \regex_replacement_c_M:w { \regex_replacement_char:nNN { ^^@ } } \char_set_catcode_letter:N \^^@ \cs_new_protected_nopar:Npn \regex_replacement_c_L:w { \regex_replacement_char:nNN { ^^@ } } \char_set_catcode_group_end:N \^^@ \cs_new_protected_nopar:Npn \regex_replacement_c_E:w { \int_decr:N \l_regex_nesting_int \regex_replacement_char:nNN { \if_false: { \fi: ^^@ } } \char_set_catcode_math_subscript:N \^^@ \cs_new_protected_nopar:Npn \regex_replacement_c_D:w { \regex_replacement_char:nNN { ^^@ } } \char_set_catcode_group_begin:N \^^@ \cs_new_protected_nopar:Npn \regex_replacement_c_B:w { \int_incr:N \l_regex_nesting_int \regex_replacement_char:nNN { \exp_after:wN ^^@ \if_false: } \fi: } } \char_set_catcode_active:N \^^@ \cs_new_protected_nopar:Npn \regex_replacement_c_A:w { \regex_replacement_char:nNN { \exp_not:N ^^@ } } \group_end: \cs_new_protected:Npn \regex_replacement_char:nNN #1#2#3 { \char_set_lccode:nn \c_zero { `#3 } \tl_to_lowercase:n { \regex_replacement_put:n { \exp_not:n {#1} } } } \cs_new_protected_nopar:Npn \regex_set:Nn { \regex_set_aux:NNn \tl_set:Nn } \cs_new_protected_nopar:Npn \regex_gset:Nn { \regex_set_aux:NNn \tl_gset:Nn } \cs_new_protected_nopar:Npn \regex_const:Nn { \regex_set_aux:NNn \tl_const:Nn } \cs_new_protected:Npn \regex_set_aux:NNn #1#2#3 { \group_begin: \regex_build:n {#3} \use:x { \group_end: #1 \exp_not:N #2 { \regex_set_aux:N #2 } } } \cs_new:Npn \regex_set_aux:N #1 { \exp_not:n { \regex_nfa:Nw #1 } \l_regex_max_state_int = \int_use:N \l_regex_max_state_int \l_regex_capturing_group_int = \int_use:N \l_regex_capturing_group_int \token_if_eq_meaning:NNT \regex_match_loop_case_hook: \regex_match_loop_caseless_hook: { \cs_set_eq:NN \regex_match_loop_case_hook: \regex_match_loop_caseless_hook: } \prg_stepwise_function:nnnN \c_zero \c_one {\l_regex_max_state_int - \c_one } \regex_set_aux:n \s_stop } \cs_new:Npn \regex_set_aux:n #1 { \tex_toks:D #1 { \tex_the:D \tex_toks:D #1 } } \cs_new:Npn \regex_nfa:Nw #1 { \msg_expandable_kernel_error:nnn { regex } { nfa-misused } {#1} \use_none_delimit_by_s_stop:w } \cs_new_protected_nopar:Npn \regex_use:N { \exp_last_unbraced:No \use_none:nn } \cs_new_protected_nopar:Npn \regex_aux_return: { \if_meaning:w \c_true_bool \g_regex_success_bool \prg_return_true: \else: \prg_return_false: \fi: } \cs_new_protected:Npn \regex_aux_build_match:nn #1#2 { \regex_build:n {#1} \regex_match:n {#2} } \cs_new_protected:Npn \regex_aux_use_match:Nn #1#2 { \exp_args:No \tl_if_head_eq_meaning:nNTF {#1} \regex_nfa:Nw { \regex_use:N #1 \regex_match:n {#2} } { \msg_kernel_error:nnx { regex } { not-nfa } { \token_to_str:N #1 } \bool_gset_false:N \g_regex_success_bool } } \cs_set_protected:Npn \regex_tmp:w #1#2#3 { \cs_new_protected_nopar:Npn #1 { #3 \regex_aux_build_match:nn } \cs_new_protected_nopar:Npn #2 { #3 \regex_aux_use_match:Nn } \prg_new_protected_conditional:Npnn #1 ##1##2##3 { T , F , TF } { #3 \regex_aux_build_match:nn {##1} {##2} ##3 \regex_aux_return: } \prg_new_protected_conditional:Npnn #2 ##1##2##3 { T , F , TF } { #3 \regex_aux_use_match:Nn {##1} {##2} ##3 \regex_aux_return: } } \tl_map_inline:nn { { extract_once } { extract_all } { replace_once } { replace_all } { split } } { \exp_args:Nccc \regex_tmp:w { regex_#1:nnN } { regex_#1:NnN } { regex_#1_aux:NnnN } } \cs_new_protected_nopar:Npn \regex_extract: { \int_set_eq:NN \l_regex_submatch_start_int \l_regex_submatch_int \if_meaning:w \c_true_bool \g_regex_success_bool \prg_replicate:nn \l_regex_capturing_group_int { \tex_skip:D \l_regex_submatch_int \c_zero sp \scan_stop: \int_incr:N \l_regex_submatch_int } \prop_map_inline:Nn \l_regex_success_submatches_prop { \if_num:w ##1 \c_max_int \exp_after:wN \regex_extract_aux_b:wn \int_use:N \else: \exp_after:wN \regex_extract_aux_e:wn \int_use:N \fi: \int_eval:w \l_regex_submatch_start_int + ##1 {##2} } \fi: } \cs_new_protected:Npn \regex_extract_aux_b:wn #1 < #2 { \tex_skip:D #1 = #2 sp plus \etex_gluestretch:D \tex_skip:D #1 \scan_stop: } \cs_new_protected:Npn \regex_extract_aux_e:wn #1 > #2 { \tex_skip:D #1 = 1 \tex_skip:D #1 plus #2 sp \scan_stop: } \cs_new_protected:Npn \regex_group_end_extract_seq:N #1 { \cs_set_eq:NN \seq_item:n \scan_stop: \flag_clear:n { regex_begin } \flag_clear:n { regex_end } \tl_set:Nx \l_regex_internal_a_tl { \prg_stepwise_function:nnnN \l_regex_max_state_int \c_one { \l_regex_submatch_int - \c_one } \regex_extract_seq_aux:n } \int_compare:nNnF { \flag_height:n { regex_begin } + \flag_height:n { regex_end } } = \c_zero { \msg_kernel_error:nn { regex } { sequence-unbalanced } } \tl_set:Nx \l_regex_internal_a_tl { \l_regex_internal_a_tl } \exp_args:NNNo \group_end: \tl_set:Nn #1 \l_regex_internal_a_tl } \cs_new:Npn \regex_extract_seq_aux:n #1 { \seq_item:n { \exp_after:wN \regex_extract_seq_aux:ww \int_value:w \regex_submatch_nesting_aux:n {#1} ; #1; } } \cs_new:Npn \regex_extract_seq_aux:ww #1; #2; { \if_num:w #1 < \c_zero \flag_raise:n { regex_end } \prg_replicate:nn {-#1} { \exp_not:n { { \if_false: } \fi: } } \fi: \regex_query_submatch:w #2; \if_num:w #1 > \c_zero \flag_raise:n { regex_begin } \prg_replicate:nn {#1} { \exp_not:n { \if_false: { \fi: } } } \fi: } \prg_new_protected_conditional:Npnn \regex_match:nn #1#2 { T , F , TF } { \regex_match_aux:n { \regex_aux_build_match:nn {#1} {#2} } } \prg_new_protected_conditional:Npnn \regex_match:Nn #1#2 { T , F , TF } { \regex_match_aux:n { \regex_aux_use_match:Nn #1 {#2} } } \cs_new_protected:Npn \regex_match_aux:n #1 { \group_begin: \tl_clear:N \l_regex_every_match_tl \regex_disable_submatches: #1 \group_end: \regex_aux_return: } \cs_new_protected_nopar:Npn \regex_count:nnN { \regex_count_aux:NnnN \regex_aux_build_match:nn } \cs_new_protected_nopar:Npn \regex_count:NnN { \regex_count_aux:NnnN \regex_aux_use_match:Nn } \cs_new_protected:Npn \regex_count_aux:NnnN #1#2#3#4 { \group_begin: \regex_disable_submatches: \int_zero:N \l_regex_match_count_int \tl_set:Nn \l_regex_every_match_tl { \int_incr:N \l_regex_match_count_int \regex_match_once: } #1 {#2} {#3} \exp_args:NNNo \group_end: \int_set:Nn #4 { \int_use:N \l_regex_match_count_int } } \cs_new_protected:Npn \regex_extract_once_aux:NnnN #1#2#3#4 { \group_begin: \tl_set:Nn \l_regex_every_match_tl { \regex_extract: } #1 {#2} {#3} \regex_group_end_extract_seq:N #4 } \cs_new_protected:Npn \regex_extract_all_aux:NnnN #1#2#3#4 { \group_begin: \tl_set:Nn \l_regex_every_match_tl { \regex_extract: \regex_match_once: } #1 {#2} {#3} \regex_group_end_extract_seq:N #4 } \cs_new_protected:Npn \regex_split_aux:NnnN #1#2#3#4 { \group_begin: \tl_set:Nn \l_regex_every_match_tl { \if_num:w \l_regex_start_index_int < \l_regex_success_index_int \regex_extract: \tex_skip:D \l_regex_submatch_start_int = \l_regex_start_index_int sp plus \tex_skip:D \l_regex_submatch_start_int \scan_stop: \fi: \regex_match_once: } #1 {#2} {#3} \tex_skip:D \l_regex_submatch_int = \l_regex_start_index_int sp plus \l_regex_current_index_int sp \scan_stop: \int_incr:N \l_regex_submatch_int \if_num:w \l_regex_start_index_int = \l_regex_current_index_int \if_meaning:w \c_true_bool \l_regex_success_empty_bool \int_decr:N \l_regex_submatch_int \fi: \fi: \regex_group_end_extract_seq:N #4 } \cs_new_protected:Npn \regex_replace_once_aux:NnnN #1#2#3#4 { \group_begin: \tl_clear:N \l_regex_every_match_tl \regex_replacement:n {#3} \exp_args:Nno #1 {#2} #4 \if_meaning:w \c_true_bool \g_regex_success_bool \regex_extract: \int_set:Nn \l_regex_internal_a_int { \regex_nesting:n { \l_regex_submatch_start_int } } \if_num:w \l_regex_internal_a_int = \c_zero \else: \msg_kernel_error:nnx { regex } { replace-unbalanced } { \l_regex_internal_a_int } \fi: \tl_set:Nx \l_regex_internal_a_tl { \if_num:w \l_regex_internal_a_int < \c_zero \prg_replicate:nn { - \l_regex_internal_a_int } { \exp_not:n { { \if_false: } \fi: } } \fi: \regex_toks_range:nn { \l_regex_min_index_int } { \tex_skip:D \l_regex_submatch_start_int } \regex_replacement_tl:n { \l_regex_submatch_start_int } \regex_toks_range:nn { \etex_gluestretch:D \tex_skip:D \l_regex_submatch_start_int } { \l_regex_max_index_int } \if_num:w \l_regex_internal_a_int > \c_zero \prg_replicate:nn { \l_regex_internal_a_int } { \exp_not:n { \if_false: { \fi: } } } \fi: } \tl_set:Nx \l_regex_internal_a_tl { \l_regex_internal_a_tl } \exp_args:NNNo \group_end: \tl_set:Nn #4 \l_regex_internal_a_tl \else: \group_end: \fi: } \cs_new_protected:Npn \regex_replace_all_aux:NnnN #1#2#3#4 { \group_begin: \tl_set:Nn \l_regex_every_match_tl { \regex_extract: \tex_skip:D \l_regex_submatch_start_int = \tex_the:D \tex_skip:D \l_regex_submatch_start_int minus \l_regex_start_index_int sp \scan_stop: \regex_match_once: } \regex_replacement:n {#3} \exp_args:Nno #1 {#2} #4 \int_set:Nn \l_regex_internal_a_int { 0 \prg_stepwise_function:nnnN \l_regex_max_state_int \l_regex_capturing_group_int { \l_regex_submatch_int - \c_one } \regex_nesting:n } \if_num:w \l_regex_internal_a_int = \c_zero \else: \msg_kernel_error:nnx { regex } { replace-unbalanced } { \l_regex_internal_a_int } \fi: \tl_set:Nx \l_regex_internal_a_tl { \if_num:w \l_regex_internal_a_int < \c_zero \prg_replicate:nn { - \l_regex_internal_a_int } { \exp_not:n { { \if_false: } \fi: } } \fi: \prg_stepwise_function:nnnN \l_regex_max_state_int \l_regex_capturing_group_int { \l_regex_submatch_int - \c_one } \regex_replace_all_aux:n \regex_toks_range:nn \l_regex_start_index_int \l_regex_max_index_int \if_num:w \l_regex_internal_a_int > \c_zero \prg_replicate:nn { \l_regex_internal_a_int } { \exp_not:n { \if_false: { \fi: } } } \fi: } \tl_set:Nx \l_regex_internal_a_tl { \l_regex_internal_a_tl } \exp_args:NNNo \group_end: \tl_set:Nn #4 \l_regex_internal_a_tl } \cs_new:Npn \regex_replace_all_aux:n #1 { \regex_toks_range:nn { \etex_glueshrink:D \tex_skip:D #1 } { \tex_skip:D #1 } \regex_replacement_tl:n {#1} } \msg_kernel_new:nnnn { regex } { trailing-backslash } { Trailing~escape~character~\iow_char:N\\. } { A~regular~expression~or~its~replacement~text~ends~with~ the~escape~character~\iow_char:N\\.~It~will~be~ignored. } \msg_kernel_new:nnnn { regex } { x-missing-rbrace } { Missing~closing~brace~in~\iow_char:N\\x~hexadecimal~sequence. } { You~wrote~something~like~ `\iow_char:N\\x\{\int_to_hexadecimal:n{#1}'.~ The~closing~brace~is~missing. } \msg_kernel_new:nnnn { regex } { x-overflow } { Character~code~'#1'~too~large~in~\iow_char:N\\x~hexadecimal~sequence. } { You~wrote~something~like~ `\iow_char:N\\x\{\int_to_hexadecimal:n{#1}\}'.~ The~character~code~'#1'~is~larger~than~\int_use:N \c_max_char_int. } \msg_kernel_new:nnnn { regex } { missing-rbrack } { Missing~right~bracket~inserted~in~regular~expression. } { LaTeX~was~given~a~regular~expression~where~a~character~class~ was~started~with~'[',~but~the~matching~']'~is~missing. } \msg_kernel_new:nnnn { regex } { missing-rparen } { Missing~right~parenthes\int_compare:nTF{#1=1}{i}{e}s~ inserted~in~regular~expression. } { LaTeX~was~given~a~regular~expression~with~\int_eval:n{#1}~ more~left~parenthes\int_compare:nTF{#1=1}{i}{e}s~than~right~ parenthes\int_compare:nTF{#1=1}{i}{e}s. } \msg_kernel_new:nnnn { regex } { extra-rparen } { Extra~right~parenthesis~ignored~in~regular~expression. } { LaTeX~came~across~a~closing~parenthesis~when~no~submatch~group~ was~open.~The~parenthesis~will~be~ignored. } \msg_kernel_new:nnnn { regex } { class-bad-escape } { Invalid~escape~\c_backslash_str #1~in~character~class. } { The~escape~sequence~\iow_char:N\\#1~may~not~appear~within~ a~character~class.~For~instance,~assertions~(which~match~zero~ characters)~would~not~make~sense~there. } \msg_kernel_new:nnnn { regex } { catcode-bad-escape } { Invalid~escape~\c_backslash_str #1~following~category~test. } { The~escape~sequence~\iow_char:N\\#1~may~not~appear~following~ a~category~test~such~as~\iow_char:N\\cL~or~ \iow_char:N\\c[\iow_char:N\^BE]. } \msg_kernel_new:nnnn { regex } { range-missing-end } { Invalid~end-point~for~range~'#1-#2'~in~character~class. } { The~end-point~'#2'~of~the~range~'#1-#2'~may~not~serve~as~an~ end-point~for~a~range:~alphanumeric~characters~should~not~be~ escaped,~and~non-alphanumeric~characters~should~be~escaped. } \msg_kernel_new:nnnn { regex } { range-backwards } { Range~[#1-#2]~out~of~order~in~character~class. } { In~ranges~of~characters~[x-y]~appearing~in~character~classes,~ the~first~character~code~must~not~be~larger~than~the~second.~ Here,~#1~has~character~code~\int_eval:n {`#1},~while~#2~has~ character~code~\int_eval:n {`#2}. } \msg_kernel_new:nnnn { regex } { c-bad-mode } { Invalid~nested~\iow_char:N\\c~escape~in~regular~expression. } { The~\iow_char:N\\c~escape~cannot~be~used~within~ a~control~sequence~test~'\iow_char:N\\c{...}'.~ To~combine~several~category~tests,~use~'\iow_char:N\\c[...]'. } \msg_kernel_new:nnnn { regex } { c-missing-rbrace } { Missing~right~brace~inserted~for~\iow_char:N\\c~escape. } { LaTeX~was~given~a~regular~expression~where~a~ '\iow_char:N\\c\iow_char:N\{...'~construction~was~not~ended~ with~a~closing~brace~'\iow_char:N\}'. } \msg_kernel_new:nnnn { regex } { c-missing-rbrack } { Missing~right~bracket~inserted~for~\iow_char:N\\c~escape. } { A~construction~'\iow_char:N\\c[...'~appears~in~a~ regular~expression,~but~the~closing~']'~is~not~present. } \msg_kernel_new:nnnn { regex } { c-missing-category } { Invalid~character~'#1'~following~\iow_char\\c~escape. } { In~regular~expressions,~the~\iow_char:N\\c~escape~sequence~ may~only~be~followed~by~a~left~brace,~a~left~bracket,~or~a~ capital~letter~representing~a~character~category,~namely~ one~of~ABCDELMOPSTU. } \msg_kernel_new:nnnn { regex } { u-missing-lbrace } { Missing~left~brace~following~\iow_char:N\\u~escape. } { The~\iow_char:N\\u~escape~sequence~must~be~followed~by~ a~brace~group~with~the~name~of~the~variable~to~use. } \msg_kernel_new:nnnn { regex } { u-missing-rbrace } { Missing~right~brace~inserted~for~\iow_char:N\\u~escape. } { LaTeX~ \tl_if_empty:xTF {#2} { reached~the~end~of~the~string~ } { encountered~an~escaped~alphanumeric~character '\iow_char:N\\#2'~ } when~parsing~the~argument~of~an~'\iow_char:N\\u\iow_char:N\{...\}'~escape. } \msg_kernel_new:nnnn { regex } { sequence-unbalanced } { Missing~ \flag_if_raised:nTF { regex_end } { left~ \flag_if_raised:nTF { regex_begin } { and~right~braces } { brace } } { right~brace } \ inserted~in~extracted~match. } { LaTeX~was~asked~to~extract~submatches~or~split~a~token~list~ according~to~a~given~regular~expression,~but~some~of~the~resulting~ items~were~not~balanced. } \msg_kernel_new:nnnn { regex } { replace-unbalanced } { The~result~of~a~replacement~does~not~have~balanced~braces. } { LaTeX~was~asked~to~do~some~regular~expression~replacement,~ and~the~resulting~token~list~would~not~have~the~same~number~ of~begin-group~and~end-group~tokens. \\ \\ \ \ \ \ \prg_case_int:nnn {#1} { { -1 } { A~left~brace~was } { 1 } { A~right~brace~was } } { \int_abs:n {#1} ~ \int_compare:nNnTF {#1} < \c_zero { left } { right } ~ braces ~ were } \ inserted. } \msg_kernel_new:nnnn { regex } { not-nfa } { This~is~not~a~regular~expression~variable. } { LaTeX~was~expecting~`#1'~to~be~a~regular~expression~variable.\\ This~control~sequence~is~not~a~regex~variable.~It's~current~meaning~ is~\\\\ \ \ \ \ \token_to_str:N #1 = \token_to_meaning:N #1 . } \msg_kernel_new:nnn { regex } { nfa-misused } { Automaton~#1 used~incorrectly. } \msg_kernel_new:nnnn { regex } { c-command } { Misused~\iow_char:N\\c~or\iow_char:N\\C~command~in~a~#1. } { In~a~#1,~the~\iow_char:N\\C~escape~sequence~ can~be~followed~by~one~of~the~letters~ABCDELMOPSTU~ or~a~brace~group,~not~by~'#2'. } \msg_kernel_new:nnnn { regex } { unknown-option } { Unknown~option~`#1'~for~regular~expressions. } { LaTeX~came~across~something~like~`(?#1)'~in~a~regular~expression,~ but~the~option~`#1'~is~not~known.~It~will~be~ignored. } \msg_kernel_new:nnnn { regex } { invalid-in-option } { Invalid~character~in~option~of~a~regular~expression. } { The~character~or~escape~sequence~`#1'~is~not~defined~ as~an~option~within~regular~expressions. } \msg_kernel_new:nnnn { regex } { g-command } { Missing~brace~for~the~\iow_char:N\\g~construction~in~a~replacement~text. } { In~the~replacement~text~for~a~regular~expression~search,~ submatches~are~represented~either~as~\iow_char:N \\g{dd..d},~ or~\\d,~where~`d'~are~single~digits.~Here,~a~brace~is~missing. } %% %% %% End of file `l3regex.sty'.