5

I need to include file, but I want to manipulate it directly from PDFLaTeX. I must remove any text which is betweem \{ and \}, including backslashes and parenthesis. I have tried many escaping options, but the best I could get it this and it is not working:

\input{|"cat cxf.tex | sed 's|\\{.*\\}||g'"}

Is this possible at all?

1
  • Welcome to TeX.SE. Are you open to using LuaLaTeX instead of pdfLaTeX?
    – Mico
    Jul 10, 2019 at 14:30

2 Answers 2

5

This works for me (with pdflatex -shell-escape, of course) and prints just “abc”.

\begin{filecontents*}{\jobname-test.tex}
abc\{def\}
\end{filecontents*}

\documentclass{article}

\begin{document}

\input{|"cat \jobname-test.tex | sed 's|\string\\{.*\string\\}||g'"}

\end{document}

The issue is that TeX performs macro expansion on the argument to \input; with \string\\ we nullify the macro nature of \\.

I use \jobname just for avoiding the risk of clobbering my files.

If you want a non-greedy replacement, it's a bit more complicated (you could use Perl, instead). The search string should be something like

\\{[^\\}]*\\}

This can be more easily accomplished by defining the string beforehand:

\begin{filecontents*}{\jobname-test.tex}
abc\{def\}ghi\{jkl\}
\end{filecontents*}

\documentclass{article}

\begin{document}

\edef\searchstring{\string\\\string{[^\string\\\string}]*\string\\\string}}
\input{|"cat \jobname-test.tex | sed 's|\searchstring||g'"}

\end{document}

In this case the output would by “abcghi”.

2
  • 1
    +1 :) just wondered if the match might be .*? so as to be non-greedy?
    – cmhughes
    Jul 10, 2019 at 17:38
  • @cmhughes As far as I know, sed doesn't support non-greedy search strings.
    – egreg
    Jul 10, 2019 at 17:47
5

Assuming you're free to use LuaLaTeX, and assuming further that the material between \{ and \} (including the delimiters) is all on one line, the following solution should work just fine for you.

The solution consists of a Lua function (stored in an external file) and two LaTeX macros; the first assigns the Lua function to the process_input_buffer callback, making it act like a preprocessor, and the second removes the preprocessor-like operation of the Lua function.

enter image description here

The pattern-matching operation, "\\{.-\\}", uses .- rather than -* to match "zero or more instances of any character". Observe that using -* would be a mistake here, as it would make Lua perform a "greedy" match and thus inappropriately obliterate the middle substring, uvw.

\RequirePackage{filecontents}
%% External file with "\{ ... \}" material
\begin{filecontents*}{cxf.tex}
$abc \{...\} uvw \{ \int_0^1 \} xyz$

abc\{ ... \}uvw\{ \int_0^1 \}xyz
\end{filecontents*}

% Place the Lua code in a separate external file
\begin{filecontents*}{external.lua}
function remove_braced_stuff ( s )
   return ( s:gsub ( "\\{.-\\}" , "" ) )
end
\end{filecontents*}

\documentclass{article}
%% Load the Lua function from the external file
\directlua{dofile("external.lua")}

%% Two utility LaTeX macros
\newcommand{\RemoveBracedStuff}{\directlua{
  luatexbase.add_to_callback ( "process_input_buffer" , 
    remove_braced_stuff , "removestuff" )}}
\newcommand{\DontRemoveBracedStuff}{\directlua{
  luatexbase.remove_from_callback ( "process_input_buffer" , 
    "removestuff" )}}

\begin{document}
\RemoveBracedStuff % Enable the Lua function
\input cxf % Load the external file

\DontRemoveBracedStuff % Disable the Lua function
%% remainder of document
\end{document}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .