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 '19 at 14:30
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 '19 at 17:38
  • @cmhughes As far as I know, sed doesn't support non-greedy search strings.
    – egreg
    Jul 10 '19 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}

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.