1

I am using sed to reformat many plain text files to be compiled with LaTeX. The file contains various sections with keywords that provide a range. One of those sections I am working with is for hymns. A hymn begins with the keyword Hymn and ends with the word Amen. The text of the hymn is to be formatted for a "verse" context.

Here is a sample input file:

Hymn I
Conditor alme siderum,
Aeterna lux credentium,
Christe, redemptor omnium,
Exaudi preces supplicum.

Qui condolens interitu
Mortis perire saeculum,
Salvasti mundum languidum,
Donans reis remedium.

Vergente mundi vespere,
Uti sponsus de thalamo,
Egressus honestissima
Virginis matris clausula. Amen.

Hymn II
...
... Amen.

I want the file to look like this:

\small{\uppercase{Hymn I}}\normalsize
\begin{verse}
Conditor alme siderum,\\
Aeterna lux credentium,\\
Christe, redemptor omnium,\\
Exaudi preces supplicum.\\!

Qui condolens interitu\\
Mortis perire saeculum,\\
Salvasti mundum languidum,\\
Donans reis remedium.\\!

Vergente mundi vespere,\\
Uti sponsus de thalamo,\\
Egressus honestissima\\
Virginis matris clausula. Amen.\\!
\end{verse}
\small{\uppercase{Hymn II}}\normalsize
\begin{verse}
...\\
... Amen.\\!
\end{verse}

I have been able to figure out much of this. but I want to know how to use sed with multiple lines correctly to get the paragraphs formatted.

I've tried things with sed '/Hymn/,/Amen/ { /Hymn\|Amen/ !{...' And H or N but I can never seem to get it quite right.

  • Why are you using sed for such text-parsing? Why don't you go for some proper parser? Why not use pandoc? – shivams Oct 29 '15 at 23:50
2

Something like this:

sed '/Hymn/,/Amen/{                                 # in this range
/Hymn/{                                             # if line matches Hymn
s/.*/\\small\{\\uppercase\{&\}\}\\normalsize/       # replace as required
h                                                   # copy over the hold space
s/.*/\\begin\{verse\}/                              # replace with \begin{verse}
H                                                   # append to hold space
d                                                   # delete the line
}
/Amen/!{                                            # if line doesn't match Amen 
/^$/!{                                              # and if line is not empty
s/$/\\\\/                                           # add trailing \\
}
H                                                   # append to hold space
d                                                   # then delete line
}
//{                                                 # if line matches Amen
s/$/\\\\!/                                          # add trailing \\!
H                                                   # append to hold space
s/.*/\\end\{verse\}/                                # replace with \end{verse}
H                                                   # append to hold space
s/.*//                                              # empty pattern space
x                                                   # exchange buffers
s/\n\n/!&/g                                         # add ! at end of each para
}
}
' infile

or, if you prefer a gnu sed two-liner:

sed '/Hymn/,/Amen/{/Hymn/{s/.*/\\small\{\\uppercase\{\&\}\}\\normalsize/;h;s/.*/\\begin\{verse\}/;H;d}
/Amen/!{/^$/!{s/$/\\\\/};H;d};//{s/$/\\\\!/;H;s/.*/\\end\{verse\}/;H;s/.*//;x;s/\n\n/!&/g}}' infile

Output with your sample:

\small{\uppercase{Hymn I}}\normalsize
\begin{verse}
Conditor alme siderum,\\
Aeterna lux credentium,\\
Christe, redemptor omnium,\\
Exaudi preces supplicum.\\!

Qui condolens interitu\\
Mortis perire saeculum,\\
Salvasti mundum languidum,\\
Donans reis remedium.\\!

Vergente mundi vespere,\\
Uti sponsus de thalamo,\\
Egressus honestissima\\
Virginis matris clausula. Amen.\\!
\end{verse}

\small{\uppercase{Hymn II}}\normalsize
\begin{verse}
...\\
... Amen.\\!
\end{verse}
  • This is close to the solution I am looking for, but it is missing the "!" at the end of each paragraph of the hymn. The "!" only shows up on the "Amen" line. – ftherese Oct 29 '15 at 18:17
  • I need the trailing ! on every last line of every paragraph, not just the "Amen" line. – ftherese Oct 29 '15 at 19:52
  • @ftherese - I've updated my post. – don_crissti Oct 29 '15 at 20:50
  • Thank you so much! Your added explanation helps immensely, I should now be able to use the H feature of sed correctly as I have finally understood it. – ftherese Nov 1 '15 at 16:43
0

I'd use perl in paragraph mode.

#!/usr/bin/env perl
# Usage: thisprogram < inputfile > outputfile
use strict;
use warnings;
use feature qw(say);

$/ = "\n\n";    # paragraph mode

while (<>) {
  # nuke last \n of paragraph due to
  s/[\n]+\z//;
  # the need to replace the mid-verse newlines with \\
  s/\n/\\\\\n/g;
  # and now actually undo that while working on the first line
  s/(Hymn \w+)[\\]+/\\small{\\uppercase{$1}}\\normalsize\n\\begin{verse}/;
  # and at the newline-free end of the paragraph, tack on the \\! bit
  s/\z/\\\\!/;
  # emit
  say;
  if (m/Amen\./) {
    say "\\end{verse}\n";
  } else {
    print "\n";
  }
}
| improve this answer | |
  • I have seen many suggestions to use Perl, I may end up going the perl route eventually, but I have already written the rest of the formatting editions in sed. I appreciate your input, and it may prove valuable if I have to switch to perl. – ftherese Oct 29 '15 at 18:20

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.