2016 Update

This commit is contained in:
Tina Müller 2016-12-05 22:15:40 +01:00
parent 948b86eafa
commit dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions

View file

@ -1,15 +1,20 @@
Even today, with proportional fonts and complex layouts, there are still [[Template:Lines_too_long|cases]] where you need to wrap text at a specified column.
;Basic task:
The basic task is to wrap a paragraph of text in a simple way in your language.
If there is a way to do this that is built-in, trivial, or provided in a standard library, show that. Otherwise implement the [http://en.wikipedia.org/wiki/Word_wrap#Minimum_length minimum length greedy algorithm from Wikipedia.]
Show your routine working on a sample of text at two different wrap columns.
'''Extra credit!''' Wrap text using a more sophisticated algorithm such as the Knuth and Plass TeX algorithm.
;Extra credit:
Wrap text using a more sophisticated algorithm such as the Knuth and Plass TeX algorithm.
If your language provides this, you get easy extra credit,
but you ''must reference documentation'' indicating that the algorithm
is something better than a simple minimimum length algorithm.
If you have both basic and extra credit solutions, show an example where
the two algorithms give different results.
<br><br>

View file

@ -0,0 +1,13 @@
;; Greedy wrap line
(defun greedy-wrap (str width)
(setq str (concatenate 'string str " ")) ; add sentinel
(do* ((len (length str))
(lines nil)
(begin-curr-line 0)
(prev-space 0 pos-space)
(pos-space (position #\Space str) (when (< (1+ prev-space) len) (position #\Space str :start (1+ prev-space)))) )
((null pos-space) (progn (push (subseq str begin-curr-line (1- len)) lines) (nreverse lines)) )
(when (> (- pos-space begin-curr-line) width)
(push (subseq str begin-curr-line prev-space) lines)
(setq begin-curr-line (1+ prev-space)) )))

View file

@ -0,0 +1,5 @@
CHARACTER*12345 TEXT
...
DO I = 0,120
WRITE (6,*) TEXT(I*80 + 1:(I + 1)*80)
END DO

View file

@ -0,0 +1,125 @@
MODULE RIVERRUN !Schemes for re-flowing wads of text to a specified line length.
INTEGER BL,BLIMIT,BM !Fingers for the scratchpad.
PARAMETER (BLIMIT = 222) !This should be enough for normal widths.
CHARACTER*(BLIMIT) BUMF !The scratchpad, accumulating text.
INTEGER OUTBUMF !Output unit number.
DATA OUTBUMF/0/ !Thus detect inadequate initialisation.
PRIVATE BL,BLIMIT,BM !These names are not so unusual
PRIVATE BUMF,OUTBUMF !That no other routine will use them.
CONTAINS
INTEGER FUNCTION LSTNB(TEXT) !Sigh. Last Not Blank.
Concocted yet again by R.N.McLean (whom God preserve) December MM.
Code checking reveals that the Compaq compiler generates a copy of the string and then finds the length of that when using the latter-day intrinsic LEN_TRIM. Madness!
Can't DO WHILE (L.GT.0 .AND. TEXT(L:L).LE.' ') !Control chars. regarded as spaces.
Curse the morons who think it good that the compiler MIGHT evaluate logical expressions fully.
Crude GO TO rather than a DO-loop, because compilers use a loop counter as well as updating the index variable.
Comparison runs of GNASH showed a saving of ~3% in its mass-data reading through the avoidance of DO in LSTNB alone.
Crappy code for character comparison of varying lengths is avoided by using ICHAR which is for single characters only.
Checking the indexing of CHARACTER variables for bounds evoked astounding stupidities, such as calculating the length of TEXT(L:L) by subtracting L from L!
Comparison runs of GNASH showed a saving of ~25-30% in its mass data scanning for this, involving all its two-dozen or so single-character comparisons, not just in LSTNB.
CHARACTER*(*),INTENT(IN):: TEXT !The bumf. If there must be copy-in, at least there need not be copy back.
INTEGER L !The length of the bumf.
L = LEN(TEXT) !So, what is it?
1 IF (L.LE.0) GO TO 2 !Are we there yet?
IF (ICHAR(TEXT(L:L)).GT.ICHAR(" ")) GO TO 2 !Control chars are regarded as spaces also.
L = L - 1 !Step back one.
GO TO 1 !And try again.
2 LSTNB = L !The last non-blank, possibly zero.
RETURN !Unsafe to use LSTNB as a variable.
END FUNCTION LSTNB !Compilers can bungle it.
SUBROUTINE STARTFLOW(OUT,WIDTH) !Preparation.
INTEGER OUT !Output device.
INTEGER WIDTH !Width limit.
OUTBUMF = OUT !Save these
BM = WIDTH !So that they don't have to be specified every time.
IF (BM.GT.BLIMIT) STOP "Too wide!" !Alas, can't show the values BLIMIT and WIDTH.
BL = 0 !No text already waiting in BUMF
END SUBROUTINE STARTFLOW!Simple enough.
SUBROUTINE FLOW(TEXT) !Add to the ongoing BUMF.
CHARACTER*(*) TEXT !The text to append.
INTEGER TL !Its last non-blank.
INTEGER T1,T2 !Fingers to TEXT.
INTEGER L !A length.
IF (OUTBUMF.LT.0) STOP "Call STARTFLOW first!" !Paranoia.
TL = LSTNB(TEXT) !No trailing spaces, please.
IF (TL.LE.0) THEN !A blank (or null) line?
CALL FLUSH !Thus end the paragraph.
RETURN !Perhaps more text will follow, later.
END IF !Curse the (possible) full evaluation of .OR. expressions!
IF (TEXT(1:1).LE." ") CALL FLUSH !This can't be checked above in case LEN(TEXT) = 0.
Chunks of TEXT are to be appended to BUMF.
T1 = 1 !Start at the start, blank or not.
10 IF (BL.GT.0) THEN !If there is text waiting in BUMF,
BL = BL + 1 !Then this latest text is to be appended
BUMF(BL:BL) = " " !After one space.
END IF !So much for the join.
Consider the amount of text to be placed, TEXT(T1:TL)
L = TL - T1 + 1 !Length of text to be placed.
IF (BM - BL .GE. L) THEN !Sufficient space available?
BUMF(BL + 1:BM + L) = TEXT(T1:TL) !Yes. Copy all the remaining text.
BL = BL + L !Advance the finger.
IF (BL .GE. BM - 1) CALL FLUSH !If there is no space for an addendum.
RETURN !Done.
END IF !Otherwise, there is an overhang.
Calculate the available space up to the end of a line. BUMF(BL + 1:BM)
L = BM - BL !The number of characters available in BUMF.
T2 = T1 + L !Finger the first character beyond the take.
IF (TEXT(T2:T2) .LE. " ") GO TO 12 !A splitter character? Happy chance!
T2 = T2 - 1 !Thus the last character of TEXT that could be placed in BUMF.
11 IF (TEXT(T2:T2) .GT. " ") THEN !Are we looking at a space yet?
T2 = T2 - 1 !No. step back one.
IF (T2 .GT. T1) GO TO 11 !And try again, if possible.
IF (L .LE. 6) THEN !No splitter found. For short appendage space,
CALL FLUSH !Starting a new line gives more scope.
GO TO 10 !At the cost of spaces at the end.
END IF !But splitting words is unsavoury too.
T2 = T1 + L - 1 !Alas, no split found.
END IF !So the end-of-line will force a split.
L = T2 - T1 + 1 !The length I settle on.
12 BUMF(BL + 1:BL + L) = TEXT(T1:T1 + L - 1) !I could add a hyphen at the arbitrary chop...
BL = BL + L !The last placed.
CALL FLUSH !The line being full.
Consider what the flushed line didn't take. TEXT(T1 + L:TL)
T1 = T1 + L !Advance to fresh grist.
13 IF (T1.GT.TL) RETURN !Perhaps there is no more. No compound testing, alas.
IF (TEXT(T1:T1).LE." ") THEN !Does a space follow a line split?
T1 = T1 + 1 !Yes. It would appear as a leading space in the output.
GO TO 13 !But the line split stands in for all that.
END IF !So, speed past all such.
IF (T1.LE.TL) GO TO 10!Does anything remain?
RETURN !Nope.
CONTAINS !A convenience.
SUBROUTINE FLUSH !Save on repetition.
IF (BL.GT.0) WRITE (OUTBUMF,"(A)") BUMF(1:BL) !Roll the bumf, if any.
BL = 0 !And be ready for more.
END SUBROUTINE FLUSH !Thus avoid the verbosity of repeated begin ... end blocks.
END SUBROUTINE FLOW !Invoke with one large blob, or, pieces.
END MODULE RIVERRUN !Flush the tail end with a null text.
PROGRAM TEST
USE RIVERRUN
INTEGER MSG,IN
CHARACTER*222 BUMF
MSG = 6
IN = 10
CALL STARTFLOW(MSG,36)
CALL FLOW("Fifteen men on a dead man's chest!")
CALL FLOW(" Yo ho ho and a bottle of rum!")
CALL FLOW("Drink and the devil have done for the rest!")
CALL FLOW(" Yo ho ho and a bottle of rum!")
CALL FLOW("")
WRITE (MSG,*)
Chew into my source file for a second example.
OPEN (IN,FILE="TextFlow.for",ACTION = "READ")
1 READ (IN,2) BUMF
2 FORMAT (A)
IF (BUMF(1:1).NE."C") GO TO 1 !No comment block yet.
CALL STARTFLOW(MSG,66) !Found it!
3 CALL FLOW(BUMF) !Roll its text.
READ (IN,2) BUMF !Grab another line.
IF (BUMF(1:1).EQ."C") GO TO 3 !And if a comment, append.
CALL FLOW("")
CLOSE (IN)
END

View file

@ -0,0 +1,23 @@
(function (width) {
'use strict';
function wrapByRegex(n, s) {
return s.match(
RegExp('.{1,' + n + '}(\\s|$)', 'g')
)
.join('\n');
}
return wrapByRegex(width,
'Even today, with proportional fonts and compl\
ex layouts, there are still cases where you ne\
ed to wrap text at a specified column. The bas\
ic task is to wrap a paragraph of text in a si\
mple way in your language. If there is a way t\
o do this that is built-in, trivial, or provid\
ed in a standard library, show that. Otherwise\
implement the minimum length greedy algorithm\
from Wikipedia.'
)
})(60);

View file

@ -0,0 +1,56 @@
/**
* [wordwrap description]
* @param {[type]} text [description]
* @param {Number} width [description]
* @param {String} br [description]
* @param {Boolean} cut [description]
* @return {[type]} [description]
*/
function wordwrap(text, width = 80, br = '\n', cut = false) {
// Приводим к uint
// 0..2^32-1 либо 0..2^64-1
width >>>= 0;
// Длина текста меньше или равна максимальной
if (0 === width || text.length <= width) {
return text;
}
// Разбиваем текст на строки
return text.split('\n').map(line => {
if (line.length <= width) {
return line;
}
// Разбиваем строку на слова
let words = line.split(' ');
// Если требуется, то обрезаем длинные слова
if (cut) {
let temp = [];
for (const word of words) {
if (word.length > width) {
let i = 0;
const length = word.length;
while (i < length) {
temp.push(word.slice(i, Math.min(i + width, length)));
i += width;
}
} else {
temp.push(word);
}
}
words = temp;
}
// console.log(words);
// Собираем новую строку
let wrapped = words.shift();
let spaceLeft = width - wrapped.length;
for (const word of words) {
if (word.length + 1 > spaceLeft) {
wrapped += br + word;
spaceLeft = width - word.length;
} else {
wrapped += ' ' + word;
spaceLeft -= 1 + word.length;
}
}
return wrapped;
}).join('\n'); // Объединяем элементы массива по LF
}

View file

@ -0,0 +1 @@
console.log(wordwrap("The quick brown fox jumped over the lazy dog.", 20, "<br />\n"));

View file

@ -0,0 +1,52 @@
function Out-WordWrap
{
[CmdletBinding()]
[OutputType([string])]
Param
(
[Parameter(Mandatory=$true,
ValueFromPipeline=$true,
Position=0)]
[string]
$Text,
[Parameter(Mandatory=$false,
Position=1)]
[ValidateRange(16,160)]
[int]
$Width = 80
)
Begin
{
function New-WordWrap ([string]$Text, [int]$Width)
{
[string[]]$words = $Text.Split()
[string]$output = ""
[int]$remaining = $Width
foreach ($word in $words)
{
if($word.Length + 1 -gt $remaining)
{
$output += "`n$word "
$remaining = $Width - ($word.Length + 1)
}
else
{
$output += "$word "
$remaining -= $word.Length + 1
}
}
return "$output`n"
}
}
Process
{
foreach ($paragraph in $Text)
{
New-WordWrap -Text $paragraph -Width $Width
}
}
}

View file

@ -0,0 +1,12 @@
[string[]]$paragraphs = "Rebum everti delicata an vel, quo ut temporibus interpretaris, mea debet mnesarchum disputando ad. Id has dolorum contentiones, mel ea noster adipisci. Id persius appareat eos, aeque dolorum fastidii eam in. Partem assentior contentiones ut mea. Cu augue facilis fabellas cum, vix eu sanctus denique imperdiet, appareat percipit qui ex.",
"Nihil discere phaedrum at duo, no eum adhuc autem error. Quo aliquam delicata contentiones et, in sed ferri legimus sententiae, nihil solet docendi id eum. Ius ut meliore vulputate adipiscing, sea cu virtute praesent. Euripidis instructior est eu. Veri cotidieque ex vel, aliquam eruditi nusquam sea ne, eu wisi ubique ullamcorper est. Qui doctus epicuri ei. Cum esse detracto concludaturque ea, veri erant per ad, vide ancillae principes ius id.",
"Id disputando signiferumque nam, mei illud aeterno ut. Facilisis evertitur mei at. Qui in wisi fugit, eirmod comprehensam duo ei. Ea mel omnium nusquam, causae consequat appellantur per te.",
"Denique deseruisse ea his. Mundi scripta adolescens te ius, cum error persius cotidieque cu. Nobis apeirian ad his. Ius omnes gloriatur at, has eu tamquam inciderint, ubique commodo pro ad. Ex veri ceteros quo, duo an labores adolescens. Sed id quod verterem prodesset, magna eloquentiam ea eum.",
"Qui sanctus oportere quaerendum ex, usu vivendo accusamus posidonium an. Quo cu graece reprimique. Ea cum purto quando referrentur, tritani perfecto ne sit. Ne sit iusto ludus, ea ius eruditi dissentiunt, fabellas disputando eu vix. Te vim eripuit debitis tincidunt, in vim nonumes consetetur.",
"Affert exerci aperiri pri ea. Ut dicant essent corrumpit sit. Sea saepe nullam referrentur ut, vis dolores perfecto cu. At nam inimicus evertitur vulputate.",
"Dolor volutpat praesent vix ne, at soluta oblique admodum eum. Duis adipisci mea in, nam ut tota choro theophrastus. Ex scripta definitiones mei, augue doctus ne sed, munere posidonium eum id. Ad graeco audire per.",
"Sale salutatus et mei, mea elit illud adipiscing ei, cum ea sumo melius forensibus. Eu inani iusto oporteat eum, ei vix iisque saperet detraxit. Fabulas perpetua similique eam ne, noster corpora dissentiet qui ex, et qui integre graecis. Eripuit nonumes deterruisset an pro, ei ferri similique cum. Odio dolores inciderint ei vim, an est dolorum delicata temporibus, eu mea quis accumsan. Vel stet affert option at.",
"In gubergren voluptaria reprimique pro, option fuisset id est. Rebum delicata ad sea, ex vidit errem vis, mei at duis dicam sensibus. Nibh debet iudicabit has no, vim te dicit libris possim. Debet viderer consequuntur ea pro. Ex dicat iriure scripta pro.",
"An dicat diceret eligendi duo. Est cu equidem deterruisset, usu ad regione equidem, vim amet vero possim ex. Theophrastus conclusionemque ad quo, inimicus deseruisse voluptatibus eum et. Duis delectus mandamus an mei, usu timeam nostrum suscipiantur id."
$paragraphs | Out-WordWrap -Width 100

View file

@ -1,17 +1,18 @@
/*REXX pgm reads a file and displays it (with word wrap to the screen). */
parse arg iFID width /*get optional arguments from CL.*/
@= /*nullify the text (so far). */
do j=0 while lines(iFID)\==0 /*read from the file until E-O-F.*/
@=@ linein(iFID) /*append the file's text to @ */
end /*j*/
$=word(@,1)
do k=2 for words(@)-1; x=word(@,k) /*parse until text (@) exhausted.*/
_=$ x /*append it to the money and see.*/
if length(_)>width then do /*words exceeded the width? */
say $ /*display what we got so far. */
_=x /*overflow for the next line. */
end
$=_ /*append this word to the output.*/
end /*k*/
if $\=='' then say $ /*handle any residual words. */
/*stick a fork in it, we're done.*/
/*REXX program reads a file and displays it to the screen (with word wrap). */
parse arg iFID width . /*obtain optional arguments from the CL*/
if iFID=='' | iFID=="," then iFID='LAWS.TXT' /*Not specified? Then use the default.*/
if width=='' | width=="," then width=linesize() /* " " " " " " */
@= /*number of words in the file (so far).*/
do while lines(iFID)\==0 /*read from the file until End-Of-File.*/
@=@ linein(iFID) /*get a record (line of text). */
end /*while*/
$=word(@,1) /*initialize $ with the first word. */
do k=2 for words(@)-1; x=word(@,k) /*parse until text (@) exhausted. */
_=$ x /*append it to the $ list and test. */
if length(_)>width then do; say $ /*this word a bridge too far? > w. */
_=x /*assign this word to the next line. */
end
$=_ /*new words (on a line) are OK so far.*/
end /*m*/
if $\=='' then say $ /*handle any residual words (overflow).*/
/*stick a fork in it, we're all done. */

View file

@ -1,48 +1,42 @@
/*REXX pgm reads a file and displays it (with word wrap to the screen).*/
parse arg iFID width justify _ . /*get optional CL args.*/
if iFID='' |iFID==',' then iFID ='LAWS.TXT' /*default input file ID*/
if width==''|width==',' then width=linesize() /*Default? Use linesize*/
if width==0 then width=80 /*indeterminable width.*/
if right(width,1)=='%' then do /*handle % of width. */
width=translate(width,,'%') /*remove the %*/
width=linesize() * translate(width,,"%")%100
end
if justify==''|justify==',' then justify='Left' /*Default? Use LEFT */
just=left(justify,1) /*only use first char of JUSTIFY.*/
upper just /*be able to handle mixed case. */
if pos(just,'BCLR')==0 then call err "JUSTIFY (3rd arg) is illegal:" justify
if _\=='' then call err "too many arguments specified." _
if \datatype(width,'W') then call err "WIDTH (2nd arg) isn't an integer:" width
n=0 /*number of words in the file. */
do j=0 while lines(iFID)\==0 /*read from the file until E-O-F.*/
_=linein(iFID) /*get a record (line of text). */
do words(_) /*extract some words (maybe not).*/
n=n+1; parse var _ @.n _ /*get & assign next word in text.*/
end /*DO words(_)*/
end /*j*/
/*REXX program reads a file and displays it to the screen (with word wrap). */
parse arg iFID width justify _ . /*obtain optional arguments from the CL*/
if iFID=='' | iFID=="," then iFID ='LAWS.TXT' /*Not specified? Then use the defaul.t*/
if width=='' |width=="," then width=linesize() /* " " " " " " */
if right(width, 1)=='%' then width=linesize() * translate(width, , "%") % 100
if justify==''|justify=="," then justify='Left' /*Default? Then use the default: LEFT */
just=left(justify, 1) /*only use first char of JUSTIFY. */
upper just /*be able to handle mixed case. */
if pos(just, 'BCLR')==0 then call err "JUSTIFY (3rd arg) is illegal:" justify
if _\=='' then call err "too many arguments specified." _
if \datatype(width,'W') then call err "WIDTH (2nd arg) isn't an integer:" width
n=0 /*the number of words in the file. */
do j=0 while lines(iFID)\==0 /*read from the file until End-Of-File.*/
_=linein(iFID) /*get a record (line of text). */
do until _==''; n=n+1 /*extract some words (or maybe not). */
parse var _ @.n _ /*obtain and assign next word in text. */
end /*DO until*/ /*parse 'til the line of text is null. */
end /*j*/
if j==0 then call err 'file' iFID "not found."
if n==0 then call err 'file' iFID "is empty (or has no words)"
$=@.1 /*init da money bag with 1st word*/
do m=2 for n-1; x=@.m /*parse until text (@) exhausted.*/
_=$ x /*append it to the money and see.*/
if length(_)>width then call tell /*this word a bridge too far? >w*/
$=_ /*the new words are OK so far. */
end /*m*/
call tell /*handle any residual words. */
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────ERR subroutine──────────────────────*/
err: say; say '***error!***'; say; say arg(1); say; say; exit 13
/*──────────────────────────────────TELL subroutine─────────────────────*/
tell: if $=='' then return /*first word may be too long. */
if just=='L' then $= strip($) /*left ◄────────*/
else do
w=max(width,length($)) /*don't truncate long words.*/
select
when just=='R' then $= right($,w) /*──────► right */
when just=='B' then $=justify($,w) /*◄────both────►*/
when just=='C' then $= center($,w) /* ◄centered► */
end /*select*/
end
say $ /*show and tell, or write──►file?*/
_=x /*handle any word overflow. */
return /*go back and keep truckin'. */
$=@.1 /*initialize $ string with first word*/
do m=2 for n-1; x=@.m /*parse until text (@) is exhausted. */
_=$ x /*append it to the $ string and test.*/
if length(_)>width then call tell /*this word a bridge too far? > w */
$=_ /*the new words are OK (so far). */
end /*m*/
call tell /*handle any residual words (if any). */
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
err: say; say '***error***'; say; say arg(1); say; say; exit 13
/*──────────────────────────────────────────────────────────────────────────────────────*/
tell: if $=='' then return /* [↓] the first word may be too long.*/
w=max(width, length($) ) /*don't truncate long words (> w). */
select
when just=='L' then $= strip($) /*left ◄──────── */
when just=='R' then $= right($,w) /*──────► right */
when just=='B' then $=justify($,w) /*◄────both────► */
when just=='C' then $= center($,w) /* ◄centered► */
end /*select*/
say $ /*display the line of words to terminal*/
_=x /*handle any word overflow. */
return /*go back and keep truckin'. */

View file

@ -1,11 +1,11 @@
class String
def wrap(width)
txt = gsub(/\s+/, " ")
txt = gsub("\n", " ")
para = []
i = 0
while i < txt.length
while i < length
j = i + width
j -= 1 while txt[j] != " "
j -= 1 while j != txt.length && j > i + 1 && !(txt[j] =~ /\s/)
para << txt[i ... j]
i = j + 1
end