import strformat, strutils
import bignum

const Limit = 11_000

# Build list of primes using "nextPrime" function from "bignum".
var primes: seq[int]
var p = newInt(2)
while p < Limit:
  primes.add p.toInt
  p = p.nextPrime()

# Build list of factorials.
var facts: array[Limit, Int]
facts[0] = newInt(1)
for i in 1..<Limit:
  facts[i] = facts[i - 1] * i

var sign = 1
echo " n: Wilson primes"
echo "—————————————————"
for n in 1..11:
  sign = -sign
  var wilson: seq[int]
  for p in primes:
    if p < n: continue
    let f = facts[n - 1] * facts[p - n] - sign
    if f mod (p * p) == 0:
      wilson.add p
  echo &"{n:2}:  ", wilson.join(" ")


use strict;
use warnings;
use ntheory <primes factorial>;

my @primes = @{primes( 10500 )};

for my $n (1..11) {
    printf "%3d: %s\n", $n, join ' ', grep { $_ >= $n && 0 == (factorial($n-1) * factorial($_-$n) - (-1)**$n) % $_**2 } @primes
}


with javascript_semantics
constant limit = 11000
include mpfr.e
mpz f = mpz_init()
sequence primes = get_primes_le(limit),
         facts = mpz_inits(limit,1) -- (nb 0!==1!, same slot)
for i=2 to limit do mpz_mul_si(facts[i],facts[i-1],i) end for
integer sgn = 1
printf(1," n:  Wilson primes\n")
printf(1,"--------------------\n")
for n=1 to 11 do
    printf(1,"%2d:  ", n)
    sgn = -sgn
    for i=1 to length(primes) do
        integer p = primes[i]
        if p>=n then
            mpz_mul(f,facts[max(n-1,1)],facts[max(p-n,1)])
            mpz_sub_si(f,f,sgn)
            if mpz_divisible_ui_p(f,p*p) then
                printf(1,"%d ", p)
            end if
        end if
    end for
    printf(1,"\n")
end for


{def text
Personne n’a sans doute oublié le terrible coup de vent de nord-est qui se déchaîna au milieu de l’équinoxe de cette année, et pendant lequel le baromètre tomba à sept cent dix millimètres. Ce fut un ouragan, sans intermittence, qui dura du 18 au 26 mars. Les ravages qu’il produisit furent immenses en Amérique, en Europe, en Asie, sur une zone large de dix-huit cents milles, qui se dessinait obliquement à l’équateur, depuis le trente-cinquième parallèle nord jusqu’au quarantième parallèle sud ! (L’île mystérieuse / Jules Verne)}
-> text


define wordwrap(
    text::string,
    row_length::integer = 75
) => {
    return regexp(`(?is)(.{1,` + #row_length + `})(?:$|\W)+`, '$1
\n', #text, true) -> replaceall
}

local(text = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris consequat ornare lectus, dignissim iaculis libero consequat sed. Proin quis magna in arcu sagittis consequat sed ac risus. Ut a pharetra dui. Phasellus molestie, mauris eget scelerisque laoreet, diam dolor vulputate nulla, in porta sem sem sit amet lacus.')

wordwrap(#text, 40)
'
'
wordwrap(#text)
'
'
wordwrap(#text, 90)


(defun wrap-text (text)
  (wrap-text text 78))

(defun wrap-text (text max-len)
  (string:join
    (make-wrapped-lines
      (string:tokens text " ") max-len)
    "\n"))

(defun make-wrapped-lines
  (((cons word rest) max-len)
    (let ((`#(,_ ,_ ,last-line ,lines) (assemble-lines max-len word rest)))
      (lists:reverse (cons last-line lines)))))

(defun assemble-lines (max-len word rest)
  (lists:foldl
    #'assemble-line/2
    `#(,max-len ,(length word) ,word ())
    rest))

(defun assemble-line
  ((word `#(,max ,line-len ,line ,acc)) (when (> (+ (length word) line-len) max))
    `#(,max ,(length word) ,word ,(cons line acc)))
  ((word `#(,max ,line-len ,line ,acc))
    `#(,max ,(+ line-len 1 (length word)) ,(++ line " " word) ,acc)))


main:-
    wilson_primes(11000).

wilson_primes(Limit):-
    writeln('  n | Wilson primes\n---------------------'),
    make_factorials(Limit),
    find_prime_numbers(Limit),
    wilson_primes(1, 12, -1).

wilson_primes(N, N, _):-!.
wilson_primes(N, M, S):-
    wilson_primes(N, S),
    S1 is -S,
    N1 is N + 1,
    wilson_primes(N1, M, S1).

wilson_primes(N, S):-
    writef('%3r |', [N]),
    N1 is N - 1,
    factorial(N1, F1),
    is_prime(P),
    P >= N,
    PN is P - N,
    factorial(PN, F2),
    0 is (F1 * F2 - S) mod (P * P),
    writef(' %w', [P]),
    fail.
wilson_primes(_, _):-
    nl.

make_factorials(N):-
    retractall(factorial(_, _)),
    make_factorials(N, 0, 1).

make_factorials(N, N, F):-
    assert(factorial(N, F)),
    !.
make_factorials(N, M, F):-
    assert(factorial(M, F)),
    M1 is M + 1,
    F1 is F * M1,
    make_factorials(N, M1, F1).


#lang racket

(require math/number-theory)

(define ((wilson-prime? n) p)
  (and (>= p n)
       (prime? p)
       (divides? (sqr p)
                 (- (* (factorial (- n 1))
                       (factorial (- p n)))
                    (expt -1 n)))))

(define primes<11000 (filter prime? (range 1 11000)))

(for ((n (in-range 1 (add1 11))))
  (printf "~a: ~a~%" n (filter (wilson-prime? n) primes<11000)))


# Factorial
sub postfix:<!> (Int $n) { (constant f = 1, |[\×] 1..*)[$n] }

# Invisible times
sub infix:<> is tighter(&infix:<**>) { $^a * $^b };

# Prime the iterator for thread safety
sink 11000!;

my @primes = ^1.1e4 .grep: *.is-prime;

say
'  n: Wilson primes
────────────────────';

.say for (1..40).hyper(:1batch).map: -> \𝒏 {
    sprintf "%3d: %s", 𝒏, @primes.grep( -> \𝒑 { (𝒑 ≥ 𝒏) && ((𝒏 - 1)!(𝒑 - 𝒏)! - (-1) ** 𝒏) %% 𝒑² } ).Str
}


-- in some movie script

----------------------------------------
-- Wraps specified text into lines of specified width (in px), returns lines as list of strings
-- @param {string} str
-- @param {integer} pixelWidth
-- @param {propList} [style]
-- @return {list}
----------------------------------------
on hardWrapText (str, pixelWidth, style)
  if voidP(style) then style = [:]
  lines = []

  -- create a new field member
  m = new(#field)
  m.text = str
  m.rect = rect(0,0,pixelWidth,0)

  -- assign style props (if not specified, defaults are used)
  repeat with i = 1 to style.count
    m.setProp(style.getPropAt(i), style[i])
  end repeat

  -- create an invisible temporary sprite
  s = channel(1).makeScriptedSprite(m)
  s.loc = point(0,0)
  s.visible = false
  _movie.updateStage()

  -- get the wrapped lines
  charPos = 0
  repeat with y = 0 to s.height-1
    n = s.pointToChar(point(pixelWidth-1, y))
    if n<>charPos then
      lines.add(str.char[charPos+1..n])
      charPos = n
    end if
  end repeat

  channel(1).removeScriptedSprite()
  return lines
end


function splittokens(s)
    local res = {}
    for w in s:gmatch("%S+") do
        res[#res+1] = w
    end
    return res
end

function textwrap(text, linewidth)
    if not linewidth then
        linewidth = 75
    end

    local spaceleft = linewidth
    local res = {}
    local line = {}

    for _, word in ipairs(splittokens(text)) do
        if #word + 1 > spaceleft then
            table.insert(res, table.concat(line, ' '))
            line = {word}
            spaceleft = linewidth - #word
        else
            table.insert(line, word)
            spaceleft = spaceleft - (#word + 1)
        end
    end

    table.insert(res, table.concat(line, ' '))
    return table.concat(res, '\n')
end

local example1 = [[
Even today, with proportional fonts and complex layouts,
there are still cases where you need to wrap text at a
specified column. 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
minimum length greedy algorithm from Wikipedia.
]]

print(textwrap(example1))
print()
print(textwrap(example1, 60))


/*REXX program finds and displays Wilson primes:  a prime   P   such that  P**2 divides:*/
/*────────────────── (n-1)! * (P-n)!  -  (-1)**n   where  n  is 1 ──◄ 11,   and  P < 18.*/
parse arg oLO oHI hip .                          /*obtain optional argument from the CL.*/
if  oLO=='' |  oLO==","  then  oLO=      1       /*Not specified?  Then use the default.*/
if  oHI=='' |  oHI==","  then  oHI=     11       /* "      "         "   "   "     "    */
if  hip=='' |  hip==","  then  hip=  11000       /* "      "         "   "   "     "    */
call genP                                        /*build array of semaphores for primes.*/
!!.= .                                           /*define the  default  for factorials. */
bignum= !(hip)                                   /*calculate a ginormous factorial prod.*/
parse value bignum 'E0' with ex 'E' ex .         /*obtain possible exponent of factorial*/
numeric digits (max(9, ex+2) )                   /*calculate max # of dec. digits needed*/
call facts hip                                   /*go & calculate a number of factorials*/
title= ' Wilson primes  P  of order '  oLO " ──► " oHI',  where  P < '  commas(hip)
w= length(title) + 1                             /*width of columns of possible numbers.*/
say ' order │'center(title, w     )
say '───────┼'center(""   , w, '─')
      do n=oLO  to oHI;  nf= !(n-1)              /*precalculate a factorial product.    */
      z= -1**n                                   /*     "       " plus or minus (+1│-1).*/
      if n==1   then lim= 103                    /*limit to known primes for 1st order. */
                else lim=   #                    /*  "    "  all     "    "  orders ≥ 2.*/
      $=                                         /*$:  a line (output) of Wilson primes.*/
         do j=1  for lim;    p= @.j              /*search through some generated primes.*/
         if (nf*!(p-n)-z)//sq.j\==0 then iterate /*expression ~ q.j ?  No, then skip it.*/       /* ◄■■■■■■■ the filter.*/
         $= $  ' '  commas(p)                    /*add a commatized prime  ──►  $  list.*/
         end   /*p*/

      if $==''  then $= '        (none found within the range specified)'
      say center(n, 7)'│'  substr($, 2)          /*display what Wilson primes we found. */
      end   /*n*/
say '───────┴'center(""   , w, '─')
exit 0                                           /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
!:      arg x; if !!.x\==.  then return !!.x;  a=1;  do f=1  for x;   a=a*f; end; return a
commas: parse arg ?;  do jc=length(?)-3  to 1  by -3; ?=insert(',', ?, jc); end;  return ?
facts:  !!.= 1;   x= 1;  do  f=1  for hip;   x= x * f;   !!.f= x;           end;  return
/*──────────────────────────────────────────────────────────────────────────────────────*/
genP:        @.1=2; @.2=3; @.3=5; @.4=7;  @.5=11 /*define some low primes.              */
      !.=0;  !.2=1; !.3=1; !.5=1; !.7=1;  !.11=1 /*   "     "   "    "     semaphores.  */
      sq.1=4; sq.2=9; sq.3= 25; sq.4= 49; #= 5;  sq.#= @.#**2   /*squares of low primes.*/
        do [email protected].#+2  by 2  for max(0, hip%[email protected].#%2-1)     /*find odd primes from here on. */
        parse var  j   ''  -1  _;  if    _==5  then iterate    /*J ÷ 5?   (right digit).*/
        if j//3==0  then iterate;  if j//7==0  then iterate    /*" " 3?    Is J ÷ by 7? */
               do k=5  while sq.k<=j             /* [↓]  divide by the known odd primes.*/
               if j // @.k == 0  then iterate j  /*Is  J ÷ X?  Then not prime.     ___  */
               end   /*k*/                       /* [↑]  only process numbers  ≤  √ J   */
        #= #+1;    @.#= j;    sq.#= j*j;  !.j= 1 /*bump # of Ps; assign next P;  P²; P# */
        end          /*j*/;               return


Module Checkit {
      \\ leading space from begin of paragraph stay as is
      a$={     In olden times when wishing still helped one, there
      lived a king whose daughters were all beautiful, but the youngest
      was so beautiful that the sun itself, which has seen so
      much, was astonished whenever it shone in her face.
      }
      const crlf$=chr$(13)+chr$(10)
      a$=replace$(crlf$, " ", a$)+crlf$
      const justify=0
      const flushright=1
      const centered=2
      const flushleft=3
      \\ set layer font
      Font "Tahoma"
      Form 80, 50
      Print "Font:";Fontname$
      Print "Font size:";Mode;"pt"
      Print "Bold:";Bold
      Print "Italic:";Italic
      \\ set left margin for Report
      Cursor 10, 8 ' pos 10 row 8 (11 9 - it is 0 based)
      m=Italic
      Italic 1
      Report centered, trim$(A$), Width-10-10
      Italic m

      Print  @(0,79),"Press any key";
      wait$=key$
      Refresh 5000
      charwidth=scale.x div width
      For i=2000 to scale.x-charwidth step 150
            \\ clear screen with 14pt fonts

            Mode 12.75
            \\ by default use justify, word wrap
            Report a$, i
            \\  we can calculate only using a negative parameter
            Report a$, i, -10000
            k=ReportLines
            \\ print any line in differnet color
            Dim a(2)
            a(0)=11, 15   ' 0 to 15 are vb6 colors, we can use html colors #aabbcc, #ff2211
            For j=1 to k {
                Pen a(j mod 2) {
                        Report a$, i, 1 line j
                  }
            }
            Refresh 5000
            wait$=key$
      Next i

      Report a$, scale.x/2, -1000
      k=ReportLines
      Document  Doc$
      Report a$, scale.x/2, k as Doc$
      \\ Print document without expanding spaces
      Print $(4), ' 4=proportional printing using columns, on line online, word wrap, expand to fit in columns
      For i=1 to k {
      Print "*";Paragraph$(Doc$, i);"*"
      }
      Print $(0),   ' restore to non proportional printing
      For i=1 to k {
            Print i, size.x(Paragraph$(Doc$, i), Fontname$, Mode), size.y(Paragraph$(Doc$, i), Fontname$, Mode)
      }
      \\ scale.x unit in twips
      Report a$, scale.x/2
      \\ width unit in characters
      Report a$, width/2
      Print @(width div 2),
      Report flushright, a$, width/2
      Cursor 0, Row
      I=Italic
      Double
      Italic 1
      Report centered, a$
      Italic I
      Double
      Normal
}
Checkit


string="In olden times when wishing still helped one, there lived a king whose daughters were all beautiful, but the youngest was so beautiful that the sun itself, which has seen so much, was astonished whenever it shone in her face.  Close by the king's castle lay a great dark forest, and under an old lime-tree in the forest was a well, and when the day was very warm, the king's child went out into the forest and sat down by the side of the cool fountain, and when she was bored she took a golden ball, and threw it up on high and caught it, and this ball was her favorite plaything.";
wordWrap[textWidth_,spaceWidth_,string_]:=Module[{start,spaceLeft,masterString},
 spaceLeft=textWidth;
 start=1;
 masterString={};
 Do[
  If[i+1>[email protected]@string
   ,
   p=StringSplit[string][[start;;i]];
   AppendTo[masterString,{[email protected]@Riffle[p,[email protected][" ",spaceWidth]]}]
   ,
   If[StringLength[[email protected]][[i+1]]+spaceWidth>spaceLeft
     ,
     spaceLeft=textWidth-StringLength[[email protected]][[i]];
     start=i;
     AppendTo[masterString,{[email protected]@Riffle[p,[email protected][" ",spaceWidth]]}]
     ,
     spaceLeft-=StringLength[[email protected]][[i]];
     spaceLeft-=spaceWidth;
     p=StringSplit[string][[start;;i]]
    ]
   ]
  ,
  {i,1,[email protected]@string}
 ];
 [email protected]@Riffle[masterString,"\n"]
];


str = "one two three four five six seven eight nine ten eleven!"
width = 15
words = str.split
pos = 0
line = ""
for word in words
    pos = pos + word.len + 1
    if pos <= width then
        line = line + word + " "
    else
        print line[:-1]
        line = word + " "
        pos = word.len
    end if
end for
print line[:-1]


/* NetRexx */
options replace format comments java crossref symbols

runSample(arg)
return

-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/*
   @see http://en.wikipedia.org/wiki/Word_wrap#Minimum_length

   SpaceLeft := LineWidth
   for each Word in Text
       if (Width(Word) + SpaceWidth) > SpaceLeft
           insert line break before Word in Text
           SpaceLeft := LineWidth - Width(Word)
       else
           SpaceLeft := SpaceLeft - (Width(Word) + SpaceWidth)
 */
method wordWrap(text, lineWidth = 80) public static
  if lineWidth > 0 then do
    NL = '\n'
    SP = ' '
    wrapped = ''
    spaceWidth = SP.length()
    spaceLeft = lineWidth
    loop w_ = 1 to text.words()
      nextWord = text.word(w_)
      if (nextWord.length() + spaceWidth) > spaceLeft then do
        wrapped = wrapped || NL || nextWord
        spaceLeft = lineWidth - nextWord.length()
        end
      else do
        wrapped = wrapped || SP || nextWord
        spaceLeft = spaceLeft - (nextWord.length() + spaceWidth)
        end
      end w_
    end
  else do
    wrapped = text
    end

  return wrapped.strip() -- clean w/s from front & back

-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method runSample(arg) public static
  parse arg lineLen .
  if lineLen  = '' then lineLen = 80
  text = getText()
  wrappedLines = wordWrap(text, lineLen)
  say 'Wrapping text at' lineLen 'characters'
  say ('....+....|'.copies((lineLen + 9) % 10)).left(lineLen)
  say wrappedLines

  return

-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method getText() public static

  -- ....+....|....+....|....+....|....+....|....+....|....+....|
  speech01 = -
    'She should have died hereafter;' -
    'There would have been a time for such a word.' -
    'Tomorrow, and tomorrow, and tomorrow,' -
    'Creeps in this petty pace from day to day,' -
    'To the last syllable of recorded time;' -
    'And all our yesterdays have lighted fools' -
    'The way to dusty death. Out, out, brief candle!' -
    'Life''s but a walking shadow, a poor player' -
    'That struts and frets his hour upon the stage' -
    'And then is heard no more. It is a tale' -
    'Told by an idiot, full of sound and fury' -
    'Signifying nothing.' -
    '' -
    '—-Macbeth (Act 5, Scene 5, lines 17-28)' -
    ''
  return speech01


DefaultDict[String, Int] cnt
L(word) re:‘\w+’.find_strings(File(‘135-0.txt’).read().lowercase())
   cnt[word]++
print(sorted(cnt.items(), key' wordc -> wordc[1], reverse' 1B)[0.<10])


require "prime"

module Modulo
  refine Integer do
    def factorial_mod(m) = (1..self).inject(1){|prod, n| (prod *= n) % m }
  end
end

using Modulo
primes = Prime.each(11000).to_a

(1..11).each do |n|
  res = primes.select do |pr|
    prpr = pr*pr
    ((n-1).factorial_mod(prpr) * (pr-n).factorial_mod(prpr) - (-1)**n) % (prpr) == 0
  end
  puts "#{n.to_s.rjust(2)}: #{res.inspect}"
end


// [dependencies]
// rug = "1.13.0"

use rug::Integer;

fn generate_primes(limit: usize) -> Vec<usize> {
    let mut sieve = vec![true; limit >> 1];
    let mut p = 3;
    let mut sq = p * p;
    while sq < limit {
        if sieve[p >> 1] {
            let mut q = sq;
            while q < limit {
                sieve[q >> 1] = false;
                q += p << 1;
            }
        }
        sq += (p + 1) << 2;
        p += 2;
    }
    let mut primes = Vec::new();
    if limit > 2 {
        primes.push(2);
    }
    for i in 1..sieve.len() {
        if sieve[i] {
            primes.push((i << 1) + 1);
        }
    }
    primes
}

fn factorials(limit: usize) -> Vec<Integer> {
    let mut f = vec![Integer::from(1)];
    let mut factorial = Integer::from(1);
    f.reserve(limit);
    for i in 1..limit {
        factorial *= i as u64;
        f.push(factorial.clone());
    }
    f
}

fn main() {
    let limit = 11000;
    let f = factorials(limit);
    let primes = generate_primes(limit);
    println!(" n | Wilson primes\n--------------------");
    let mut s = -1;
    for n in 1..=11 {
        print!("{:2} |", n);
        for p in &primes {
            if *p >= n {
                let mut num = Integer::from(&f[n - 1] * &f[*p - n]);
                num -= s;
                if num % ((p * p) as u64) == 0 {
                    print!(" {}", p);
                }
            }
        }
        println!();
        s = -s;
    }
}


func is_wilson_prime(p, n = 1) {
    var m = p*p
    (factorialmod(n-1, m) * factorialmod(p-n, m) - (-1)**n) % m == 0
}

var primes = 1.1e4.primes

say "  n: Wilson primes\n────────────────────"

for n in (1..11) {
    printf("%3d: %s\n", n, primes.grep {|p| is_wilson_prime(p, n) })
}


import "/math" for Int
import "/big" for BigInt
import "/fmt" for Fmt

var limit = 11000
var primes = Int.primeSieve(limit)
var facts = List.filled(limit, null)
facts[0] = BigInt.one
for (i in 1...11000) facts[i] = facts[i-1] * i
var sign = 1
System.print(" n:  Wilson primes")
System.print("--------------------")
for (n in 1..11) {
    Fmt.write("$2d:  ", n)
    sign = -sign
    for (p in primes) {
        if (p < n) continue
        var f = facts[n-1] * facts[p-n] - sign
        if (f.isDivisibleBy(p*p)) Fmt.write("%(p) ", p)
    }
    System.print()
}


import std/wordwrap

let txt = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur."
echo txt.wrapWords()
echo ""
echo txt.wrapWords(45)


#load "str.cma"

let txt = "In olden times when wishing still helped one, there lived
a king whose daughters were all beautiful, but the youngest was so
beautiful that the sun itself, which has seen so much, was astonished
whenever it shone in her face.  Close by the king's castle lay a great
dark forest, and under an old lime-tree in the forest was a well, and
when the day was very warm, the king's child went out into the forest
and sat down by the side of the cool fountain, and when she was bored
she took a golden ball, and threw it up on high and caught it, and
this ball was her favorite plaything."

let () =
  let line_width = int_of_string Sys.argv.(1) in
  let words = Str.split (Str.regexp "[ \n]+") txt in
  let buf = Buffer.create 10 in
  let _ =
    List.fold_left (fun (width, sep) word ->
      let wlen = String.length word in
      let len = width + wlen + 1 in
      if len > line_width then
      begin
        Buffer.add_char buf '\n';
        Buffer.add_string buf word;
        (wlen, " ")
      end else begin
        Buffer.add_string buf sep;
        Buffer.add_string buf word;
        (len, " ")
      end
    ) (0, "") words
  in
  print_endline (Buffer.contents buf)


with Ada.Command_Line;
with Ada.Text_IO;
with Ada.Integer_Text_IO;
with Ada.Strings.Maps;
with Ada.Strings.Fixed;
with Ada.Characters.Handling;
with Ada.Containers.Indefinite_Ordered_Maps;
with Ada.Containers.Indefinite_Ordered_Sets;
with Ada.Containers.Ordered_Maps;

procedure Word_Frequency is
    package TIO renames Ada.Text_IO;

    package String_Counters is new Ada.Containers.Indefinite_Ordered_Maps(String, Natural);
    package String_Sets is new Ada.Containers.Indefinite_Ordered_Sets(String);
    package Sorted_Counters is new Ada.Containers.Ordered_Maps
      (Natural,
       String_Sets.Set,
       "=" => String_Sets."=",
       "<" => ">");
    -- for sorting by decreasing number of occurrences and ascending lexical order

    procedure Increment(Key : in String; Element : in out Natural) is
    begin
        Element := Element + 1;
    end Increment;

    path : constant String := Ada.Command_Line.Argument(1);
    how_many : Natural := 10;
    set : constant Ada.Strings.Maps.Character_Set := Ada.Strings.Maps.To_Set(ranges => (('a', 'z'), ('0', '9')));
    F : TIO.File_Type;
    first : Positive;
    last : Natural;
    from : Positive;
    counter : String_Counters.Map;
    sorted_counts : Sorted_Counters.Map;
    C1 : String_Counters.Cursor;
    C2 : Sorted_Counters.Cursor;
    tmp_set : String_Sets.Set;
begin
    -- read file and count words
    TIO.Open(F, name => path, mode => TIO.In_File);
    while not TIO.End_Of_File(F) loop
       declare
          line : constant String := Ada.Characters.Handling.To_Lower(TIO.Get_Line(F));
       begin
          from := line'First;
          loop
             Ada.Strings.Fixed.Find_Token(line(from .. line'Last), set, Ada.Strings.Inside, first, last);
             exit when last < First;
             C1 := counter.Find(line(first .. last));
             if String_Counters.Has_Element(C1) then
                counter.Update_Element(C1, Increment'Access);
             else
                counter.Insert(line(first .. last), 1);
             end if;
             from := last + 1;
          end loop;
       end;
    end loop;
    TIO.Close(F);

    -- fill Natural -> StringSet Map
    C1 := counter.First;
    while String_Counters.Has_Element(C1) loop
       if sorted_counts.Contains(String_Counters.Element(C1)) then
          tmp_set := sorted_counts.Element(String_Counters.Element(C1));
          tmp_set.Include(String_Counters.Key(C1));
       else
          sorted_counts.Include(String_Counters.Element(C1), String_Sets.To_Set(String_Counters.Key(C1)));
       end if;
       String_Counters.Next(C1);
    end loop;

    -- output
    C2 := sorted_counts.First;
    while Sorted_Counters.Has_Element(C2) loop
       for Item of Sorted_Counters.Element(C2) loop
          Ada.Integer_Text_IO.Put(TIO.Standard_Output, Sorted_Counters.Key(C2), width => 9);
          TIO.Put(TIO.Standard_Output, " ");
          TIO.Put_Line(Item);
       end loop;
       Sorted_Counters.Next(C2);
       how_many := how_many - 1;
       exit when how_many = 0;
    end loop;
end Word_Frequency;


(define (get-one-word start)
(let loop ((chars #null) (end start))
   (let ((char (car end)))
      (if (has? (list #\space #\newline) char)
         (values (reverse chars) (force (cdr end)))
         (loop (cons char chars) (force (cdr end)))))))

(define (get-all-words string)
(let loop ((words #null) (start (str-iter string)))
   (let* ((word next (get-one-word start)))
      (if (null? next)
         (reverse words)
         (loop (cons (runes->string word) words) next)))))

(define (get-one-line words n)
(let loop ((line #null) (words words) (i 0))
   (let*((word (car words))
         (len (string-length word)))
      (if (null? (cdr words))
         (values (reverse (cons word line)) #null)
         (if (> (+ i len) n 1)
            (values (reverse line) words)
            (loop (cons word line) (cdr words) (+ i len 1)))))))

(define (get-all-lines words n)
(let loop ((lines #null) (words words))
   (let* ((line words (get-one-line words n)))
      (if (null? words)
         (reverse (cons line lines))
         (loop (cons line lines) words)))))

(define (hyphenation width string)
(let*((words (get-all-words string))
      (lines (get-all-lines words width)))
   lines))


# find the n most common words in a file                             #
# use the associative array in the Associate array/iteration task    #
# but with integer values                                            #
PR read "aArrayBase.a68" PR
MODE AAKEY   = STRING;
MODE AAVALUE = INT;
AAVALUE init element value = 0;
# returns text converted to upper case                                 #
OP   TOUPPER  = ( STRING text )STRING:
     BEGIN
        STRING result := text;
        FOR ch pos FROM LWB result TO UPB result DO
            IF is lower( result[ ch pos ] ) THEN result[ ch pos ] := to upper( result[ ch pos ] ) FI
        OD;
        result
     END # TOUPPER # ;
# returns text converted to an INT or -1 if text is not a number     #
OP   TOINT    = ( STRING text )INT:
     BEGIN
        INT  result     := 0;
        BOOL is numeric := TRUE;
        FOR ch pos FROM UPB text BY -1 TO LWB text WHILE is numeric DO
            CHAR c = text[ ch pos ];
            is numeric := is numeric AND c >= "0" AND c <= "9";
            IF is numeric THEN ( result *:= 10 ) +:= ABS c - ABS "0" FI
        OD;
        IF is numeric THEN result ELSE -1 FI
     END # TOINT # ;
# returns TRUE if c is a letter, FALSE otherwise                     #
OP   ISLETTER    = ( CHAR c )BOOL:
        IF ( c >= "a" AND c <= "z" )
        OR ( c >= "A" AND c <= "Z" )
        THEN TRUE
        ELSE char in string( c, NIL, "ÇåçêëÆôöÿÖØáóÔ" )
        FI # ISLETER # ;
# get the file name and number of words from then commmand line      #
STRING file name       := "pg-les-misrables.txt";
INT    number of words := 10;
FOR arg pos TO argc - 1 DO
    STRING arg upper = TOUPPER argv( arg pos );
    IF   arg upper = "FILE"   THEN
        file name := argv( arg pos + 1 )
    ELIF arg upper  = "NUMBER" THEN
        number of words := TOINT argv( arg pos + 1 )
    FI
OD;
IF  FILE input file;
    open( input file, file name, stand in channel ) /= 0
THEN
    # failed to open the file #
    print( ( "Unable to open """ + file name + """", newline ) )
ELSE
    # file opened OK #
    print( ( "Processing: ", file name, newline ) );
    BOOL at eof := FALSE;
    BOOL at eol := FALSE;
    # set the EOF handler for the file #
    on logical file end( input file, ( REF FILE f )BOOL:
                                     BEGIN
                                         # note that we reached EOF on the #
                                         # latest read #
                                         at eof := TRUE;
                                         # return TRUE so processing can continue #
                                         TRUE
                                     END
                       );
    # set the end-of-line handler for the file so get word can see line boundaries #
    on line end( input file
               , ( REF FILE f )BOOL:
                 BEGIN
                     # note we reached end-of-line #
                     at eol := TRUE;
                     # return FALSE to use the default eol handling  #
                     # i.e. just get the next charactefr             #
                     FALSE
                 END
               );
    # get the words from the file and store the counts in an associative array #
    REF AARRAY words := INIT LOC AARRAY;
    INT word count := 0;
    CHAR c := " ";
    WHILE get( input file, ( c ) );
          NOT at eof
    DO
        WHILE NOT ISLETTER c AND NOT at eof DO get( input file, ( c ) ) OD;
        STRING word := "";
        at eol      := FALSE;
        WHILE ISLETTER c AND NOT at eol AND NOT at eof DO word +:= c; get( input file, ( c ) ) OD;
        word count +:= 1;
        words // TOUPPER word +:= 1
    OD;
    close( input file );
    print( ( file name, " contains ", whole( word count, 0 ), " words", newline ) );
    # find the most used words                                       #
    [ number of words ]STRING top words;
    [ number of words ]INT    top counts;
    FOR i TO number of words DO top words[ i ] := ""; top counts[ i ] := 0 OD;
    REF AAELEMENT w := FIRST words;
    WHILE w ISNT nil element DO
        INT    count  = value OF w;
        STRING word   = key   OF w;
        BOOL   found := FALSE;
        FOR i TO number of words WHILE NOT found DO
            IF count > top counts[ i ] THEN
                # found a word that is used nore than a current      #
                # most used word                                     #
                found := TRUE;
                # move the other words down one place                #
                FOR move pos FROM number of words BY - 1 TO i + 1 DO
                    top counts[ move pos ] := top counts[ move pos - 1 ];
                    top words [ move pos ] := top words [ move pos - 1 ]
                OD;
                # install the new word                               #
                top counts[ i ] := count;
                top words [ i ] := word
            FI
        OD;
        w := NEXT words
    OD;
    print( ( whole( number of words, 0 ), " most used words:", newline ) );
    print( ( " count  word", newline ) );
    FOR i TO number of words DO
        print( ( whole( top counts[ i ], -6 ), ": ", top words[ i ], newline ) )
    OD
FI


wrap(s,len)={
  my(t="",cur);
  s=Vec(s);
  for(i=1,#s,
    if(s[i]==" ",
      if(cur>#t,
        print1(" "t);
        cur-=#t+1
      ,
        print1("\n"t);
        cur=len-#t
      );
      t=""
    ,
      t=concat(t,s[i])
    )
  );
  if(cur>#t,
    print1(" "t)
  ,
    print1("\n"t)
  )
};
King="And so let freedom ring from the prodigious hilltops of New Hampshire; let freedom ring from the mighty mountains of New York; let freedom ring from the heightening Alleghenies of Pennsylvania; let freedom ring from the snow-capped Rockies of Colorado; let freedom ring from the curvaceous slopes of California. But not only that: let freedom ring from Stone Mountain of Georgia; let freedom ring from Lookout Mountain of Tennessee; let freedom ring from every hill and molehill of Mississippi. From every mountainside, let freedom ring.";
wrap(King, 75)
wrap(King, 50)


my $s = "In olden times when wishing still helped one, there lived a king
whose daughters were all beautiful, but the youngest was so beautiful
that the sun itself, which has seen so much, was astonished whenever
it shone in her face.  Close-by-the-king's-castle-lay-a-great-dark
forest, and under an old lime-tree in the forest was a well, and when
the day was very warm, the king's child went out into the forest and
sat down by the side of the cool fountain, and when she was bored she
took a golden ball, and threw it up on high and caught it, and this
ball was her favorite plaything.";

$s =~ s/\b\s+/ /g;
$s =~ s/\s*$/\n\n/;

my $_ = $s;
s/\s*(.{1,66})\s/$1\n/g, print;

$_ = $s;
s/\s*(.{1,25})\s/$1\n/g, print;


⍝⍝ NOTE: input text is assumed to be encoded in ISO-8859-1
⍝⍝ (The suggested example '135-0.txt' of Les Miserables on
⍝⍝ Project Gutenberg is in UTF-8.)
⍝⍝
⍝⍝ Use Unix 'iconv' if required
⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝
∇r ← lowerAndStrip s;stripped;mixedCase
 ⍝⍝ Convert text to lowercase, punctuation and newlines to spaces
 stripped ← '               abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz*'
 mixedCase ← ⎕av[11],' ,.?!;:"''()[]-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
 r ← stripped[mixedCase ⍳ s]
∇

⍝⍝ Return the _n_ most frequent words and a count of their occurrences
⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝
∇r ← n wordCount fname ;D;wl;sidx;swv;pv;wc;uw;sortOrder
  D ← lowerAndStrip (⎕fio['read_file'] fname)  ⍝ raw text with newlines
  wl ← (~ D ∊ ' ') ⊂ D
  sidx ← ⍒wl
  swv ← wl[sidx]
  pv ← +\ 1,~2 ≡/ swv
  wc ← ∊ ⍴¨ pv ⊂ pv
  uw ← 1 ⊃¨ pv ⊂ swv
  sortOrder ← ⍒wc
  r ← n↑[2] uw[sortOrder],[0.5]wc[sortOrder]
∇

      5 wordCount '135-0.txt'
   the    of   and     a    to
 41042 19952 14938 14526 13942


(*
    For simplicity here, words are considered to be uninterrupted sequences of letters and/or digits.
    The set text is too messy to warrant faffing around with anything more sophisticated.
    The first letter in each word is upper-cased and the rest lower-cased for case equivalence and presentation.
    Where more than n words qualify for the top n or fewer places, all are included in the result.
*)

use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or later
use framework "Foundation"
use scripting additions

on wordFrequency(filePath, n)
    set |⌘| to current application

    -- Get the text and "capitalize" it (lower-case except for the first letters in words).
    set theText to |⌘|'s class "NSString"'s stringWithContentsOfFile:(filePath) usedEncoding:(missing value) |error|:(missing value)
    set theText to theText's capitalizedStringWithLocale:(|⌘|'s class "NSLocale"'s currentLocale()) -- Yosemite compatible.
    -- Split it at the non-word characters.
    set nonWordCharacters to |⌘|'s class "NSCharacterSet"'s alphanumericCharacterSet()'s invertedSet()
    set theWords to theText's componentsSeparatedByCharactersInSet:(nonWordCharacters)

    -- Use a counted set to count the individual words' occurrences.
    set countedSet to |⌘|'s class "NSCountedSet"'s alloc()'s initWithArray:(theWords)

    -- Build a list of word/frequency records, excluding any empty strings left over from the splitting above.
    set mutableSet to |⌘|'s class "NSMutableSet"'s setWithSet:(countedSet)
    tell mutableSet to removeObject:("")
    script o
        property discreteWords : mutableSet's allObjects() as list
        property wordsAndFrequencies : {}
    end script
    set discreteWordCount to (count o's discreteWords)
    repeat with i from 1 to discreteWordCount
        set thisWord to item i of o's discreteWords
        set end of o's wordsAndFrequencies to {thisWord:thisWord, frequency:(countedSet's countForObject:(thisWord)) as integer}
    end repeat

    -- Convert to NSMutableArray, reverse-sort the result on the frequencies, and convert back to list.
    set wordsAndFrequencies to |⌘|'s class "NSMutableArray"'s arrayWithArray:(o's wordsAndFrequencies)
    set descendingByFrequency to |⌘|'s class "NSSortDescriptor"'s sortDescriptorWithKey:("frequency") ascending:(false)
    tell wordsAndFrequencies to sortUsingDescriptors:({descendingByFrequency})
    set o's wordsAndFrequencies to wordsAndFrequencies as list

    if (discreteWordCount > n) then
        -- If there are more than n records, check for any immediately following the nth which may have the same frequency as it.
        set nthHighestFrequency to frequency of item n of o's wordsAndFrequencies
        set qualifierCount to n
        repeat with i from (n + 1) to discreteWordCount
            if (frequency of item i of o's wordsAndFrequencies = nthHighestFrequency) then
                set qualifierCount to i
            else
                exit repeat
            end if
        end repeat
    else
        -- Otherwise reduce n to the actual number of discrete words.
        set n to discreteWordCount
        set qualifierCount to discreteWordCount
    end if

    -- Compose a text report from the qualifying words and frequencies.
    if (qualifierCount = n) then
        set output to {"The " & n & " most frequently occurring words in the file are:"}
    else
        set output to {(qualifierCount as text) & " words share the " & ((n as text) & " highest frequencies in the file:")}
    end if
    repeat with i from 1 to qualifierCount
        set {thisWord:thisWord, frequency:frequency} to item i of o's wordsAndFrequencies
        set end of output to thisWord & ":      " & (tab & frequency)
    end repeat
    set astid to AppleScript's text item delimiters
    set AppleScript's text item delimiters to linefeed
    set output to output as text
    set AppleScript's text item delimiters to astid

    return output
end wordFrequency

-- Test code:
set filePath to POSIX path of ((path to desktop as text) & "www.rosettacode.org:Word frequency:135-0.txt")
set n to 10
return wordFrequency(filePath, n)


string s = substitute("""In olden times when wishing still helped one, there lived a king
whose daughters were all beautiful, but the youngest was so beautiful that the sun itself,
which has seen so much, was astonished whenever it shone in her face. Close by the king's
castle lay a great dark forest, and under an old lime-tree in the forest was a well, and
when the day was very warm, the king's child went out into the forest and sat down by the
side of the cool fountain, and when she was bored she took a golden ball, and threw it up
on high and caught it, and this ball was her favorite plaything.""","\n"," ")

procedure word_wrap(string s, integer maxwidth)
    sequence words = split(s)
    string line = words[1]
    for i=2 to length(words) do
        string word = words[i]
        if length(line)+length(word)+1>maxwidth then
            puts(1,line&"\n")
            line = word
        else
            line &= " "&word
        end if
    end for
    puts(1,line&"\n")
end procedure

word_wrap(s,72)
word_wrap(s,80)


include ..\Utilitys.pmt

72 var long
0 >ps

"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas varius sapien
vel purus hendrerit vehicula. Integer hendrerit viverra turpis, ac sagittis arcu
pharetra id. Sed dapibus enim non dui posuere sit amet rhoncus tellus
consectetur. Proin blandit lacus vitae nibh tincidunt cursus. Cum sociis natoque
penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nam tincidunt
purus at tortor tincidunt et aliquam dui gravida. Nulla consectetur sem vel
felis vulputate et imperdiet orci pharetra. Nam vel tortor nisi. Sed eget porta
tortor. Aliquam suscipit lacus vel odio faucibus tempor. Sed ipsum est,
condimentum eget eleifend ac, ultricies non dui. Integer tempus, nunc sed
venenatis feugiat, augue orci pellentesque risus, nec pretium lacus enim eu
nibh."

split
len for drop
    pop swap len ps> + >ps
    tps long > if ps> drop len >ps nl endif
    print " " print
    ps> 1 + >ps
endfor
drop ps> drop


findFrequency: function [file, count][
    freqs: #[]
    r: {/[[:alpha:]]+/}
    loop flatten map split.lines read file 'l -> match lower l r 'word [
        if not? key? freqs word -> freqs\[word]: 0
        freqs\[word]: freqs\[word] + 1
    ]
    freqs: sort.values.descending freqs
    result: new []
    loop 0..dec count 'x [
        'result ++ @[@[get keys freqs x, get values freqs x]]
    ]
    return result
]

loop findFrequency "https://www.gutenberg.org/files/135/135-0.txt" 10 'pair [
    print pair
]


URLDownloadToFile, http://www.gutenberg.org/files/135/135-0.txt, % A_temp "\tempfile.txt"
FileRead, H, % A_temp "\tempfile.txt"
FileDelete,  % A_temp "\tempfile.txt"
words := []
while pos := RegExMatch(H, "\b[[:alpha:]]+\b", m, A_Index=1?1:pos+StrLen(m))
	words[m] := words[m] ? words[m] + 1 : 1
for word, count in words
	list .= count "`t" word "`r`n"
Sort, list, RN
loop, parse, list, `n, `r
{
	result .= A_LoopField "`r`n"
	if A_Index = 10
		break
}
MsgBox % "Freq`tWord`n" result
return


<?php

$text = <<<ENDTXT
If there's anything you need
All you have to do is say
You know you satisfy everything in me
We shouldn't waste a single day

So don't stop me falling
It's destiny calling
A power I just can't deny
It's never changing
Can't you hear me, I'm saying
I want you for the rest of my life

Together forever and never to part
Together forever we two
And don't you know
I would move heaven and earth
To be together forever with you
ENDTXT;

// remove preexisting line breaks
$text = str_replace( PHP_EOL,  " " , $text );

echo wordwrap( $text, 20 ), PHP_EOL, PHP_EOL;

echo wordwrap( $text, 40 ), PHP_EOL, PHP_EOL;

echo wordwrap( $text, 80 ), PHP_EOL, PHP_EOL;


import util.

go =>
  text(1,Text),
  foreach(LineWidth in [60,80])
     println(lineWidth=LineWidth),
     println(wrap(Text,LineWidth)),
     nl
  end,
  nl.

wrap(Text,LineWidth) = Wrapped =>
  Words = Text.split(),
  Wrapped = Words[1],
  SpaceLeft = LineWidth - Wrapped.len,
  foreach(Word in Words.tail)
    WordLen = Word.length,
    if (WordLen + 1) > SpaceLeft then
      Wrapped := Wrapped ++ "\n" ++ Word,
      SpaceLeft := LineWidth - WordLen
    else
      Wrapped := Wrapped ++ " " ++ Word,
      SpaceLeft := SpaceLeft - WordLen - 1
    end
  end.

text(1,"Lorem ipsum dolor sit amet, consectetur adipiscing
elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est
laborum.").


# syntax: GAWK -f WORD_FREQUENCY.AWK [-v show=x] LES_MISERABLES.TXT
#
# A word is anything separated by white space.
# Therefor "this" and "this." are different.
# But "This" and "this" are identical.
# As I am "free to define what a letter is" I have chosen to allow
# numerics and all special characters as they are usually considered
# parts of words in text processing applications.
#
{   nbytes += length($0) + 2 # +2 for CR/LF
    nfields += NF
    $0 = tolower($0)
    for (i=1; i<=NF; i++) {
      arr[$i]++
    }
}
END {
    show = (show == "") ? 10 : show
    width1 = length(show)
    PROCINFO["sorted_in"] = "@val_num_desc"
    for (i in arr) {
      if (width2 == 0) { width2 = length(arr[i]) }
      if (n++ >= show) { break }
      printf("%*d %*d %s\n",width1,n,width2,arr[i],i)
    }
    printf("input: %d records, %d bytes, %d words of which %d are unique\n",NR,nbytes,nfields,length(arr))
    exit(0)
}


OPTION _EXPLICIT

' SUBs and FUNCTIONs
DECLARE SUB CountWords (FromString AS STRING)
DECLARE SUB QuickSort (lLeftN AS LONG, lRightN AS LONG, iMode AS INTEGER)
DECLARE SUB ShowResults ()
DECLARE SUB ShowCompletion ()
DECLARE SUB TopCounted ()
DECLARE FUNCTION InsertWord& (WhichWord AS STRING)
DECLARE FUNCTION BinarySearch& (LookFor AS STRING, RetPos AS INTEGER)
DECLARE FUNCTION CleanWord$ (WhichWord AS STRING)

' Var
DIM iFile AS INTEGER
DIM iCol AS INTEGER
DIM iFil AS INTEGER
DIM iStep AS INTEGER
DIM iBar AS INTEGER
DIM iBlock AS INTEGER
DIM lIni AS LONG
DIM lEnd AS LONG
DIM lLines AS LONG
DIM lLine AS LONG
DIM lLenF AS LONG
DIM iRuns AS INTEGER
DIM lMaxWords AS LONG
DIM sTimer AS SINGLE
DIM strFile AS STRING
DIM strKey AS STRING
DIM strText AS STRING
DIM strDate AS STRING
DIM strTime AS STRING
DIM strBar AS STRING
DIM lWords AS LONG
DIM strWords AS STRING
CONST AddWords = 100
CONST TopCount = 10
CONST FALSE = 0, TRUE = NOT FALSE

' Initialize
iFile = FREEFILE
lIni = 1
strDate = DATE$
strTime = TIME$
lEnd = 0
lMaxWords = 1000
REDIM strWords(lIni TO lMaxWords) AS STRING
REDIM lWords(lIni TO lMaxWords) AS LONG
REDIM lTopWords(1) AS LONG
REDIM strTopWords(1) AS STRING

' ---Main program loop
$RESIZE:SMOOTH
DO
    DO
        CLS
        PRINT "This program will count how many words are in a text file and shows the 10"
        PRINT "most used of them."
        PRINT
        INPUT "Document to open (TXT file) (f=see files): ", strFile
        IF UCASE$(strFile) = "F" THEN
            strFile = ""
            FILES
            DO: LOOP UNTIL INKEY$ <> ""
        END IF
    LOOP UNTIL strFile <> ""
    OPEN strFile FOR BINARY AS #iFile
    IF LOF(iFile) > 0 THEN
        iRuns = iRuns + 1
        CLOSE #iFile

        ' Opens the document file to analyze it
        sTimer = TIMER
        ON TIMER(1) GOSUB ShowAdvance
        OPEN strFile FOR INPUT AS #iFile
        lLenF = LOF(iFile)
        PRINT "Looking for words in "; strFile; ". File size:"; STR$(lLenF); ". ";: iCol = POS(0): PRINT "Initializing";
        COLOR 23: PRINT "...";: COLOR 7

        ' Count how many lines has the file
        lLines = 0
        DO WHILE NOT EOF(iFile)
            LINE INPUT #iFile, strText
            lLines = lLines + 1
        LOOP
        CLOSE #iFile

        ' Shows the bar
        LOCATE , iCol: PRINT "Initialization complete."
        PRINT
        PRINT "Processing"; lLines; "lines";: COLOR 23: PRINT "...": COLOR 7
        iFil = CSRLIN
        iCol = POS(0)
        iBar = 80
        iBlock = 80 / lLines
        IF iBlock = 0 THEN iBlock = 1
        PRINT STRING$(iBar, 176)
        lLine = 0
        iStep = lLines * iBlock / iBar
        IF iStep = 0 THEN iStep = 1
        IF iStep > 20 THEN
            TIMER ON
        END IF
        OPEN strFile FOR INPUT AS #iFile
        DO WHILE NOT EOF(iFile)
            lLine = lLine + 1
            IF (lLine MOD iStep) = 0 THEN
                strBar = STRING$(iBlock * (lLine / iStep), 219)
                LOCATE iFil, 1
                PRINT strBar
                ShowCompletion
            END IF
            LINE INPUT #iFile, strText
            CountWords strText
            strKey = INKEY$
        LOOP
        ShowCompletion
        CLOSE #iFile
        TIMER OFF
        LOCATE iFil - 1, 1
        PRINT "Done!" + SPACE$(70)
        strBar = STRING$(iBar, 219)
        LOCATE iFil, 1
        PRINT strBar
        LOCATE iFil + 5, 1
        PRINT "Finishing";: COLOR 23: PRINT "...";: COLOR 7
        ShowResults

        ' Frees the RAM
        lMaxWords = 1000
        lEnd = 0
        REDIM strWords(lIni TO lMaxWords) AS STRING
        REDIM lWords(lIni TO lMaxWords) AS LONG

    ELSE
        CLOSE #iFile
        KILL strFile
        PRINT
        PRINT "Document does not exist."
    END IF
    PRINT
    PRINT "Try again? (Y/n)"
    DO
        strKey = UCASE$(INKEY$)
    LOOP UNTIL strKey = "Y" OR strKey = "N" OR strKey = CHR$(13) OR strKey = CHR$(27)
LOOP UNTIL strKey = "N" OR strKey = CHR$(27) OR iRuns >= 99

CLS
IF iRuns >= 99 THEN
    PRINT "Maximum runs reached for this session."
END IF

PRINT "End of program"
PRINT "Start date/time: "; strDate; " "; strTime
PRINT "End date/time..: "; DATE$; " "; TIME$
END
' ---End main program

ShowAdvance:
ShowCompletion
RETURN

FUNCTION BinarySearch& (LookFor AS STRING, RetPos AS INTEGER)
    ' Var
    DIM lFound AS LONG
    DIM lLow AS LONG
    DIM lHigh AS LONG
    DIM lMid AS LONG
    DIM strLookFor AS STRING
    SHARED lIni AS LONG
    SHARED lEnd AS LONG
    SHARED lMaxWords AS LONG
    SHARED strWords() AS STRING
    SHARED lWords() AS LONG

    ' Binary search for stated word in the list
    lLow = lIni
    lHigh = lEnd
    lFound = 0
    strLookFor = UCASE$(LookFor)
    DO WHILE (lFound < 1) AND (lLow <= lHigh)
        lMid = (lHigh + lLow) / 2
        IF strWords(lMid) = strLookFor THEN
            lFound = lMid
        ELSEIF strWords(lMid) > strLookFor THEN
            lHigh = lMid - 1
        ELSE
            lLow = lMid + 1
        END IF
    LOOP

    ' Should I return the position if not found?
    IF lFound = 0 AND RetPos THEN
        IF lEnd < 1 THEN
            lFound = 1
        ELSEIF strWords(lMid) > strLookFor THEN
            lFound = lMid
        ELSE
            lFound = lMid + 1
        END IF
    END IF

    ' Return the value
    BinarySearch = lFound

END FUNCTION

FUNCTION CleanWord$ (WhichWord AS STRING)
    ' Var
    DIM iSeek AS INTEGER
    DIM iStep AS INTEGER
    DIM bOK AS INTEGER
    DIM strWord AS STRING
    DIM strChar AS STRING

    strWord = WhichWord

    ' Look for trailing wrong characters
    strWord = LTRIM$(RTRIM$(strWord))
    IF LEN(strWord) > 0 THEN
        iStep = 0
        DO
            ' Determines if step will be forward or backwards
            IF iStep = 0 THEN
                iStep = -1
            ELSE
                iStep = 1
            END IF

            ' Sets the initial value of iSeek
            IF iStep = -1 THEN
                iSeek = LEN(strWord)
            ELSE
                iSeek = 1
            END IF

            bOK = FALSE
            DO
                strChar = MID$(strWord, iSeek, 1)
                SELECT CASE strChar
                    CASE "A" TO "Z"
                        bOK = TRUE
                    CASE CHR$(129) TO CHR$(154)
                        bOK = TRUE
                    CASE CHR$(160) TO CHR$(165)
                        bOK = TRUE
                END SELECT

                ' If it is not a character valid as a letter, please move one space
                IF NOT bOK THEN
                    iSeek = iSeek + iStep
                END IF

                ' If no letter was recognized, then exit the loop
                IF iSeek < 1 OR iSeek > LEN(strWord) THEN
                    bOK = TRUE
                END IF
            LOOP UNTIL bOK

            IF iStep = -1 THEN
                ' Reviews if a word was encountered
                IF iSeek > 0 THEN
                    strWord = LEFT$(strWord, iSeek)
                ELSE
                    strWord = ""
                END IF
            ELSEIF iStep = 1 THEN
                IF iSeek <= LEN(strWord) THEN
                    strWord = MID$(strWord, iSeek)
                ELSE
                    strWord = ""
                END IF
            END IF
        LOOP UNTIL iStep = 1 OR strWord = ""
    END IF

    ' Return the result
    CleanWord = strWord

END FUNCTION

SUB CountWords (FromString AS STRING)
    ' Var
    DIM iStart AS INTEGER
    DIM iLenW AS INTEGER
    DIM iLenS AS INTEGER
    DIM iLenD AS INTEGER
    DIM strString AS STRING
    DIM strWord AS STRING
    DIM lWhichWord AS LONG
    SHARED lEnd AS LONG
    SHARED lMaxWords AS LONG
    SHARED strWords() AS STRING
    SHARED lWords() AS LONG

    ' Converts to Upper Case and cleans leading and trailing spaces
    strString = UCASE$(FromString)
    strString = LTRIM$(RTRIM$(strString))

    ' Get words from string
    iStart = 1
    iLenW = 0
    iLenS = LEN(strString)
    DO WHILE iStart <= iLenS
        iLenW = INSTR(iStart, strString, " ")
        IF iLenW = 0 AND iStart <= iLenS THEN
            iLenW = iLenS + 1
        END IF
        strWord = MID$(strString, iStart, iLenW - iStart)

        ' Will remove mid dashes or apostrophe or "â€"
        iLenD = INSTR(strWord, "-")
        IF iLenD < 1 THEN
            iLenD = INSTR(strWord, "'")
            IF iLenD < 1 THEN
                iLenD = INSTR(strWord, "â€")
            END IF
        END IF
        IF iLenD >= 2 THEN
            strWord = LEFT$(strWord, iLenD - 1)
            iLenW = iStart + (iLenD - 1)
        END IF
        strWord = CleanWord(strWord)

        IF strWord <> "" THEN
            ' Look for the word to be counted
            lWhichWord = BinarySearch(strWord, FALSE)

            ' If the word doesn't exist in the list, add it
            IF lWhichWord = 0 THEN
                lWhichWord = InsertWord(strWord)
            END IF

            ' Count the word
            IF lWhichWord > 0 THEN
                lWords(lWhichWord) = lWords(lWhichWord) + 1
            END IF
        END IF
        iStart = iLenW + 1
    LOOP

END SUB

' Here a word will be inserted in the list
FUNCTION InsertWord& (WhichWord AS STRING)
    ' Var
    DIM lFound AS LONG
    DIM lWord AS LONG
    DIM strWord AS STRING
    SHARED lIni AS LONG
    SHARED lEnd AS LONG
    SHARED lMaxWords AS LONG
    SHARED strWords() AS STRING
    SHARED lWords() AS LONG

    ' Look for the word in the list
    strWord = UCASE$(WhichWord)
    lFound = BinarySearch(WhichWord, TRUE)
    IF lFound > 0 THEN
        ' Add one word
        lEnd = lEnd + 1

        ' Verifies if there is still room for a new word
        IF lEnd > lMaxWords THEN
            lMaxWords = lMaxWords + AddWords ' Other words
            IF lMaxWords > 32767 THEN
                IF lEnd <= 32767 THEN
                    lMaxWords = 32767
                ELSE
                    lFound = -1
                END IF
            END IF

            IF lFound > 0 THEN
                REDIM _PRESERVE strWords(lIni TO lMaxWords) AS STRING
                REDIM _PRESERVE lWords(lIni TO lMaxWords) AS LONG
            END IF
        END IF

        IF lFound > 0 THEN
            ' Move the words below this
            IF lEnd > 1 THEN
                FOR lWord = lEnd TO lFound + 1 STEP -1
                    strWords(lWord) = strWords(lWord - 1)
                    lWords(lWord) = lWords(lWord - 1)
                NEXT lWord
            END IF

            ' Insert the word in the position
            strWords(lFound) = strWord
            lWords(lFound) = 0
        END IF
    END IF

    InsertWord = lFound
END FUNCTION

SUB QuickSort (lLeftN AS LONG, lRightN AS LONG, iMode AS INTEGER)
    ' Var
    DIM lPivot AS LONG
    DIM lLeftNIdx AS LONG
    DIM lRightNIdx AS LONG
    SHARED lWords() AS LONG
    SHARED strWords() AS STRING

    ' Clasifies from highest to lowest
    lLeftNIdx = lLeftN
    lRightNIdx = lRightN
    IF (lRightN - lLeftN) > 0 THEN
        lPivot = (lLeftN + lRightN) / 2
        DO WHILE (lLeftNIdx <= lPivot) AND (lRightNIdx >= lPivot)
            IF iMode = 0 THEN ' Ascending
                DO WHILE (lWords(lLeftNIdx) < lWords(lPivot)) AND (lLeftNIdx <= lPivot)
                    lLeftNIdx = lLeftNIdx + 1
                LOOP
                DO WHILE (lWords(lRightNIdx) > lWords(lPivot)) AND (lRightNIdx >= lPivot)
                    lRightNIdx = lRightNIdx - 1
                LOOP
            ELSE ' Descending
                DO WHILE (lWords(lLeftNIdx) > lWords(lPivot)) AND (lLeftNIdx <= lPivot)
                    lLeftNIdx = lLeftNIdx + 1
                LOOP
                DO WHILE (lWords(lRightNIdx) < lWords(lPivot)) AND (lRightNIdx >= lPivot)
                    lRightNIdx = lRightNIdx - 1
                LOOP
            END IF
            SWAP lWords(lLeftNIdx), lWords(lRightNIdx)
            SWAP strWords(lLeftNIdx), strWords(lRightNIdx)
            lLeftNIdx = lLeftNIdx + 1
            lRightNIdx = lRightNIdx - 1
            IF (lLeftNIdx - 1) = lPivot THEN
                lRightNIdx = lRightNIdx + 1
                lPivot = lRightNIdx
            ELSEIF (lRightNIdx + 1) = lPivot THEN
                lLeftNIdx = lLeftNIdx - 1
                lPivot = lLeftNIdx
            END IF
        LOOP
        QuickSort lLeftN, lPivot - 1, iMode
        QuickSort lPivot + 1, lRightN, iMode
    END IF
END SUB

SUB ShowCompletion ()
    ' Var
    SHARED iFil AS INTEGER
    SHARED lLine AS LONG
    SHARED lLines AS LONG
    SHARED lEnd AS LONG

    LOCATE iFil + 1, 1
    PRINT "Lines analyzed :"; lLine
    PRINT USING "% of completion: ###%"; (lLine / lLines) * 100
    PRINT "Words found....:"; lEnd
END SUB

SUB ShowResults ()
    ' Var
    DIM iMaxL AS INTEGER
    DIM iMaxW AS INTEGER
    DIM lWord AS LONG
    DIM lHowManyWords AS LONG
    DIM strString AS STRING
    DIM strFileR AS STRING
    SHARED lIni AS LONG
    SHARED lEnd AS LONG
    SHARED lLenF AS LONG
    SHARED lMaxWords AS LONG
    SHARED sTimer AS SINGLE
    SHARED strFile AS STRING
    SHARED strWords() AS STRING
    SHARED lWords() AS LONG
    SHARED strTopWords() AS STRING
    SHARED lTopWords() AS LONG
    SHARED iRuns AS INTEGER

    ' Show results

    ' Creates file name
    lWord = INSTR(strFile, ".")
    IF lWord = 0 THEN lWord = LEN(strFile)
    strFileR = LEFT$(strFile, lWord)
    IF RIGHT$(strFileR, 1) <> "." THEN strFileR = strFileR + "."

    ' Retrieves the longest word found and the highest count
    FOR lWord = lIni TO lEnd
        ' Gets the longest word found
        IF LEN(strWords(lWord)) > iMaxL THEN
            iMaxL = LEN(strWords(lWord))
        END IF

        lHowManyWords = lHowManyWords + lWords(lWord)
    NEXT lWord
    IF iMaxL > 60 THEN iMaxW = 60 ELSE iMaxW = iMaxL

    ' Gets top counted
    TopCounted

    ' Shows the results
    CLS
    PRINT "File analyzed : "; strFile
    PRINT "Length of file:"; lLenF
    PRINT "Time lapse....:"; TIMER - sTimer;"seconds"
    PRINT "Words found...:"; lHowManyWords; "(Unique:"; STR$(lEnd); ")"
    PRINT "Longest word..:"; iMaxL
    PRINT
    PRINT "The"; TopCount; "most used are:"
    PRINT STRING$(iMaxW, "-"); "+"; STRING$(80 - (iMaxW + 1), "-")
    PRINT " Word"; SPACE$(iMaxW - 5); "| Count"
    PRINT STRING$(iMaxW, "-"); "+"; STRING$(80 - (iMaxW + 1), "-")
    strString = "\" + SPACE$(iMaxW - 2) + "\| #########,"
    FOR lWord = lIni TO TopCount
        PRINT USING strString; strTopWords(lWord); lTopWords(lWord)
    NEXT lWord
    PRINT STRING$(iMaxW, "-"); "+"; STRING$(80 - (iMaxW + 1), "-")
    PRINT "See files "; strFileR + "S" + LTRIM$(STR$(iRuns)); " and "; strFileR + "C" + LTRIM$(STR$(iRuns)); " to see the full list."
END SUB

SUB TopCounted ()
    ' Var
    DIM lWord AS LONG
    DIM strFileR AS STRING
    DIM iFile AS INTEGER
    CONST Descending = 1
    SHARED lIni AS LONG
    SHARED lEnd AS LONG
    SHARED lMaxWords AS LONG
    SHARED strWords() AS STRING
    SHARED lWords() AS LONG
    SHARED strTopWords() AS STRING
    SHARED lTopWords() AS LONG
    SHARED iRuns AS INTEGER
    SHARED strFile AS STRING

    ' Assigns new dimmentions
    REDIM strTopWords(lIni TO TopCount) AS STRING
    REDIM lTopWords(lIni TO TopCount) AS LONG

    ' Saves the current values
    lWord = INSTR(strFile, ".")
    IF lWord = 0 THEN lWord = LEN(strFile)
    strFileR = LEFT$(strFile, lWord)
    IF RIGHT$(strFileR, 1) <> "." THEN strFileR = strFileR + "."
    iFile = FREEFILE
    OPEN strFileR + "S" + LTRIM$(STR$(iRuns)) FOR OUTPUT AS #iFile
    FOR lWord = lIni TO lEnd
        WRITE #iFile, strWords(lWord), lWords(lWord)
    NEXT lWord
    CLOSE #iFile

    ' Classifies the counted in descending order
    QuickSort lIni, lEnd, Descending

    ' Now, saves the required values in the arrays
    FOR lWord = lIni TO TopCount
        strTopWords(lWord) = strWords(lWord)
        lTopWords(lWord) = lWords(lWord)
    NEXT lWord

    ' Now, saves the order from the file
    OPEN strFileR + "C" + LTRIM$(STR$(iRuns)) FOR OUTPUT AS #iFile
    FOR lWord = lIni TO lEnd
        WRITE #iFile, strWords(lWord), lWords(lWord)
    NEXT lWord
    CLOSE #iFile

END SUB


: (prinl (wrap 12 (chop "The quick brown fox jumps over the lazy dog")))
The quick
brown fox
jumps over
the lazy dog
-> "The quick^Jbrown fox^Jjumps over^Jthe lazy dog"


*process source attributes xref or(!);
 ww: proc Options(main);
 /*********************************************************************
 * 21.08-2013 Walter Pachl  derived from REXX version 2
 *********************************************************************/
 Dcl in  record input;
 Dcl out record output;
 On Endfile(in) z=' ';
 Dcl z char(32767) Var;
 Dcl s char(32767) Var Init('');
 dcl o Char(200) Var;
 Dcl (i,w,p) Bin Fixed(31) Init(0);
 w=72;
 Read File(in) Into(z);
 s=z;
 Do Until(s='');
   Do i=w+1 to 1 by -1;
     If substr(s,i,1)='' Then Leave;
     End;
   If i=0 Then
     p=index(s,' ');
   Else
     p=i;
   o=left(s,p);
   Write file(out) From(o);
   s=substr(s,p+1);
   If length(s)<200 Then Do;
     Read File(in) Into(z);
     s=s!!z;
     End;
   End;
 End;


@echo off

call:wordCount 1 2 3 4 5 6 7 8 9 10 42 101

pause>nul
exit

:wordCount
setlocal enabledelayedexpansion

set word=100000
set line=0
for /f "delims=" %%i in (input.txt) do (
	set /a line+=1
	for %%j in (%%i) do (
		if not !skip%%j!==true (
			echo line !line! ^| word !word:~-5! - "%%~j"

			type input.txt | find /i /c "%%~j" > count.tmp
			set /p tmpvar=<count.tmp

			set tmpvar=000000000!tmpvar!
			set tmpvar=!tmpvar:~-10!
			set count[!word!]=!tmpvar! %%~j

			set "skip%%j=true"
			set /a word+=1
		)
	)
)
del count.tmp

set wordcount=0
for /f "tokens=1,2 delims= " %%i in ('set count ^| sort /+14 /r') do (
	set /a wordcount+=1
	for /f "tokens=2 delims==" %%k in ("%%i") do (
		set word[!wordcount!]=!wordcount!. %%j - %%k
	)
)

cls
for %%i in (%*) do echo !word[%%i]!
endlocal
goto:eof


function wrap{
$divide=$args[0] -split " "
$width=$args[1]
$spaceleft=$width

foreach($word in $divide){
    if($word.length+1 -gt $spaceleft){
        $output+="`n$word "
        $spaceleft=$width-($word.length+1)
    } else {
        $output+="$word "
        $spaceleft-=$word.length+1
    }
}

return "$output`n"
}

### The Main Thing...

$paragraph="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur."

"`nLine width:30`n"
wrap $paragraph 30
"========================================================="
"Line width:100`n"
wrap $paragraph 100

### End script


% See https://en.wikipedia.org/wiki/Line_wrap_and_word_wrap#Minimum_number_of_lines
word_wrap(String, Length, Wrapped):-
    re_split("\\S+", String, Words),
    wrap(Words, Length, Length, Wrapped, '').

wrap([_], _, _, Result, Result):-!.
wrap([Space, Word|Words], Line_length, Space_left, Result, String):-
    string_length(Word, Word_len),
    string_length(Space, Space_len),
    (Space_left < Word_len + Space_len ->
        Space1 = '\n',
        Space_left1 is Line_length - Word_len
        ;
        Space1 = Space,
        Space_left1 is Space_left - Word_len - Space_len
    ),
    atomic_list_concat([String, Space1, Word], String1),
    wrap(Words, Line_length, Space_left1, Result, String1).

sample_text("Lorem ipsum dolor sit amet, consectetur adipiscing \
elit, sed do eiusmod tempor incididunt ut labore et dolore magna \
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco \
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure \
dolor in reprehenderit in voluptate velit esse cillum dolore eu \
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non \
proident, sunt in culpa qui officia deserunt mollit anim id est \
laborum.").

test_word_wrap(Line_length):-
    sample_text(Text),
    word_wrap(Text, Line_length, Wrapped),
    writef('Wrapped at %w characters:\n%w\n',
           [Line_length, Wrapped]).

main:-
    test_word_wrap(60),
    nl,
    test_word_wrap(80).


  ( 10-most-frequent-words
  =     MergeSort                        { Local variable declarations. }
        types
        sorted-words
        frequency
        type
        most-frequent-words
    .   ( MergeSort                      { Definition of function MergeSort. }
        =   A N Z pivot
          .   !arg:? [?N                 { [?N is a subpattern that counts the number of preceding elements }
            & (   !N:>1                           { if N at least 2 ... }
                & div$(!N.2):?pivot               {     divide N by 2 ... }
                & !('($arg:?A [($pivot) ?Z))      {     split list in two halves A and Z ... }
                & MergeSort$!A+MergeSort$!Z       {     sort each of A and Z and return sum }
              | !arg                              { else just return a single element}
              )
        )
      &     MergeSort             { Sort }
          $ ( vap                 { Split second argument at each occurrence of third character and apply first argument to each chunk. }
            $ ( (=.low$!arg)      { Return input, lowercased. }
              .   str
                $ ( vap           { Vaporize second argument in UTF-8 or Latin-1 characters and apply first argument to each of them. }
                  $ ( (
                      =
                        .   upp$!arg:low$!arg&\n  { Return newline instead of non-alphabetic character. }
                          | !arg                  { Return (Euro-centric) alphabetic character.}
                      )
                    . get$(!arg,NEW STR) { Read input text as a single string. }
                    )
                  )
              . \n                       { Split at newlines }
              )
            )
        : ?sorted-words                  { Assign sum of (frequency*lowercasedword) terms to sorted-words. }
      & :?types                          { Initialize types as an empty list. }
      &   whl                            { Loop until right hand side fails. }
        ' ( !sorted-words:#?frequency*%@?type+?sorted-words    { Extract first frequency*type term from sum. }
          & (!frequency.!type) !types:?types                   { Prepend (frequency.type) pair to types list}
          )
      &   MergeSort$!types                                     { Sort the list of (frequency.type) pairs. }
        : (?+[-11+?most-frequent-words|?most-frequent-words)   { Pick the last 10 terms from the sum returned by MergeSort. }
      & !most-frequent-words                                   { Return the last 10 terms. }
  )
& out$(10-most-frequent-words$"135-0.txt")      { Call 10-most-frequent-words with name of inout file and print result to screen. }


#include <stdbool.h>
#include <stdio.h>
#include <glib.h>

typedef struct word_count_tag {
    const char* word;
    size_t count;
} word_count;

int compare_word_count(const void* p1, const void* p2) {
    const word_count* w1 = p1;
    const word_count* w2 = p2;
    if (w1->count > w2->count)
        return -1;
    if (w1->count < w2->count)
        return 1;
    return 0;
}

bool get_top_words(const char* filename, size_t count) {
    GError* error = NULL;
    GMappedFile* mapped_file = g_mapped_file_new(filename, FALSE, &error);
    if (mapped_file == NULL) {
        fprintf(stderr, "%s\n", error->message);
        g_error_free(error);
        return false;
    }
    const char* text = g_mapped_file_get_contents(mapped_file);
    if (text == NULL) {
        fprintf(stderr, "File %s is empty\n", filename);
        g_mapped_file_unref(mapped_file);
        return false;
    }
    gsize file_size = g_mapped_file_get_length(mapped_file);
    // Store word counts in a hash table
    GHashTable* ht = g_hash_table_new_full(g_str_hash, g_str_equal,
                                           g_free, g_free);
    GRegex* regex = g_regex_new("\\w+", 0, 0, NULL);
    GMatchInfo* match_info;
    g_regex_match_full(regex, text, file_size, 0, 0, &match_info, NULL);
    while (g_match_info_matches(match_info)) {
        char* word = g_match_info_fetch(match_info, 0);
        char* lower = g_utf8_strdown(word, -1);
        g_free(word);
        size_t* count = g_hash_table_lookup(ht, lower);
        if (count != NULL) {
            ++*count;
            g_free(lower);
        } else {
            count = g_new(size_t, 1);
            *count = 1;
            g_hash_table_insert(ht, lower, count);
        }
        g_match_info_next(match_info, NULL);
    }
    g_match_info_free(match_info);
    g_regex_unref(regex);
    g_mapped_file_unref(mapped_file);

    // Sort words in decreasing order of frequency
    size_t size = g_hash_table_size(ht);
    word_count* words = g_new(word_count, size);
    GHashTableIter iter;
    gpointer key, value;
    g_hash_table_iter_init(&iter, ht);
    for (size_t i = 0; g_hash_table_iter_next(&iter, &key, &value); ++i) {
        words[i].word = key;
        words[i].count = *(size_t*)value;
    }
    qsort(words, size, sizeof(word_count), compare_word_count);

    // Print the most common words
    if (count > size)
        count = size;
    printf("Top %lu words\n", count);
    printf("Rank\tCount\tWord\n");
    for (size_t i = 0; i < count; ++i)
        printf("%lu\t%lu\t%s\n", i + 1, words[i].count, words[i].word);
    g_free(words);
    g_hash_table_destroy(ht);
    return true;
}

int main(int argc, char** argv) {
    if (argc != 2) {
        fprintf(stderr, "usage: %s file\n", argv[0]);
        return EXIT_FAILURE;
    }
    if (!get_top_words(argv[1], 10))
        return EXIT_FAILURE;
    return EXIT_SUCCESS;
}


DataSection
  Data.s "In olden times when wishing still helped one, there lived a king "+
    "whose daughters were all beautiful, but the youngest was so beautiful "+
    "that the sun itself, which has seen so much, was astonished whenever "+
    "it shone-in-her-face.  Close-by-the-king's castle lay a great dark "+
    "forest, and under an old lime-tree in the forest was a well, and when "+
    "the day was very warm, the king's child went out into the forest and "+
    "sat down by the side of the cool-fountain, and when she was bored she "+
    "took a golden ball, and threw it up on high and caught it, and this "+
    "ball was her favorite plaything."
EndDataSection

Procedure.i ww_pos(txt$,l.i)
  While Mid(txt$,l,1)<>Chr(32) And l>0 And Len(txt$)>l : l-1 : Wend
  If l>0 : ProcedureReturn l : Else : ProcedureReturn Len(Trim(txt$)) : EndIf
EndProcedure

Procedure WriteLine(txt$,ls.i)
  Shared d$,lw
  Select LCase(d$)
    Case "l" : PrintN(Mid(txt$,1,ls))
    Case "r" : PrintN(RSet(Trim(Mid(txt$,1,ls)),lw,Chr(32)))
  EndSelect
EndProcedure

Procedure main(txt$,lw.i)
  If Len(txt$)
    p=ww_pos(txt$,lw) : WriteLine(txt$,p) : ProcedureReturn main(LTrim(Right(txt$,Len(txt$)-p)),lw)
  EndIf
EndProcedure

Procedure.i MaxWordLen(txt$)
  For i=1 To CountString(txt$,Chr(32))+1
    wrd$=LTrim(StringField(txt$,i,Chr(32)))
    wrdl=Len(wrd$)+1 : If wrdl>l : l=wrdl : EndIf
  Next
  ProcedureReturn l
EndProcedure

OpenConsole()
Read.s t$
Print("Input line width: ") : lw=Val(Input()) : minL=MaxWordLen(t$)
If lw<minL : lw=minL : PrintN("Min. line width "+Str(lw-1)) : EndIf
Print("Input direction l:left r:rigth ")
Repeat : d$=Inkey() : Delay(50) : Until FindString("lr",d$,1,#PB_String_NoCase) : PrintN(d$+#CRLF$)
main(t$,lw) : Input()


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;

namespace WordCount {
    class Program {
        static void Main(string[] args) {
            var text = File.ReadAllText("135-0.txt").ToLower();

            var match = Regex.Match(text, "\\w+");
            Dictionary<string, int> freq = new Dictionary<string, int>();
            while (match.Success) {
                string word = match.Value;
                if (freq.ContainsKey(word)) {
                    freq[word]++;
                } else {
                    freq.Add(word, 1);
                }

                match = match.NextMatch();
            }

            Console.WriteLine("Rank  Word  Frequency");
            Console.WriteLine("====  ====  =========");
            int rank = 1;
            foreach (var elem in freq.OrderByDescending(a => a.Value).Take(10)) {
                Console.WriteLine("{0,2}    {1,-4}    {2,5}", rank++, elem.Key, elem.Value);
            }
        }
    }
}


#include <algorithm>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
#include <unordered_map>
#include <vector>

int main(int ac, char** av) {
  std::ios::sync_with_stdio(false);
  int head = (ac > 1) ? std::atoi(av[1]) : 10;
  std::istreambuf_iterator<char> it(std::cin), eof;
  std::filebuf file;
  if (ac > 2) {
    if (file.open(av[2], std::ios::in), file.is_open()) {
      it = std::istreambuf_iterator<char>(&file);
    } else return std::cerr << "file " << av[2] << " open failed\n", 1;
  }
  auto alpha = [](unsigned c) { return c-'A' < 26 || c-'a' < 26; };
  auto lower = [](unsigned c) { return c | '\x20'; };
  std::unordered_map<std::string, int> counts;
  std::string word;
  for (; it != eof; ++it) {
    if (alpha(*it)) {
      word.push_back(lower(*it));
    } else if (!word.empty()) {
      ++counts[word];
      word.clear();
    }
  }
  if (!word.empty()) ++counts[word]; // if file ends w/o ws
  std::vector<std::pair<const std::string,int> const*> out;
  for (auto& count : counts) out.push_back(&count);
  std::partial_sort(out.begin(),
    out.size() < head ? out.end() : out.begin() + head,
    out.end(), [](auto const* a, auto const* b) {
      return a->second > b->second;
    });
  if (out.size() > head) out.resize(head);
  for (auto const& count : out) {
    std::cout << count->first << ' ' << count->second << '\n';
  }
  return 0;
}


>>> import textwrap
>>> help(textwrap.fill)
Help on function fill in module textwrap:

fill(text, width=70, **kwargs)
    Fill a single paragraph of text, returning a new string.

    Reformat the single paragraph in 'text' to fit in lines of no more
    than 'width' columns, and return a new string containing the entire
    wrapped paragraph.  As with wrap(), tabs are expanded and other
    whitespace characters converted to space.  See TextWrapper class for
    available keyword args to customize wrapping behaviour.

>>> txt = '''\
Reformat the single paragraph in 'text' to fit in lines of no more
than 'width' columns, and return a new string containing the entire
wrapped paragraph.  As with wrap(), tabs are expanded and other
whitespace characters converted to space.  See TextWrapper class for
available keyword args to customize wrapping behaviour.'''
>>> print(textwrap.fill(txt, width=75))
Reformat the single paragraph in 'text' to fit in lines of no more than
'width' columns, and return a new string containing the entire wrapped
paragraph.  As with wrap(), tabs are expanded and other whitespace
characters converted to space.  See TextWrapper class for available keyword
args to customize wrapping behaviour.
>>> print(textwrap.fill(txt, width=45))
Reformat the single paragraph in 'text' to
fit in lines of no more than 'width' columns,
and return a new string containing the entire
wrapped paragraph.  As with wrap(), tabs are
expanded and other whitespace characters
converted to space.  See TextWrapper class
for available keyword args to customize
wrapping behaviour.
>>> print(textwrap.fill(txt, width=85))
Reformat the single paragraph in 'text' to fit in lines of no more than 'width'
columns, and return a new string containing the entire wrapped paragraph.  As with
wrap(), tabs are expanded and other whitespace characters converted to space.  See
TextWrapper class for available keyword args to customize wrapping behaviour.
>>>


  $ "Consider the inexorable logic of the Big Lie. If a man has
     a consuming love for cats and dedicates himself to the
     protection of cats, you have only to accuse him of killing
     and mistreating cats. Your lie will have the unmistakable
     ring of truth, whereas his outraged denials will reek of
     falsehood and evasion. Those who have heard voices from the
     nondominant brain hemisphere remark of the absolute
     authority of the voice. They know they are hearing the
     Truth. The fact that no evidence is adduced and that the
     voice may be talking utter nonsense has nothing to do with
     facts. Those who manipulate Truth to their advantage, the
     people of the Big Lie, are careful to shun facts. In fact
     nothing is more deeply offensive to such people than the
     concept of fact. To adduce fact in your defense is to rule
     yourself out of court."

  nest$ dup
  55 wrap$ cr
  75 wrap$ cr
  say "-- William S. Burroughs, Ghost Of Chance, 1981" cr


(defn count-words [file n]
  (->> file
    slurp
    clojure.string/lower-case
    (re-seq #"\w+")
    frequencies
    (sort-by val >)
    (take n)))


       IDENTIFICATION DIVISION.
       PROGRAM-ID. WordFrequency.
       AUTHOR.  Bill Gunshannon.
       DATE-WRITTEN.  30 Jan 2020.
      ************************************************************
      ** Program Abstract:
      **   Given a text file and an integer n, print the n most
      **   common words in the file (and the number of their
      **   occurrences) in decreasing frequency.
      **
      **   A file named Parameter.txt provides this information.
      **   Format is:
      **   12345678901234567890123456789012345678901234567890
      **   |------------------|----|
      **     ^^^^^^^^^^^^^^^^  ^^^^
      **          |              |
      **     Source Text File   Number of words with count
      **       20 Characters      5 digits with leading zeroes
      **
      **
      ************************************************************

       ENVIRONMENT DIVISION.

       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
            SELECT Parameter-File ASSIGN TO "Parameter.txt"
                 ORGANIZATION IS LINE SEQUENTIAL.
            SELECT Input-File ASSIGN TO Source-Text
                 ORGANIZATION IS LINE SEQUENTIAL.
            SELECT Word-File ASSIGN TO "Word.txt"
                 ORGANIZATION IS LINE SEQUENTIAL.
            SELECT Output-File ASSIGN TO "Output.txt"
                 ORGANIZATION IS LINE SEQUENTIAL.
            SELECT Print-File ASSIGN TO "Printer.txt"
                 ORGANIZATION IS LINE SEQUENTIAL.
            SELECT Sort-File     ASSIGN TO DISK.

       DATA DIVISION.

       FILE SECTION.

       FD  Parameter-File
           DATA RECORD IS Parameter-Record.
       01  Parameter-Record.
           05 Source-Text               PIC X(20).
           05 How-Many                  PIC 99999.

       FD  Input-File
           DATA RECORD IS Input-Record.
       01  Input-Record.
           05 Input-Line                PIC X(80).

       FD  Word-File
           DATA RECORD IS Word-Record.
       01  Word-Record.
           05 Input-Word               PIC X(20).

       FD  Output-File
           DATA RECORD IS Output-Rec.
       01  Output-Rec.
           05  Output-Rec-Word         PIC X(20).
           05  Output-Rec-Word-Cnt     PIC 9(5).

       FD  Print-File
           DATA RECORD IS Print-Rec.
       01  Print-Rec.
           05  Print-Rec-Word          PIC X(20).
           05  Print-Rec-Word-Cnt      PIC 9(5).

       SD  Sort-File.
       01  Sort-Rec.
           05  Sort-Word               PIC X(20).
           05  Sort-Word-Cnt           PIC 9(5).

       WORKING-STORAGE SECTION.

       01 Eof                    PIC X     VALUE 'F'.
       01 InLine                 PIC X(80).
       01 Word1                  PIC X(20).
       01 Current-Word           PIC X(20).
       01 Current-Word-Cnt       PIC 9(5).
       01 Pos                    PIC 99
                 VALUE 1.
       01 Cnt                    PIC 99.
       01 Report-Rank.
          05  IRank              PIC 99999
                 VALUE 1.
          05 Rank                PIC ZZZZ9.

       PROCEDURE DIVISION.

       Main-Program.
      **
      **  Read the Parameters
      **
         OPEN INPUT Parameter-File.
         READ Parameter-File.
         CLOSE Parameter-File.

      **
      **  Open Files for first stage
      **
         OPEN INPUT  Input-File.
         OPEN OUTPUT  Word-File.

      **
      **  Pare\se the Source Text into a file of invidual words
      **
         PERFORM UNTIL Eof = 'T'
            READ Input-File
               AT END MOVE 'T' TO Eof
            END-READ

         PERFORM Parse-a-Words

         MOVE SPACES TO Input-Record
         MOVE 1 TO Pos
         END-PERFORM.

      **
      **  Cleanup from the first stage
      **
         CLOSE Input-File Word-File

      **
      **  Sort the individual words in alphabetical order
      **
         SORT Sort-File
              ON ASCENDING KEY Sort-Word
              USING Word-File
              GIVING Word-File.

      **
      **  Count each time a word is used
      **
         PERFORM Collect-Totals.

      **
      **  Sort data by number of usages per word
      **
         SORT Sort-File
              ON DESCENDING KEY Sort-Word-Cnt
              USING Output-File
              GIVING Print-File.

      **
      **  Show the work done
      **
         OPEN INPUT Print-File.
            DISPLAY " Rank  Word               Frequency"
         PERFORM How-Many TIMES
            READ Print-File
            MOVE IRank TO Rank
            DISPLAY Rank "  " Print-Rec
            ADD 1 TO IRank
         END-PERFORM.

      **
      **  Cleanup
      **
         CLOSE Print-File.
         CALL "C$DELETE" USING "Word.txt" ,0
         CALL "C$DELETE" USING "Output.txt" ,0

         STOP RUN.

        Parse-a-Words.
          INSPECT Input-Record CONVERTING '-.,"();:/[]{}!?|' TO SPACE
          PERFORM UNTIL Pos > FUNCTION STORED-CHAR-LENGTH(Input-Record)

          UNSTRING Input-Record DELIMITED BY SPACE INTO Word1
                    WITH POINTER Pos TALLYING IN Cnt
          MOVE FUNCTION TRIM(FUNCTION LOWER-CASE(Word1)) TO Word-Record

          IF Word-Record NOT EQUAL SPACES AND Word-Record IS ALPHABETIC
             THEN WRITE Word-Record
          END-IF

          END-PERFORM.

       Collect-Totals.
          MOVE 'F' to Eof
          OPEN INPUT Word-File
          OPEN OUTPUT Output-File
             READ Word-File
             MOVE Input-Word TO Current-Word
             MOVE 1 to Current-Word-Cnt
          PERFORM UNTIL Eof = 'T'
             READ Word-File
                AT END MOVE 'T' TO Eof
             END-READ

             IF FUNCTION TRIM(Word-Record)
                    EQUAL
                           FUNCTION TRIM(Current-Word)
                THEN
                     ADD 1 to Current-Word-Cnt
                ELSE
                     MOVE Current-Word TO Output-Rec-Word
                     MOVE Current-Word-Cnt TO Output-Rec-Word-Cnt
                     WRITE Output-Rec
                     MOVE 1 to Current-Word-Cnt
                     MOVE Word-Record TO Current-Word
                     MOVE SPACES TO Input-Record
            END-IF

          END-PERFORM.
          CLOSE Word-File Output-File.
       END-PROGRAM.


> x <- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. "
> cat(paste(strwrap(x=c(x, "\n"), width=80), collapse="\n"))
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus.
Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec
consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero
egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem
lacinia consectetur.
> cat(paste(strwrap(x=c(x, "\n"), width=60), collapse="\n"))
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas
congue ligula ac quam viverra nec consectetur ante
hendrerit. Donec et mollis dolor. Praesent et diam eget
libero egestas mattis sit amet vitae augue. Nam tincidunt
congue enim, ut porta lorem lacinia consectetur.


#lang at-exp racket
(require scribble/text/wrap)
(define text
  @(λ xs (regexp-replace* #rx" *\n *" (string-append* xs) " ")){
    In olden times when wishing still helped one, there lived a king whose
    daughters were all beautiful, but the youngest was so beautiful that the
    sun itself, which has seen so much, was astonished whenever it shone in her
    face.  Close by the king's castle lay a great dark forest, and under an old
    lime-tree in the forest was a well, and when the day was very warm, the
    king's child went out into the forest and sat down by the side of the cool
    fountain, and when she was bored she took a golden ball, and threw it up on
    high and caught it, and this ball was her favorite plaything.})
(for-each displayln (wrap-line text 60))


my $s = "In olden times when wishing still helped one, there lived a king
whose daughters were all beautiful, but the youngest was so beautiful
that the sun itself, which has seen so much, was astonished whenever
it shone in her face.  Close-by-the-king's-castle-lay-a-great-dark
forest, and under an old lime-tree in the forest was a well, and when
the day was very warm, the king's child went out into the forest and
sat down by the side of the cool fountain, and when she was bored she
took a golden ball, and threw it up on high and caught it, and this
ball was her favorite plaything.";

$s ~~ s:g/»\s+/ /;
$s ~~ s/\s*$/\n\n/;

say $s.subst(/ \s* (. ** 1..66) \s /, -> $/ { "$0\n" }, :g);
say $s.subst(/ \s* (. ** 1..25) \s /, -> $/ { "$0\n" }, :g);


(defun count-word (n pathname)
  (with-open-file (s pathname :direction :input)
    (loop for line = (read-line s nil nil) while line
          nconc (list-symb (drop-noise line)) into words
          finally (return (subseq (sort (pair words)
                                        #'> :key #'cdr)
                                  0 n)))))

  (defun list-symb (s)
    (let ((*read-eval* nil))
      (read-from-string (concatenate 'string "(" s ")"))))

(defun drop-noise (s)
  (delete-if-not #'(lambda (x) (or (alpha-char-p x)
                                   (equal x #\space)
                                   (equal x #\-))) s))

(defun pair (words &aux (hash (make-hash-table)) ac)
  (dolist (word words) (incf (gethash word hash 0)))
  (maphash #'(lambda (e n) (push `(,e . ,n) ac)) hash) ac)


require "http/client"
require "regex"

# Get the text from the internet
response = HTTP::Client.get "https://www.gutenberg.org/files/135/135-0.txt"
text = response.body

text
  .downcase
  .scan(/[a-zA-ZáéíóúÁÉÍÓÚâêôäüöàèìòùñ']+/)
  .reduce({} of String => Int32) { |hash, match|
    word = match[0]
    hash[word] = hash.fetch(word, 0) + 1 # using fetch to set a default value (1) to the new found word
    hash
  }
  .to_a                                        # convert the returned hash to an array of tuples (String, Int32) -> {word, sum}
  .sort { |a, b| b[1] <=> a[1] }[0..9]         # sort and get the first 10 elements
  .each_with_index(1) { |(word, n), i| puts "#{i} \t #{word} \t #{n}" } # print the result


/*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.*/
            @[email protected] 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. */


# Project : Word wrap

load "stdlib.ring"

doc = "In olden times when wishing still helped one, there lived a king
whose daughters were all beautiful, but the youngest was so beautiful
that the sun itself, which has seen so much, was astonished whenever
it shone in her face.  Close by the king's castle lay a great dark
forest, and under an old lime-tree in the forest was a well, and when
the day was very warm, the king's child went out into the forest and
sat down by the side of the cool fountain, and when she was bored she
took a golden ball, and threw it up on high and caught it, and this
ball was her favorite plaything."

wordwrap(doc,72)
wordwrap(doc,80)

func wordwrap(doc, maxline)
        words = split(doc, " ")
        line = words[1]
        for i=2 to len(words)
             word = words[i]
            if len(line)+len(word)+1 > maxline
               see line + nl
               line = word
            else
               line = line + " " + word
           ok
        next
        see line + nl + nl


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

text = <<END
In olden times when wishing still helped one, there lived a king
whose daughters were all beautiful, but the youngest was so beautiful
that the sun itself, which has seen so much, was astonished whenever
it shone in her face.  Close by the king's castle lay a great dark
forest, and under an old lime-tree in the forest was a well, and when
the day was very warm, the king's child went out into the forest and
sat down by the side of the cool fountain, and when she was bored she
took a golden ball, and threw it up on high and caught it, and this
ball was her favorite plaything.
END

[72,80].each do |w|
  puts "." * w
  puts text.wrap(w)
end


import std.algorithm : sort;
import std.array : appender, split;
import std.range : take;
import std.stdio : File, writefln, writeln;
import std.typecons : Tuple;
import std.uni : toLower;

//Container for a word and how many times it has been seen
alias Pair = Tuple!(string, "k", int, "v");

void main() {
    int[string] wcnt;

    //Read the file line by line
    foreach (line; File("135-0.txt").byLine) {
        //Split the words on whitespace
        foreach (word; line.split) {
            //Increment the times the word has been seen
            wcnt[word.toLower.idup]++;
        }
    }

    //Associative arrays cannot be sort, so put the key/value in an array
    auto wb = appender!(Pair[]);
    foreach(k,v; wcnt) {
        wb.put(Pair(k,v));
    }
    Pair[] sw = wb.data.dup;

    //Sort the array, and display the top ten values
    writeln("Rank  Word        Frequency");
    int rank=1;
    foreach (word; sw.sort!"a.v>b.v".take(10)) {
        writefln("%4s  %-10s  %9s", rank++, word.k, word.v);
    }
}


program Word_frequency;

{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  System.IOUtils,
  System.Generics.Collections,
  System.Generics.Defaults,
  System.RegularExpressions;

type
  TWords = TDictionary<string, Integer>;

  TFreqPair = TPair<string, Integer>;

  TFreq = TArray<TFreqPair>;

function CreateValueCompare: IComparer<TFreqPair>;
begin
  Result := TComparer<TFreqPair>.Construct(
    function(const Left, Right: TFreqPair): Integer
    begin
      Result := Right.Value - Left.Value;
    end);
end;

function WordFrequency(const Text: string): TFreq;
var
  words: TWords;
  match: TMatch;
  w: string;
begin
  words := TWords.Create();
  match := TRegEx.Match(Text, '\w+');
  while match.Success do
  begin
    w := match.Value;
    if words.ContainsKey(w) then
      words[w] := words[w] + 1
    else
      words.Add(w, 1);
    match := match.NextMatch();
  end;

  Result := words.ToArray;
  words.Free;
  TArray.Sort<TFreqPair>(Result, CreateValueCompare);
end;

var
  Text: string;
  rank: integer;
  Freq: TFreq;
  w: TFreqPair;

begin
  Text := TFile.ReadAllText('135-0.txt').ToLower();

  Freq := WordFrequency(Text);

  Writeln('Rank  Word  Frequency');
  Writeln('====  ====  =========');

  for rank := 1 to 10 do
  begin
    w := Freq[rank - 1];
    Writeln(format('%2d   %6s   %5d', [rank, w.Key, w.Value]));
  end;

  readln;
end.


doc$ = "In olden times when wishing still helped one, there lived a king ";_
"whose daughters were all beautiful, but the youngest was so beautiful ";_
"that the sun itself, which has seen so much, was astonished whenever ";_
"it shone in her face."

wrap$ = " style='white-space: pre-wrap;white-space: -moz-pre-wrap;white-space: -pre-wrap;";_
                "white-space: -o-pre-wrap;word-wrap: break-word'"

html "

"
html "" + doc$ + "	" + doc$ + "

"


#[derive(Clone, Debug)]
pub struct LineComposer<I> {
    words: I,
    width: usize,
    current: Option<String>,
}

impl<I> LineComposer<I> {
    pub(crate) fn new<S>(words: I, width: usize) -> Self
    where
        I: Iterator<Item = S>,
        S: AsRef<str>,
    {
        LineComposer {
            words,
            width,
            current: None,
        }
    }
}

impl<I, S> Iterator for LineComposer<I>
where
    I: Iterator<Item = S>,
    S: AsRef<str>,
{
    type Item = String;

    fn next(&mut self) -> Option<Self::Item> {
        let mut next = match self.words.next() {
            None => return self.current.take(),
            Some(value) => value,
        };

        let mut current = self.current.take().unwrap_or_else(String::new);

        loop {
            let word = next.as_ref();
            if self.width <= current.len() + word.len() {
                self.current = Some(String::from(word));
                // If the first word itself is too long, avoid producing an
                // empty line. Continue instead with the next word.
                if !current.is_empty() {
                    return Some(current);
                }
            }

            if !current.is_empty() {
                current.push_str(" ")
            }

            current.push_str(word);

            match self.words.next() {
                None => return Some(current), // Last line, current remains None
                Some(word) => next = word,
            }
        }
    }
}

// This part is just to extend all suitable iterators with LineComposer

pub trait ComposeLines: Iterator {
    fn compose_lines(self, width: usize) -> LineComposer<Self>
    where
        Self: Sized,
        Self::Item: AsRef<str>,
    {
        LineComposer::new(self, width)
    }
}

impl<T, S> ComposeLines for T
where
    T: Iterator<Item = S>,
    S: AsRef<str>,
{
}

fn main() {
    let text = r"
        In olden times when wishing still helped one, there lived a king whose
        daughters were all beautiful, but the youngest was so beautiful that the
        sun itself, which has seen so much, was astonished whenever it shone in
        her face. Close by the king's castle lay a great dark forest, and under
        an old lime tree in the forest was a well, and when the day was very
        warm, the king's child went out into the forest and sat down by the side
        of the cool fountain, and when she was bored she took a golden ball, and
        threw it up on high and caught it, and this ball was her favorite
        plaything.";

    text.split_whitespace()
        .compose_lines(80)
        .for_each(|line| println!("{}", line));
}


import java.util.StringTokenizer

object WordWrap extends App {
  final val defaultLineWidth = 80
  final val spaceWidth = 1

  def letsWrap(text: String, lineWidth: Int = defaultLineWidth) = {
    println(s"\n\nWrapped at: $lineWidth")
    println("." * lineWidth)
    minNumLinesWrap(ewd, lineWidth)
  }

  final def ewd = "Vijftig jaar geleden publiceerde Edsger Dijkstra zijn kortstepadalgoritme. Daarom een kleine ode" +
    " aan de in 2002 overleden Dijkstra, iemand waar we als Nederlanders best wat trotser op mogen zijn. Dijkstra was" +
    " een van de eerste programmeurs van Nederland. Toen hij in 1957 trouwde, werd het beroep computerprogrammeur door" +
    " de burgerlijke stand nog niet erkend en uiteindelijk gaf hij maar `theoretische natuurkundige’ op.\nZijn" +
    " beroemdste resultaat is het kortstepadalgoritme, dat de kortste verbinding vindt tussen twee knopen in een graaf" +
    " (een verzameling punten waarvan sommigen verbonden zijn). Denk bijvoorbeeld aan het vinden van de kortste route" +
    " tussen twee steden. Het slimme van Dijkstra’s algoritme is dat het niet alle mogelijke routes met elkaar" +
    " vergelijkt, maar dat het stap voor stap de kortst mogelijke afstanden tot elk punt opbouwt. In de eerste stap" +
    " kijk je naar alle punten die vanaf het beginpunt te bereiken zijn en markeer je al die punten met de afstand tot" +
    " het beginpunt. Daarna kijk je steeds vanaf het punt dat op dat moment de kortste afstand heeft tot het beginpunt" +
    " naar alle punten die je vanaf daar kunt bereiken. Als je een buurpunt via een nieuwe verbinding op een snellere" +
    " manier kunt bereiken, schrijf je de nieuwe, kortere afstand tot het beginpunt bij zo’n punt. Zo ga je steeds een" +
    " stukje verder tot je alle punten hebt gehad en je de kortste route tot het eindpunt hebt gevonden."

  def minNumLinesWrap(text: String, LineWidth: Int) {
    val tokenizer = new StringTokenizer(text)
    var SpaceLeft = LineWidth
    while (tokenizer.hasMoreTokens) {
      val word: String = tokenizer.nextToken
      if ((word.length + spaceWidth) > SpaceLeft) {
        print("\n" + word + " ")
        SpaceLeft = LineWidth - word.length
      } else {
        print(word + " ")
        SpaceLeft -= (word.length + spaceWidth)
      }
    }
  }

  letsWrap(ewd)
  letsWrap(ewd, 120)
} // 44 lines


open System.IO
open System.Text.RegularExpressions
let g=Regex("[A-Za-zÀ-ÿ]+").Matches(File.ReadAllText "135-0.txt")
[for n in g do yield n.Value.ToLower()]|>List.countBy(id)|>List.sortBy(fun n->(-(snd n)))|>List.take 10|>List.iter(fun n->printfn "%A" n)


USING: ascii io math.statistics prettyprint sequences
splitting ;
IN: rosetta-code.word-count

lines " " join " .,?!:;()\"-" split harvest [ >lower ] map
sorted-histogram <reversed> 10 head .