blue.monk has asked for the wisdom of the Perl Monks concerning the following question:

Ok,

I'm tying to do is use p(sed) to mark up a LaTex *.tex file. What needs to be done is every time there's a new/blank line before and after the word I'm matching replace it with \chapter{foo} i.e.:

\N Matthew \N

Would be replaced with \chapter{Matthew}

but would not be replaced in cases like these:
Matthew Mark Luke and John
or
Matthew
Mark
(since there is no "newline" before or after)

TIA, David

Here's a quick hack using s2p:

#!/usr/bin/perl -w eval 'exec /usr/bin/perl -S $0 ${1+"$@"}' if 0; $0 =~ s/^.*?(\w+)[\.\w+]*$/$1/; use strict; use Symbol; use vars qw{ $isEOF $Hold %wFiles @Q $CondReg $doAutoPrint $doOpenWrite $doPrint }; $doAutoPrint = 1; $doOpenWrite = 1; # prototypes sub openARGV(); sub getsARGV(;\$); sub eofARGV(); sub printQ(); # Run: the sed loop reading input and applying the script # sub Run(){ my( $h, $icnt, $s, $n ); # hack (not unbreakable :-/) to avoid // matching an empty string my $z = "\000"; $z =~ /$z/; # Initialize. openARGV(); $Hold = ''; $CondReg = 0; $doPrint = $doAutoPrint; CYCLE: while( getsARGV() ){ chomp(); $CondReg = 0; # cleared on t BOS:; # #!/usr/bin/sed # s/Matthew/\\chapter{Matthew}/g { $s = s /Matthew/\\chapter{Matthew}/sg; $CondReg ||= $s; } EOS: if( $doPrint ){ print $_, "\n"; } else { $doPrint = $doAutoPrint; } printQ() if @Q; } exit( 0 ); } Run(); # openARGV: open 1st input file # sub openARGV(){ unshift( @ARGV, '-' ) unless @ARGV; my $file = shift( @ARGV ); open( ARG, "<$file" ) || die( "$0: can't open $file for reading ($!)\n" ); $isEOF = 0; } # getsARGV: Read another input line into argument (default: $_). # Move on to next input file, and reset EOF flag $isEOF. sub getsARGV(;\$){ my $argref = @_ ? shift() : \$_; while( $isEOF || ! defined( $$argref = <ARG> ) ){ close( ARG ); return 0 unless @ARGV; my $file = shift( @ARGV ); open( ARG, "<$file" ) || die( "$0: can't open $file for reading ($!)\n" ); $isEOF = 0; } 1; } # eofARGV: end-of-file test # sub eofARGV(){ return @ARGV == 0 && ( $isEOF = eof( ARG ) ); } # makeHandle: Generates another file handle for some file (given by it +s path) # to be written due to a w command or an s command's w fla +g. sub makeHandle($){ my( $path ) = @_; my $handle; if( ! exists( $wFiles{$path} ) || $wFiles{$path} eq '' ){ $handle = $wFiles{$path} = gensym(); if( $doOpenWrite ){ if( ! open( $handle, ">$path" ) ){ die( "$0: can't open $path for writing: ($!)\n" ); } } } else { $handle = $wFiles{$path}; } return $handle; } # printQ: Print queued output which is either a string or a reference # to a pathname. sub printQ(){ for my $q ( @Q ){ if( ref( $q ) ){ # flush open w files so that reading this file gets it all if( exists( $wFiles{$$q} ) && $wFiles{$$q} ne '' ){ open( $wFiles{$$q}, ">>$$q" ); } # copy file to stdout: slow, but safe if( open( RF, "<$$q" ) ){ while( defined( my $line = <RF> ) ){ print $line; } close( RF ); } } else { print $q; } } undef( @Q ); }

Replies are listed 'Best First'.
Re: s/[newline]FOO[newline]/\\bar{foo}/sg
by davido (Cardinal) on Jun 30, 2004 at 17:46 UTC

    I have no idea how to use sed, and I'm surpised anyone would pass some other language through a source filter to convert it to Perl so that questions can be asked in Perl context. Imagine if we passed Perl through B::C to convert a script to C source code and then tried to ask questions about the spaghetti code in a C forum.

    Here is a Perlish solution to what I think you're trying to accomplish:

    my $string = 'stuff' # This should contain your original text. s/\n([a-zA-Z]+)\n/\n\\chapter{$1}\n/g;

    This is untested, but should take you in the right direction for a Perl solution.

    This fails if the chapter name is the first line of a file, since line one can't possibly have a newline preceeding it.

    Update: Almost forgot the /g modifier.


    Dave

Re: s/[newline]FOO[newline]/\\bar{foo}/sg
by qq (Hermit) on Jun 30, 2004 at 23:56 UTC
    perl -p -i.bk -e 's/^ (\w+) $/ \\chapter{$1} /'  *.tex

    If there are no spaces before and after the word, remove them from the regex.

    qq