Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I have ~250 poems to typeset, consisting of ~40 verses each. 99% are in this form:

line 1
line 2
line 3
line 4

line 5
line 6
line 7
line 8

...

The "source" of each poem is a PDF file which I use to copy / paste into a plain text file.

Now the task is to format these poems while avoiding too much markup. I could do this:

\begin{verse}
line 1 \\
line 2 \\
line 3 \\
line 4 \\
\end{verse}

\begin{verse}
line 5 \\
line 6 \\
line 7 \\
line 8 \\
\end{verse}

But I much prefer not adding \begin{verse} and \end{verse} around each verse and I would like to avoid the double backslash at the end of each line. What can I do?

Some "rules"

  • No page break is allowed inside a 4 line verse
  • I want to avoid markup, but if it's not possible, its OK to add markup
  • All exceptions are handeld manually
  • No other special formatting is required (each of the four lines are flush left and ragged right, no automatic line breaking
  • Some poems should be mulitcolumn, if feasible
  • Each poem is in its own file, having a \title{...} and a \date{...} before it starts (I could put this somewhere else though).
share|improve this question
1  
I'm sure you already know this, but \obeylines could be used to avoid those \\s –  morbusg Jan 16 '13 at 11:08
add comment

3 Answers

up vote 20 down vote accepted

enter image description here

\documentclass[twocolumn]{article}

\textheight.5\textheight

\begingroup
\makeatletter
\catcode13\active%
\gdef\verseinput#1{%
{%
\interlinepenalty\@M%
\def^^M{\@ifnextchar^^M\par{\ifhmode\break\fi}}%
\rightskip\fill%
\parindent\z@%
\parskip\baselineskip%
\raggedbottom%
\catcode13\active\input{#1}%
\par%
}}%
\endgroup%
\begin{document}

\verseinput{v1.txt}

\end{document}

line 1
line 2
line 3
line 4

line 5
line 6
line 7
line 8

line 9
line 10
line 11
line 12

line a9
line a10
line a11
line a12

line b9
line b10
line b11
line b12

line a9
line a10
line a11
line a12

line b9
line b10
line b11
line b12

line a9
line a10
line a11
line a12

line b9
line b10
line b11
line b12

line a9
line a10
line a11
line a12

line b9
line b10
line b11
line b12

line a9
line a10
line a11
line a12

line b9
line b10
line b11
line b12
share|improve this answer
add comment

Add the following to your preamble and you don't need to type any mark-up:

\documentclass{article}
\makeatletter
\newdimen\allttindent \allttindent=0pt % set this to change the indent

\def\docspecials{\do\ \do\$\do\&%
  \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~}

\def\alltt{\trivlist \item[]\if@minipage\else\vskip\parskip\fi
\leftskip\@totalleftmargin  \advance\leftskip\allttindent \rightskip\z@
\parindent\z@\parfillskip\@flushglue\parskip\z@
\@tempswafalse \def\par{\if@tempswa\hbox{}\fi\@tempswatrue\@@par}
\obeylines \tt \catcode``=13 \@noligs
\let\do\@makeother \docspecials
 \frenchspacing\@vobeyspaces}

\let\endalltt=\endtrivlist
\AtBeginDocument{\alltt}
\AtEndDocument{\endalltt}
\makeatother

\begin{document}
There was an old woman of 92
Parlez-vous
There was an old woman of 92
Parlez-vous
There was an old woman of 92
Did a fart and away it flew
Inky pinky parlez-vous

The fart went rolling down the street
Knocked a copper off his feet

The copper got out his rusty pistol
Blew the fart right on to Bristol

The people of Bristol were having a dance
The fart went rolling on to France

The people of France were not at home
The fart went rolling on to Rome
\end{document}

It does not do the multicolumn but it maybe possible to trigger a multicolumn based on a word of the poem. Let me know the word and maybe egreg can come up with a macro for that! The preamble is borrowed from alltt2.

share|improve this answer
2  
There's some dirty smell emanating from this solution. –  Marc van Dongen Jan 16 '13 at 10:59
    
@MarcvanDongen :) –  Yiannis Lazarides Jan 16 '13 at 11:01
    
It works fine, except for the rule "no pagebreak inside a verse", but I guess this can be sorted out. Multicolumn works fine at a first glance –  topskip Jan 16 '13 at 11:04
    
@topskip It will be easier to re-write the poem than coerce TeX to do this. I am afraid you might need to do a bit of manual adjustment here. –  Yiannis Lazarides Jan 16 '13 at 11:15
add comment

An alternative option is to convert the plain text poems to the verse environment using another program. This method has the advantage that you could use it to automate the processing of poems from different files or from a database.

To prevent page breaks inside verses the following answer may be relevant: http://tex.stackexchange.com/a/21985/7092

As an example of the conversion, here's a simple tool using JavaScript with that performs this task. Here I consider a verse as any number of lines separated by a single line breaks. Save the code below as an html file to use it.

verses

<html>
<head>
<title>Verses!</title>

<script>
function convertVerses() 
{
    var input = document.getElementById('input').value
    var lines = input.split(/\r?\n/);
    var env = "verse"
    var output = "";
    for (var i = 0;i < lines.length;i++)
    {
        if (!lines[i].match(/^[ \t\n]*$/))
        {   
         //   alert(lines[i])
        // no empty line       
            if (lines.length==1 || 
              (i==0 && lines[i+1].match(/^[ \t\n]*$/)) ||
                (i==lines.length && lines[i-1].match(/^[ \t\n]*$/)) ||
                (lines[i-1].match(/^[ \t\n]*$/) && lines[i+1].match(/^[ \t\n]*$/))) {
                // only line of verse
                output += '\\begin\{'+env+'\}\n' + lines[i] + '\n\\end\{'+env+'\}\n\n';   
            } else  if (i==0 || lines[i-1].match(/^[ \t\n]*$/)) { 
                // first line of verse
                output += '\\begin\{'+env+'\}\n' +lines[i] + '\\\\\n';
            } else if (i==lines.length || lines[i+1].match(/^[ \t\n]*$/))  {
                // last line of verse
                output += lines[i] + '\n\\end\{'+env+'\}\n\n';   
            } else {
                // any other line of the verse 
                output += lines[i] + '\\\\\n';
            }  
        }
    }
    document.getElementById('output').value = output;
}

</script>

<style>
textarea {width:700px;height:330px;display:block;margin:10px}
button {width:700px;height:50px;margin:10px}
</style>
</head>

<body>    
<textarea id="input">
p0

p1
p2
p3 

p5
p6

p9
</textarea>
<button onclick="convertVerses()"> Convert!</button>
<textarea id="output">
</textarea>
</body>    
</html>
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.