Here's some work I did on code to "wrap lines" of text to fit it within an arbitrary width. One reason for doing this is that I needed code like this the other day and was not able to find in on the J wiki, so I wrote it. Later, I found the code I knew was there: it is also given below.

There's still work to be done on these as none of them work exactly as I would want. Try

   40 lineNoWiderThan sampleText2

to see how the line-breaking appears odd as it does not heed double-LF as a "new paragraph" marker.

Of course, this is simple enough to remedy in J:

   ;LF,~&.>40 lineNoWiderThan &.><;._2 sampleText2
The text of the Oath of Hippocrates:

I swear by Apollo the physician, and
Aesculapius, Hygeia, and Panacea and all
the gods and goddesses, that, according
to my ability and judgment, I will keep
this Oath and this covenant:
...

Standard Library Function

After I'd written the following, Chris Burke mentioned that the standard library function "foldtext" does what I want. Not only that, it handles the paragraphs properly with no modification:

   load 'text'
   40 foldtext sampleText2
The text of the Oath of Hippocrates: 

I swear by Apollo the physician, and
Aesculapius, Hygeia, and Panacea and all
the gods and goddesses, that, according
to my ability and judgment, I will keep
this Oath and this covenant: 
...

I leave the following expositions here for historical interest.

Simple, Inexact Version

Here's some code that worked well enough when I just needed something that was approximately correct. It is not exactly correct because it will allow lines longer than the specified maximum. However, it gets close to the desired result and one can always adjust the maximum to get a more stringent fit.

NB.* simpleWordWrap: wrap text to new line where (space-delim'd words) longer than max.
simpleWordWrap=: 4 : 0
   max=. x.
   ss=. <;._1 ' ',dsp y.
   lens=. ;#&.>ss
   whb=. whb<max,}:whb=. max|+/\lens+1
NB.   >;&.>' ',~&.>&.>whb<;.1 ss        NB. Matrix result
   }:;(LF) _1}&.>;&.>' ',~&.>&.>whb<;.1 ss
)

A Stricter Version

The preceding version is much faster but a little lax: it will allow lines longer than the max. The following version is substantially slower but completely strict. This is a poor example of J code as it embodies a very scalar approach as can be inferred by the deep nesting of "if." statements.

lineBreak=: 4 : 0
   >0{x lineBreakDetail^:_ ] y
)

lineBreakDetail=: 4 : 0
   if. 0~:L. y do. str=. >_1{y [ pfx=. >0{y
   else. str=. y [ pfx=. '' end.
   if. 0~:#str do.
       if. x<#str do.
           whsp=. I. str e. ' ',TAB
           if. 0=$whsp do. str=. '' [ pfx=. pfx,str,LF
           else.
               if. x<:{.whsp do.
                    str=. str}.~>:{.whsp [ pfx=. pfx,(LF) _1}str{.~>:{.whsp
               else.
                   whtk=. <:0 i.~/:(>:x),whsp
                   brk=. >:whtk{whsp
                   pfx=. pfx,(LF) _1}brk{.str
                   str=. brk}.str
                end.
           end.
       else. str=. '' [ pfx=. pfx,str end.
   end.
   pfx;str
)

Elegant Versions

Finally, here's code Roger wrote that shames my efforts. I took the liberty of giving the top-level function a long, more meaningful name. My name for his "fmt" function, from his Text Formatting essay, is "lineNoWiderThan".

tc =: # (i.~{.]) [: }. (,#) {~^:a: 0:

NB.* lineNoWiderThan: Given: a string of words separated by blanks 
NB. and a positive integer w of the desired width. Replace appropriate 
NB. blanks in the string by the newline character LF , so that lines 
NB. are no wider than w and each line contains all the words that fit 
NB. within the line.

lineNoWiderThan=: 4 : 0
 e=. (' ' I.@:= y),#y
 LF (e {~ <: tc e I. (x+2)+}:_1,e)} y
)

end        =: #@] ,~ ' ' I.@:= ]
candidates =: ] I. 2&+@[ + }:@(_1&,)@]
ix         =: [ (<:@tc@candidates { ]) end
NB.* lineNoWiderThant: tacit version of "lineNoWiderThan".
lineNoWiderThant       =: LF"_`ix`] }

NB.* fmtcheck: same as lineNoWiderThan, but incorporates checks.
fmtcheck=: 4 : 0
 assert. 1 >: #$y
 assert. (''-:y) +. 2=3!:0 y
 assert. -. LF e. y
 assert. (0=#$x) *. (x=<.x) *. 0<:x
 assert. x (0&< *. >:) #;._2 y,' '
 e=. (' ' I.@:= y),#y
 z=. LF (e {~ <: tc e I. (x+2)+}:_1,e)} y
 assert. y -: ' ' (I. z=LF)}z
 assert. x >: n=. #;._2 z,LF
 assert. x <: (}:n) + }. i.&' ';._2 z,LF
)

Sample (Long Lines of) Text for Testing

sampleText1=: 0 : 0
Sweat covered Brion's body, trickling into the tight loincloth that was the only garment he wore. The light fencing foil in his hand felt as heavy as a bar of lead to his exhausted muscles, worn out by a month of continual exercise. These things were of no importance. The cut on his chest, still dripping blood, the ache of his overstrained eyes--even the soaring arena around him with the thousands of spectators--were trivialities not worth thinking about. There was only one thing in his universe: the button-tipped length of shining steel that hovered before him, engaging his own weapon. He felt the quiver and scrape of its life, knew when it moved and moved himself to counteract it. And when he attacked, it was always there to beat him aside.

A sudden motion. He reacted--but his blade just met air. His instant of panic was followed by a small sharp blow high on his chest.
)

sampleText2=: 0 : 0
The text of the Oath of Hippocrates: 

I swear by Apollo the physician, and Aesculapius, Hygeia, and Panacea and all the gods and goddesses, that, according to my ability and judgment, I will keep this Oath and this covenant: 

To reckon him who taught me this Art equally dear to me as my parents, to share my substance with him, and relieve his necessities if required; to look upon his offspring on the same footing as my own brothers, and to teach them this Art, if they shall wish to learn it, without fee or stipulation and that by precept, lecture, and every other mode of instruction, I will impart a knowledge of the Art to my own sons, and those of my teachers, and to disciples who have signed the covenant and have taken an oath according to the law of medicine, but no one else. 

I will follow that system of regimen which, according to my ability and judgment, I consider for the benefit of patients, and abstain from whatever is deleterious and mischievous. 

I will give no deadly medicine to anyone if asked, nor suggest any such counsel; and in like manner I will not give to a women an abortive remedy. With purity and with holiness I will pass my life and practice my Art. 

I will not cut persons laboring under the stone, but will leave this to be done by such men as are practitioners of this work. 

Into whatever houses I enter, I will go into them for the benefit of the sick, and will abstain from every voluntary act of mischief and corruption; and, further, from the seduction of females or males, of freemen and slaves. 

Whatever, in connection with my professional practice, or not in connection with it, I see or hear, in the life of men, which ought not to be spoken of abroad, I will not divulge, as reckoning that all such should be kept secret. 

While I continue to keep this Oath unviolated, may it be granted to me to enjoy life and practice of the Art, respected by all men, in all times. But should I trespass and violate this Oath, may the reverse be my lot.
)

See Also

DevonMcCormick/FittingTextIntoMargins (last edited 2008-12-08 10:45:30 by )