Here's a perl
script to get you started, subDollars.pl
. As a disclaimer, you should test it significantly before using it on anything important. I can't guarantee the results, but it should get you started.
You can use it in the following way
perl subDollars.pl test.tex
will simply output to the terminal with the substitutions
perl subDollars.pl -s test.tex
will not output to the terminal
perl subDollars.pl -w test.tex
will overwrite test.tex
with the substitutions in place
perl subDollars.pl -o test.tex output.tex
will output to output.tex
with the substitutions in place.
Any environments that you don't want it to operate on should be included in
my %nosubstitutions = ("tikzpicture"=>1, "verbatim"=>1, "nosubblock"=>1);
This hash can consist of stand environments such as tikzpicture
\begin{tikzpicture}
\draw[red] ($(#2)+(-.5em,.9em)$) rectangle ($(RightPoint)+(0.2em,-0.3em)$);
\end{tikzpicture}
or any blocks of code that are not necessarily within an environment, but you can wrap them in a 'commented' environment, such as
%\begin{nosubblock}
\draw[red] ($(#2)+(-.5em,.9em)$) rectangle ($(RightPoint)+(0.2em,-0.3em)$);
%\end{nosubblock}
The script won't account for $...$
and $$...$$
split across lines- that's certainly doable, but a little more work.
subDollars.pl
#!/usr/bin/perl
use strict;
use warnings;
use File::Copy; # to copy the original file to backup (if overwrite option set)
use Getopt::Std; # to get the switches/options/flags
# get the options
my %options=();
getopts("wos", \%options);
# standard output
my $out = *STDOUT;
# overwrite option
my $overwrite = 0;
$overwrite = $options{w};
# output file option
my $outputToFile = $options{o};
# can't call the script with MORE THAN 2 files
if(scalar(@ARGV)>2)
{
print $out <<ENDQUOTE
ERROR:
\t You're calling subDollars.pl with more than two file names
\t The script can take at MOST two file names, but you
\t need to call it with the -o switch; for example
\t subDollars.pl -o originalfile.tex outputfile.tex
Exiting...
ENDQUOTE
;
exit(2);
}
# check for output file
if($outputToFile and scalar(@ARGV)==1)
{
print $out <<ENDQUOTE
ERROR: When using the -o flag you need to call this script with 2 arguments
subDollars.pl -o "$ARGV[0]" [needs another name here]
Exiting...
ENDQUOTE
;
exit(2);
}
# don't call the script with 2 files unless the -o flag is active
if(!$outputToFile and scalar(@ARGV)==2)
{
print $out <<ENDQUOTE
ERROR:
\t You're calling subDollars.pl with two file names, but not the -o flag.
\t Did you mean to use the -o flag ?
Exiting...
ENDQUOTE
;
exit(2);
}
# array to store the modified lines
my @lines;
# hash naming environments that contain lines
# that should not be substituted
my %nosubstitutions = ("tikzpicture"=>1, "verbatim"=>1, "nosubblock"=>1);
# switch to toggle nosubstitutions- initially off
my $nosubs = 0;
# if we want to over write the current file
# create a backup first
if ($overwrite)
{
# original name of file
my $filename = $ARGV[0];
# copy it
my $backupFile = $filename;
my $backupExtension='.bak';
$backupFile =~ s/\.tex/$backupExtension/;
copy($filename,$backupFile) or die "Could not write to backup file $backupFile. Please check permissions. Exiting.\n";
}
# open the file
open(MAINFILE, $ARGV[0]) or die "Could not open input file";
# loop through the lines in the INPUT file
while(<MAINFILE>)
{
# check for BEGIN of an environment that doesn't want substitutions
$nosubs = 1 if( $_ =~ m/^\s*\\begin{(.*?)}/ and $nosubstitutions{$1} );
# check for %\begin{nosubblock}
$nosubs = 1 if( $_ =~ m/^\s*%\s*\\begin{(.*?)}/ and $nosubstitutions{$1} );
# check for END of an environment that doesn't want substitutions
$nosubs = 0 if( $_ =~ m/^\s*\\end{(.*?)}/ and $nosubstitutions{$1});
# check for %\end{nosubblock}
$nosubs = 0 if( $_ =~ m/^\s*%\s*\\end{(.*?)}/ and $nosubstitutions{$1} );
# substitute $.*$ with \(.*\)
# note: this does NOT match $$.*$$
s/(?<!\$)\$([^\$].*?)\$/\\\($1\\\)/g unless($nosubs);
# substitute $$.*$$ with \[.*\]
s/\$\$(.*?)\$\$/\\\[$1\\\]/g unless($nosubs);
push(@lines,$_);
}
# output the formatted lines to the terminal
print @lines if(!$options{s});
# if -w is active then output to $ARGV[0]
if($overwrite)
{
open(OUTPUTFILE,">",$ARGV[0]);
print OUTPUTFILE @lines;
close(OUTPUTFILE);
}
# if -o is active then output to $ARGV[1]
if($outputToFile)
{
open(OUTPUTFILE,">",$ARGV[1]);
print OUTPUTFILE @lines;
close(OUTPUTFILE);
}
exit;
Here's a test file to test it on
before.tex
\documentclass{article}
\begin{document}
$x=a+b$
$x=a+b$ and another $x=a+b$, $x=a+b$ and another $x=a+b$
$$x=a+b$$ and another $$x=a+b$$, $$x=a+b$$ and another $$x=a+b$$
\begin{tikzpicture}
\draw[red] ($(#2)+(-.5em,.9em)$) rectangle ($(RightPoint)+(0.2em,-0.3em)$);
\end{tikzpicture}
\begin{verbatim}
\draw[red] ($(#2)+(-.5em,.9em)$) rectangle ($(RightPoint)+(0.2em,-0.3em)$);
\end{verbatim}
$$x=a+b$$ and another $$x=a+b$$, $$x=a+b$$ and another $$x=a+b$$
%\begin{nosubblock}
\draw[red] ($(#2)+(-.5em,.9em)$) rectangle ($(RightPoint)+(0.2em,-0.3em)$);
%\end{nosubblock}
$x=a+b$ and another $x=a+b$, $x=a+b$ and another $x=a+b$
$$x=a+b$$ and another $$x=a+b$$, $$x=a+b$$ and another $$x=a+b$$
\end{document}
after.tex
\documentclass{article}
\begin{document}
\(x=a+b\)
\(x=a+b\) and another \(x=a+b\), \(x=a+b\) and another \(x=a+b\)
\[x=a+b\] and another \[x=a+b\], \[x=a+b\] and another \[x=a+b\]
\begin{tikzpicture}
\draw[red] ($(#2)+(-.5em,.9em)$) rectangle ($(RightPoint)+(0.2em,-0.3em)$);
\end{tikzpicture}
\begin{verbatim}
\draw[red] ($(#2)+(-.5em,.9em)$) rectangle ($(RightPoint)+(0.2em,-0.3em)$);
\end{verbatim}
\[x=a+b\] and another \[x=a+b\], \[x=a+b\] and another \[x=a+b\]
%\begin{nosubblock}
\draw[red] ($(#2)+(-.5em,.9em)$) rectangle ($(RightPoint)+(0.2em,-0.3em)$);
%\end{nosubblock}
\(x=a+b\) and another \(x=a+b\), \(x=a+b\) and another \(x=a+b\)
\[x=a+b\] and another \[x=a+b\], \[x=a+b\] and another \[x=a+b\]
\end{document}
Best Answer
Option 1:
sed
The stream editing tool,
sed
, would be a natural first choice, but the problem is thatsed
can't match non-greedy regular expressions.We need a non-greedy regular expression here- to clarify why, let's consider
If we apply this substitution to a file that contains something like
then we'll get
which is clearly not what we want- regular expression matches like this are greedy by default.
To make it non-greedy, we typically use
.*?
, but the problem is thatsed
does not support this type of match. Happily (thanks Hendrik) we can use the following insteadOnce you're comfortable that it does what you want, you can use
which will overwrite each file, and make a back up first,
myfile.tex.bak
Option 2:
perl
We could, instead, use a little
perl
one-liner:When you're sure that you trust it is working correctly, you can use the following to overwrite myfile.tex
You can replace
myfile.tex
with, for example,*.tex
to operate on all the.tex
files in the current working directory.Details of
perl
's switches are discussed here (for example): http://perldoc.perl.org/perlrun.html#Command-Switches