Contents
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. )
