Created
July 14, 2017 16:52
-
-
Save petemcfarlane/cc50ac6bc47d040fcda953abf98908c6 to your computer and use it in GitHub Desktop.
Exercise from part 2.25 of https://www.futurelearn.com/courses/functional-programming-erlang/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module (textprocessing). | |
-export ([input/0,format/2,format/3,squeezeWordsIntoLine/2,words/1,justify/2,wordsWithSpaces/3]). | |
input () -> | |
"The heat bloomed in December | |
as the carnival season | |
kicked into gear. | |
Nearly helpless with sun and glare, I avoided Rio's brilliant | |
sidewalks | |
and glittering beaches, | |
panting in dark corners | |
and waiting out the inverted southern summer.". | |
format(Text, LineLength) -> | |
Words = words(Text), | |
Lines = squeezeWordsIntoLine(Words, LineLength), | |
Out = string:join(Lines, "\n"), | |
io:format("~s~n",[Out]). | |
format(Text, LineLength, justify) -> | |
Words = words(Text), | |
Lines = squeezeWordsIntoLine(Words, LineLength), | |
Justified = lists:map(fun (Line) -> justify(Line, LineLength) end, Lines), | |
Out = string:join(Justified, "\n"), | |
io:format("~s~n",[Out]); | |
format(Text, LineLength, rightalign) -> | |
Words = words(Text), | |
Lines = squeezeWordsIntoLine(Words, LineLength), | |
RightAligned = lists:map(fun (Line) -> rightAlign(Line, LineLength) end, Lines), | |
Out = string:join(RightAligned, "\n"), | |
io:format("~s~n",[Out]); | |
format(Text, LineLength, center) -> | |
Words = words(Text), | |
Lines = squeezeWordsIntoLine(Words, LineLength), | |
Centered = lists:map(fun (Line) -> center(Line, LineLength) end, Lines), | |
Out = string:join(Centered, "\n"), | |
io:format("~s~n",[Out]). | |
words(Text) -> | |
string:lexemes(filterLinebreaks(Text), " "). | |
filterLinebreaks([]) -> | |
[]; | |
filterLinebreaks([$\n|Xs]) -> | |
[" " | filterLinebreaks(Xs)]; | |
filterLinebreaks([X|Xs]) -> | |
[X | filterLinebreaks(Xs)]. | |
squeezeWordsIntoLine([Word|Words], LineLength) -> | |
squeezeWordsIntoLine(Words, LineLength, Word). | |
squeezeWordsIntoLine([Word|Words], LineLength, Line) -> | |
case length(Line ++ " " ++ Word) =< LineLength of | |
true -> squeezeWordsIntoLine(Words, LineLength, Line ++ " " ++ Word); | |
false -> [Line] ++ squeezeWordsIntoLine(Words, LineLength, Word) | |
end; | |
squeezeWordsIntoLine([], _, Line) -> | |
[Line]. | |
wordsWithSpaces([], _SpacesPerWord, _Remainer) -> | |
[]; | |
wordsWithSpaces([Word], _SpacesPerWord, 0) -> | |
[Word]; | |
wordsWithSpaces([Word|Words], SpacesPerWord, 0) -> | |
[ Word,string:copies(" ", SpacesPerWord) | wordsWithSpaces(Words, SpacesPerWord, 0) ]; | |
wordsWithSpaces([Word|Words], SpacesPerWord, Remainder) -> | |
[ Word,string:copies(" ", SpacesPerWord+1) | wordsWithSpaces(Words, SpacesPerWord, Remainder-1) ]. | |
justify(Line, LineLength) when length(Line) == LineLength -> | |
Line; | |
justify(Line, LineLength) -> | |
Words = string:lexemes(Line, " "), | |
NumberOfWords = length(Words), | |
case NumberOfWords of | |
1 -> Line; | |
_ -> | |
WordsLength = lists:foldl(fun(Word, Acc) -> length(Word) + Acc end, 0, Words), | |
TotalSpacesNeeded = LineLength - WordsLength, | |
NumberOfWords = length(Words), | |
SpacesPerWord = TotalSpacesNeeded div (NumberOfWords - 1), | |
SpareSpaces = TotalSpacesNeeded rem (NumberOfWords - 1), | |
WordsWithSpaces = wordsWithSpaces(Words, SpacesPerWord, SpareSpaces), | |
string:join(WordsWithSpaces, "") | |
end. | |
rightAlign(Line, LineLength) -> | |
string:pad(Line, LineLength, leading). | |
center(Line, LineLength) -> | |
string:pad(Line, LineLength, both). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment