# How can I apply a regex (l3regex) on items in a sequence? [LaTeX3]?

I am trying to apply a regular expression to a string item from a sequence in LaTeX3.

# Example

Compiles with error, but only by pressing return many times.

! Missing control sequence inserted.
<inserted text>
\inaccessible
l.64 \listprint[separator={ \par }]


## Documents.txt

Input file Documents.txt in same folder as source tex file:

test1_de.tex
test1_en.tex
test2_de.tex
test2_en.tex


## Source TeX File

\documentclass{article}
\usepackage{fontspec}
\usepackage{xparse}
\usepackage{expl3}
\usepackage{l3regex}

\ExplSyntaxOn
\NewDocumentCommand{\listset}{O{default}m}
{
\macmadness_listset:nn { #1 } { #2 }
}

\NewDocumentCommand{\listprint}{+O{}}
{
\group_begin:
\keys_set:nn { macmadness/lists } { #1 }
\group_end:
}

\cs_new_protected:Nn \macmadness_listset:nn % Command called by \listset (see above)
{
}
\cs_generate_variant:Nn \seq_set_split:Nnn {cnV}

{
name .initial:n      = default,
action .code:n       = \cs_set_eq:NN \__macmadness_action:n #1,
action .initial:n    = \use:n,
separator .tl_set:N  = \l__macmadness_list_separator_tl, % output delimiter
separator .initial:n = { ,~ }, % output delimiter
}

{
{
$\langle$ \textit{empty~list} $\rangle$
}
{
{
\tl_set:Nn \l_filename_tl { ##1 }
\regex_replace_all:nnN {(.*)[\c{_}|.] } { \1 } \l_filename_tl
\seq_put_right:Nn \l_macmadness_output_seq { \__macmadness_action:n { ../\regex_replace_all:nnN {(.*)[\c{_}|.] } { \1 } ##1 /##1 } }
}
}
}
\cs_generate_variant:Nn \seq_use:Nn { NV }

\ExplSyntaxOff

\begin{document}
\listset{./Documents.txt}
\listprint[separator={ \par }]
\end{document}


The special line with the regex command is:

\seq_put_right:Nn \l_macmadness_output_seq { \__macmadness_action:n { ../\regex_replace_all:nnN {(.*)[\c{_}|.] } { \1 } ##1 /##1 }


I think the problem is that the \regex_replace does not know to stop after the first ##1 and continues gobbling up tokens. If that is the problem, how could I make it stop reading at that point.

(just FYI, the regular expression is messed up and does not result in what I want anyway.)

I would like the output of that to be:

../test1/test1_de.tex
../test1/test1_en.tex
../test2/test2_de.tex
../test2/test2_en.tex

• why separator={ \par } ? – David Carlisle Jul 9 '15 at 12:49
• @DavidCarlisle It can be anything. It is just used between items in the output. \par would list each item vertically. – Jonathan Komar Jul 10 '15 at 7:19

It's unclear why you're looking for \_ when the input file is not expected to have such token.

\tl_new:N \l_macmadness_filename_tl

{
{
$\langle$ \textit{empty~list} $\rangle$
}
{
{
\regex_replace_all:nnN {([^_.]*).*} { \1 } \l_macmadness_filename_tl
{
}
}
}
}


The replacement has already been done by \regex_replace:nnN before; I changed the search regex to match all characters until the first underscore or period.

Full code:

\documentclass{article}
\usepackage{fontspec}
\usepackage{xparse}
\usepackage{expl3}
\usepackage{l3regex}

\ExplSyntaxOn
\NewDocumentCommand{\listset}{O{default}m}
{
\macmadness_listset:nn { #1 } { #2 }
}

\NewDocumentCommand{\listprint}{+O{}}
{
\group_begin:
\keys_set:nn { macmadness/lists } { #1 }
\group_end:
}

\cs_new_protected:Nn \macmadness_listset:nn % Command called by \listset (see above)
{
}
\cs_generate_variant:Nn \seq_set_split:Nnn {cnV}

{
name .initial:n      = default,
action .code:n       = \cs_set_eq:NN \__macmadness_action:n #1,
action .initial:n    = \use:n,
separator .tl_set:N  = \l__macmadness_list_separator_tl, % output delimiter
separator .initial:n = { ,~ }, % output delimiter
}

{
{
$\langle$ \textit{empty~list} $\rangle$
}
{
{
\regex_replace_all:nnN {([^_.]*).*} { \1 } \l_macmadness_filename_tl
{
}
}
}
}
\cs_generate_variant:Nn \seq_use:Nn { NV }

\ExplSyntaxOff

\begin{document}
\listset{./Documents.txt}
\listprint[separator={ \par }]
\end{document}

• I've copied your code into mine and it does not work correctly. Are you sure that you did not change anything else? Would you be willing to explain the extra { } where \exp_not: is located, and \exp_not: itself? That seems to be an important step I was missing. Also, the reason why I was looking for \_ is because originally, the code was used outside of a LaTeX3 environment. I had to escape the underscore there. Thanks for that correction. – Jonathan Komar Jul 10 '15 at 7:26
• I see no extra { } next to \exp_not:N – egreg Jul 10 '15 at 8:24
• Wherein \exp_not:N is located I should have written. There are extra brackets around \exp_not:N that are not in my example. The pair just above { \seq_use:NV \l_macmadness_output_seq \l__macmadness_list_separator_tl } – Jonathan Komar Jul 10 '15 at 8:28
• @daleif Fixed (I changed a name in almost all places) – egreg Jul 10 '15 at 11:16
• @daleif It doesn't disappear, as it produces a small dot; with pdflatex you have to use T1 encoding. – egreg Jul 10 '15 at 11:43