3

I would like to do some simple pattern matching in LaTeX, where a character in the pattern (e.g., shell like as in *, or regex like as in .*, I´ll use the latter) replaces zero or more characters in the target. I have strong a preference for a solution that works seamlessly with pdfLaTeX, XeLaTeX and luaLaTeX.

Given a list of lists and a pattern, like:

\newcommand{\target}{{a,b,c},{a,x,y,c},{a,b,d}}
\newcommand{\pattern}{a,.*,c}

I would like to have a command

\matchpattern{\pattern}{\target}\result

that would set \result to the elements in \target matching \pattern, i.e.,

{{a,b,c},{a,x,y,c}}

I'm also ok with \result ending with only the first {a,b,c} or last {a,x,y,c} match (and not all the matches), if it makes the solution simpler/easier.

I believe that both the package makematch and l3regex could help. But I could not understand how to use makematch from the documentation, and l3regex if far beyond my wizard level.

Any help is welcome. Thank you.

3
  • you could use l3regexp for that but do you really want to use regular expressions here (slow and delicate) it would be much quicler for this case for eample to consider the target as clists (comma lists) and accept all such lists that have first entry a and last entry c it would aslo save asking if you want za,zb,zc to match since it matches a.*c Nov 25 at 14:19
  • @DavidCarlisle, thanks for the suggestion. I don't need really need a regex, and I could do with a simpler solution. Although for clarity my example omits it, the "*" operator may be in the beginning, middle or end of the pattern. The pattern may even have no star operator. Do you believe that, in this case, the list processing approach is still going to be faster than a regex? Nov 25 at 14:28
  • Are you familiar with Lua and its pattern-matching functions? If so, you could easily perform pattern matching while compiling your LaTeX document with LuaLaTeX.
    – Mico
    Nov 25 at 14:56
5

The syntax is

\matchpattern[+][*]{<pattern>}{<target>}<result>

where + denotes using a stored pattern and * using a stored target.

\documentclass{article}

\ExplSyntaxOn

\NewDocumentCommand{\matchpattern}{t+ s m m m}
 {
  \IfBooleanTF{#1}
   {% use stored pattern
    \IfBooleanTF{#2}
     {% expand the argument
      \joao_matchpattern:nVNN #3 #4 #5 \regex_match:NnT
     }
     {% explicit argument
      \joao_matchpattern:nnNN #3 { #4 } #5 \regex_match:NnT
     }
   }
   {% use explicit pattern
    \IfBooleanTF{#2}
     {% expand the argument
      \joao_matchpattern:nVNN { #3 } #4 #5 \regex_match:nnT
     }
     {
      \joao_matchpattern:nnNN { #3 } { #4 } #5 \regex_match:nnT
     }
   }
 }

\NewDocumentCommand{\definepattern}{mm}
 {
  \regex_set:Nn #1 { #2 }
 }

\clist_new:N \l__joao_matchpattern_tmp_clist

\cs_new_protected:Nn \joao_matchpattern:nnNN
 {% #4 is either \regex_match:NnT or \regex_match:nnT
  % #1 is the pattern (either stored or explicit)
  % #2 is the target (either stored or explicit)
  % #3 is the macro to hold the result
  \clist_clear:N \l__joao_matchpattern_tmp_clist  
  \clist_map_inline:nn { #2 }
   {
    #4 { #1 } { ##1 }
     {
      \clist_put_right:Nn \l__joao_matchpattern_tmp_clist { {##1} }
     }
   }
  \clist_set_eq:NN #3 \l__joao_matchpattern_tmp_clist
 }
\cs_generate_variant:Nn \joao_matchpattern:nnNN { nV }

\ExplSyntaxOff

\begin{document}

\matchpattern{a,.*,c}{{a,b,c},{a,x,y,c},{a,b,d}}\result

\show\result

\definepattern{\pattern}{a,.*,c}

\matchpattern+{\pattern}{{a,b,c},{a,x,y,c},{a,b,d}}\result

\show\result

\newcommand{\target}{{a,b,c},{a,x,y,c},{a,b,d}}

\matchpattern+*{\pattern}{\target}\result

\show\result

\stop

In all three cases the answer is

> \result=macro:
->{a,b,c},{a,x,y,c}.
1
  • Thanks egreg. I definitely need to upgrade my wizard skills to latex3. :) Nov 25 at 18:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.