web-dev-qa-db-fra.com

Construire un ASCII graphique des mots les plus couramment utilisés dans un texte donné

Le défi:

Construisez un ASCII graphique des mots les plus couramment utilisés dans un texte donné.

Les règles:

  • Accepter uniquement a-z et A-Z (caractères alphabétiques) dans le cadre d'un mot.
  • Ignorez le boîtier (She == she pour notre but).
  • Ignorez les mots suivants (assez arbitraire, je sais): the, and, of, to, a, i, it, in, or, is
  • Clarification: considérant don't: ce serait considéré comme 2 "mots" différents dans les plages a-z et A-Z: (don et t).

  • Facultativement (il est trop tard pour modifier officiellement les spécifications maintenant) vous pouvez choisissez de supprimer tous les "mots" d'une seule lettre (cela pourrait également entraîner un raccourcissement de la liste des ignorés).

Analyser un text donné (lire un fichier spécifié via des arguments de ligne de commande ou canalisé; présumer us-ascii) et construisez-nous un Word frequency chart avec les caractéristiques suivantes:

  • Affichez le tableau (voir également l'exemple ci-dessous) pour les 22 mots les plus courants (classés par fréquence décroissante).
  • La barre width représente le nombre d'occurrences (fréquence) du mot (proportionnellement). Ajoutez un espace et imprimez le mot.
  • Assurez-vous que ces barres (plus espace-Word-espace) toujours fit: bar + [space] + Word + [space] doit toujours être <= 80 caractères (assurez-vous de tenir compte des éventuelles longueurs de barre et de mot différentes: par exemple: le deuxième mot le plus courant pourrait être beaucoup plus long que le premier sans trop différer en fréquence). Maximize largeur de barre à l'intérieur de ces contraintes et mise à l'échelle appropriée des barres (selon les fréquences qu'elles représentent).

Un exemple:

Le texte de l'exemple peut être trouvé ici ( Alice's Adventures in Wonderland, par Lewis Carroll).

Ce texte spécifique produirait le graphique suivant:

 _________________________________________________________________________ 
 | _________________________________________________________________________ | elle 
 | _______________________________________________________________ | vous 
 | ____________________________________________________________ | dit 
 | ____________________________________________________ | alice 
 | ______________________________________________ | était 
 | __________________________________________ | 
 | ___________________________________ | comme 
 | _______________________________ | son 
 | ____________________________ | avec 
 | ____________________________ | à 
 | ___________________________ | s 
 | ___________________________ | t 
 | _________________________ | le 
 | _________________________ | tous 
 | ______________________ | ce 
 | ______________________ | pour 
 | ______________________ | avait 
 | _____________________ | mais 
 | ____________________ | être 
 | ____________________ | pas 
 | ___________________ | ils 
 | __________________ | alors 


Pour votre information: ce sont les fréquences sur lesquelles le tableau ci-dessus est construit:

 [("elle", 553), ("vous", 481), ("dit", 462), ("alice", 403), ("était", 358), ("que 
 ', 330), (' as ', 274), (' her ', 248), (' with ', 227), (' at ', 227), (' s ', 219), ( 't' 
, 218), ('on', 204), ('all', 200), ('this', 181), ('for', 179), ('had', 178 ), ('
 mais', 175), ('be', 167), ('not', 166), ('they', 155), ('so', 152)] 

Un deuxième exemple (pour vérifier si vous avez implémenté la spécification complète): Remplacez chaque occurrence de you dans le lien Alice au pays des merveilles fichier avec superlongstringstring:

 ________________________________________________________________ 
 | ________________________________________________________________ | elle 
 | _______________________________________________________ | superlongstringstring 
 | _____________________________________________________ | dit 
 | ______________________________________________ | alice 
 | ________________________________________ | était 
 | _____________________________________ | que 
 | ______________________________ | comme 
 | ___________________________ | son 
 | _________________________ | avec 
 | _________________________ | à 
 | ________________________ | s 
 | ________________________ | t 
 | ______________________ | le 
 | _____________________ | tous 
 | ___________________ | ce 
 | ___________________ | pour 
 | ___________________ | avait 
 | __________________ | mais 
 | _________________ | être 
 | _________________ | pas 
 | ________________ | ils 
 | ________________ | alors 

Le gagnant:

Solution la plus courte (par nombre de caractères, par langue). S'amuser!


Edit : Tableau résumant les résultats jusqu'à présent (2012-02-15) (initialement ajouté par l'utilisateur Nas Banov):

 Langage détendu strict 
 ========= ======= ====== 
 GolfScript 130 143 
 Perl 185 
 Windows PowerShell 148 199 
 Mathematica 199 
 Ruby 185 205 
 Unix Toolchain 194 228 
 Python 183 243 
 Clojure 282 
 Scala 311 
 Haskell 333 
 Awk 336 
 R 298 
 Javascript 304 354 
 Groovy 321 
 Matlab 404 
 C # 422 
 Smalltalk 386 
 PHP 450 
 F # 452 
 TSQL 483 507 

Les nombres représentent la longueur de la solution la plus courte dans une langue spécifique. "Strict" fait référence à une solution qui implémente complètement la spécification (dessine |____| bars, ferme la première barre en haut avec un ____ ligne, tient compte de la possibilité de mots longs à haute fréquence, etc.). "Détendu" signifie que certaines libertés ont été prises pour raccourcir la solution.

Seules les solutions de moins de 500 caractères sont incluses. La liste des langues est triée selon la longueur de la solution "stricte". 'Unix Toolchain' est utilisé pour signifier diverses solutions qui utilisent le shell * nix traditionnel plus un mélange d'outils (comme grep, tr, sort, uniq, head, Perl, awk).

156
ChristopheD

LabVIEW 51 nœuds, 5 structures, 10 diagrammes

Apprendre à l'éléphant à faire des claquettes n'est jamais joli. Je vais, ah, sauter le nombre de caractères.

labVIEW code

results

Le programme se déroule de gauche à droite:

labVIEW code explained

123
Joe Z

Ruby 1.9, 185 caractères

(fortement basé sur les autres solutions Ruby solutions)

w=($<.read.downcase.scan(/[a-z]+/)-%w{the and of to a i it in or is}).group_by{|x|x}.map{|x,y|[-y.size,x]}.sort[0,22]
k,l=w[0]
puts [?\s+?_*m=76-l.size,w.map{|f,x|?|+?_*(f*m/k)+"| "+x}]

Au lieu d'utiliser des commutateurs de ligne de commande comme les autres solutions, vous pouvez simplement passer le nom de fichier en argument. (c'est à dire. Ruby1.9 wordfrequency.rb Alice.txt)

Étant donné que j'utilise des littéraux de caractères ici, cette solution ne fonctionne que dans Ruby 1.9.

Modifier: les points-virgules remplacés par des sauts de ligne pour plus de "lisibilité". : P

Edit 2: Shtééf a souligné que j'avais oublié l'espace de fuite - corrigé cela.

Edit 3: Suppression de l'espace de fuite à nouveau;)

42
Ventero

GolfScript, 177175173167164163144131 130 caractères

Lent - 3 minutes pour l'exemple de texte (130)

{32|.123%97<n@if}%]''*n%"oftoitinorisa"2/-"theandi"3/-$(1@{.3$>1{;)}if}/]2/{~~\;}$22<.0=~:2;,76\-:1'_':0*' '\@{"
|"\~1*2/0*'| '@}/

Explication:

{           #loop through all characters
 32|.       #convert to uppercase and duplicate
 123%97<    #determine if is a letter
 n@if       #return either the letter or a newline
}%          #return an array (of ints)
]''*        #convert array to a string with magic
n%          #split on newline, removing blanks (stack is an array of words now)
"oftoitinorisa"   #Push this string
2/          #split into groups of two, i.e. ["of" "to" "it" "in" "or" "is" "a"]
-           #remove any occurrences from the text
"theandi"3/-#remove "the", "and", and "i"
$           #sort the array of words
(1@         #takes the first Word in the array, pushes a 1, reorders stack
            #the 1 is the current number of occurrences of the first Word
{           #loop through the array
 .3$>1{;)}if#increment the count or Push the next Word and a 1
}/
]2/         #gather stack into an array and split into groups of 2
{~~\;}$     #sort by the latter element - the count of occurrences of each Word
22<         #take the first 22 elements
.0=~:2;     #store the highest count
,76\-:1     #store the length of the first line
'_':0*' '\@ #make the first line
{           #loop through each Word
"
|"\~        #start drawing the bar
1*2/0       #divide by zero
*'| '@      #finish drawing the bar
}/

"Correct" (j'espère). (143)

{32|.123%97<n@if}%]''*n%"oftoitinorisa"2/-"theandi"3/-$(1@{.3$>1{;)}if}/]2/{~~\;}$22<..0=1=:^;{~76@,-^*\/}%$0=:1'_':0*' '\@{"
|"\~1*^/0*'| '@}/

Moins lent - une demi-minute. (162)

'"'/' ':S*n/S*'"#{%q
'\+"
.downcase.tr('^a-z','
')}\""+~n%"oftoitinorisa"2/-"theandi"3/-$(1@{.3$>1{;)}if}/]2/{~~\;}$22<.0=~:2;,76\-:1'_':0*S\@{"
|"\~1*2/0*'| '@}/

Sortie visible dans les journaux de révision.

39
Nabb

Solution basée sur un ensemble Transact SQL (SQL Server 2005) 1063892873853827820783683647644 630 caractères

Merci à Gabe pour quelques suggestions utiles pour réduire le nombre de personnages.

NB: Des sauts de ligne ont été ajoutés pour éviter les barres de défilement, seul le dernier saut de ligne est requis.

DECLARE @ VARCHAR(MAX),@F REAL SELECT @=BulkColumn FROM OPENROWSET(BULK'A',
SINGLE_BLOB)x;WITH N AS(SELECT 1 i,LEFT(@,1)L UNION ALL SELECT i+1,SUBSTRING
(@,i+1,1)FROM N WHERE i<LEN(@))SELECT i,L,i-RANK()OVER(ORDER BY i)R INTO #D
FROM N WHERE L LIKE'[A-Z]'OPTION(MAXRECURSION 0)SELECT TOP 22 W,-COUNT(*)C
INTO # FROM(SELECT DISTINCT R,(SELECT''+L FROM #D WHERE R=b.R FOR XML PATH
(''))W FROM #D b)t WHERE LEN(W)>1 AND W NOT IN('the','and','of','to','it',
'in','or','is')GROUP BY W ORDER BY C SELECT @F=MIN(($76-LEN(W))/-C),@=' '+
REPLICATE('_',-MIN(C)*@F)+' 'FROM # SELECT @=@+' 
|'+REPLICATE('_',-C*@F)+'| '+W FROM # ORDER BY C PRINT @

Version lisible

DECLARE @  VARCHAR(MAX),
        @F REAL
SELECT @=BulkColumn
FROM   OPENROWSET(BULK'A',SINGLE_BLOB)x; /*  Loads text file from path
                                             C:\WINDOWS\system32\A  */

/*Recursive common table expression to
generate a table of numbers from 1 to string length
(and associated characters)*/
WITH N AS
     (SELECT 1 i,
             LEFT(@,1)L

     UNION ALL

     SELECT i+1,
            SUBSTRING(@,i+1,1)
     FROM   N
     WHERE  i<LEN(@)
     )
  SELECT   i,
           L,
           i-RANK()OVER(ORDER BY i)R
           /*Will group characters
           from the same Word together*/
  INTO     #D
  FROM     N
  WHERE    L LIKE'[A-Z]'OPTION(MAXRECURSION 0)
             /*Assuming case insensitive accent sensitive collation*/

SELECT   TOP 22 W,
         -COUNT(*)C
INTO     #
FROM     (SELECT DISTINCT R,
                          (SELECT ''+L
                          FROM    #D
                          WHERE   R=b.R FOR XML PATH('')
                          )W
                          /*Reconstitute the Word from the characters*/
         FROM             #D b
         )
         T
WHERE    LEN(W)>1
AND      W NOT IN('the',
                  'and',
                  'of' ,
                  'to' ,
                  'it' ,
                  'in' ,
                  'or' ,
                  'is')
GROUP BY W
ORDER BY C

/*Just noticed this looks risky as it relies on the order of evaluation of the 
 variables. I'm not sure that's guaranteed but it works on my machine :-) */
SELECT @F=MIN(($76-LEN(W))/-C),
       @ =' '      +REPLICATE('_',-MIN(C)*@F)+' '
FROM   #

SELECT @=@+' 
|'+REPLICATE('_',-C*@F)+'| '+W
             FROM     #
             ORDER BY C

PRINT @

Sortie

 _________________________________________________________________________ 
|_________________________________________________________________________| she
|_______________________________________________________________| You
|____________________________________________________________| said
|_____________________________________________________| Alice
|_______________________________________________| was
|___________________________________________| that
|____________________________________| as
|________________________________| her
|_____________________________| at
|_____________________________| with
|__________________________| on
|__________________________| all
|_______________________| This
|_______________________| for
|_______________________| had
|_______________________| but
|______________________| be
|_____________________| not
|____________________| they
|____________________| So
|___________________| very
|__________________| what

Et avec la longue chaîne

 _______________________________________________________________ 
|_______________________________________________________________| she
|_______________________________________________________| superlongstringstring
|____________________________________________________| said
|______________________________________________| Alice
|________________________________________| was
|_____________________________________| that
|_______________________________| as
|____________________________| her
|_________________________| at
|_________________________| with
|_______________________| on
|______________________| all
|____________________| This
|____________________| for
|____________________| had
|____________________| but
|___________________| be
|__________________| not
|_________________| they
|_________________| So
|________________| very
|________________| what
35
Martin Smith

206

Shell, grep, tr, grep, sort, uniq, sort, head, Perl

~ % wc -c wfg
209 wfg
~ % cat wfg
egrep -oi \\b[a-z]+|tr A-Z a-z|egrep -wv 'the|and|of|to|a|i|it|in|or|is'|sort|uniq -c|sort -nr|head -22|Perl -lape'($f,$w)=@F;$.>1or($q,$x)=($f,76-length$w);$b="_"x($f/$q*$x);$_="|$b| $w ";$.>1or$_=" $b\n$_"'
~ % # usage:
~ % sh wfg < 11.txt

hm, juste vu ci-dessus: sort -nr -> sort -n puis head -> tail => 208 :)
update2: euh, bien sûr, ce qui précède est idiot, car il sera alors inversé. Donc, 209.
update3: optimisation de l'expression rationnelle d'exclusion -> 206

egrep -oi \\b[a-z]+|tr A-Z a-z|egrep -wv 'the|and|o[fr]|to|a|i[tns]?'|sort|uniq -c|sort -nr|head -22|Perl -lape'($f,$w)=@F;$.>1or($q,$x)=($f,76-length$w);$b="_"x($f/$q*$x);$_="|$b| $w ";$.>1or$_=" $b\n$_"'



pour le plaisir, voici une version uniquement Perl (beaucoup plus rapide):

~ % wc -c pgolf
204 pgolf
~ % cat pgolf
Perl -lne'$1=~/^(the|and|o[fr]|to|.|i[tns])$/i||$f{lc$1}++while/\b([a-z]+)/gi}{@w=(sort{$f{$b}<=>$f{$a}}keys%f)[0..21];$Q=$f{$_=$w[0]};$B=76-y///c;print" "."_"x$B;print"|"."_"x($B*$f{$_}/$Q)."| $_"for@w'
~ % # usage:
~ % sh pgolf < 11.txt
35
stor

Rubis 207213211210207203201 200 caractères

Une amélioration sur Anurag, intégrant la suggestion de rfusca. Supprime également l'argument de tri et quelques autres golfs mineurs.

w=(STDIN.read.downcase.scan(/[a-z]+/)-%w{the and of to a i it in or is}).group_by{|x|x}.map{|x,y|[-y.size,x]}.sort.take 22;k,l=w[0];m=76.0-l.size;puts' '+'_'*m;w.map{|f,x|puts"|#{'_'*(m*f/k)}| #{x} "}

Exécuter en tant que:

Ruby GolfedWordFrequencies.rb < Alice.txt

Edit: replacez les "met", doit être là pour éviter d'avoir des guillemets en sortie.
Edit2: Fichier modifié-> IO
Edit3: supprimé/i
Edit4: Suppression des parenthèses autour (f * 1.0), recompté
Edit5: utilisez l'ajout de chaîne pour la première ligne; développez s sur place.
Edit6: Fait flotter m, supprimé 1.0. EDIT: ne fonctionne pas, modifie les longueurs. EDIT: Pas pire qu'avant
Edit7: utilisez STDIN.read.

34
archgoon

Mathematica (297284248244242 199 caractères) Fonctionnel pur

et test de loi de Zipf

Regardez maman ... pas de vars, pas de mains, .. pas de tête

Édition 1> quelques raccourcis définis (284 caractères)

f[x_, y_] := Flatten[Take[x, All, y]]; 

BarChart[f[{##}, -1], 
         BarOrigin -> Left, 
         ChartLabels -> Placed[f[{##}, 1], After], 
         Axes -> None
] 
& @@
Take[
  SortBy[
     Tally[
       Select[
        StringSplit[ToLowerCase[Import[i]], RegularExpression["\\W+"]], 
       !MemberQ[{"the", "and", "of", "to", "a", "i", "it", "in", "or","is"}, #]&]
     ], 
  Last], 
-22]

Quelques explications

Import[] 
   # Get The File

ToLowerCase []
   # To Lower Case :)

StringSplit[ STRING , RegularExpression["\\W+"]]
   # Split By Words, getting a LIST

Select[ LIST, !MemberQ[{LIST_TO_AVOID}, #]&]
   #  Select from LIST except those words in LIST_TO_AVOID
   #  Note that !MemberQ[{LIST_TO_AVOID}, #]& is a FUNCTION for the test

Tally[LIST]
   # Get the LIST {Word,word,..} 
     and produce another  {{Word,counter},{Word,counter}...}

SortBy[ LIST ,Last]
   # Get the list produced bt tally and sort by counters
     Note that counters are the LAST element of {Word,counter}

Take[ LIST ,-22]
   # Once sorted, get the biggest 22 counters

BarChart[f[{##}, -1], ChartLabels -> Placed[f[{##}, 1], After]] &@@ LIST
   # Get the list produced by Take as input and produce a bar chart

f[x_, y_] := Flatten[Take[x, All, y]]
   # Auxiliary to get the list of the first or second element of lists of lists x_
     dependending upon y
   # So f[{##}, -1] is the list of counters
   # and f[{##}, 1] is the list of words (labels for the chart)

Sortie

texte alternatif http://i49.tinypic.com/2n8mrer.jpg

Mathematica n'est pas bien adapté pour le golf, et c'est simplement à cause des noms de fonctions longs et descriptifs. Des fonctions comme "RegularExpression []" ou "StringSplit []" me font juste sangloter :(.

Test de loi de Zipf

Le loi de Zipf prédit que pour un texte en langage naturel, le Log (Rank) vs Journal (occurrences) Le tracé suit une relation linéaire .

La loi est utilisée dans le développement d'algorithmes de criptographie et de compression de données. (Mais ce n'est PAS le "Z" dans l'algorithme LZW).

Dans notre texte, nous pouvons le tester avec les éléments suivants

 f[x_, y_] := Flatten[Take[x, All, y]]; 
 ListLogLogPlot[
     Reverse[f[{##}, -1]], 
     AxesLabel -> {"Log (Rank)", "Log Counter"}, 
     PlotLabel -> "Testing Zipf's Law"]
 & @@
 Take[
  SortBy[
    Tally[
       StringSplit[ToLowerCase[b], RegularExpression["\\W+"]]
    ], 
   Last],
 -1000]

Le résultat est (assez bien linéaire)

texte alternatif http://i46.tinypic.com/33fcmdk.jpg

Édition 6> (242 caractères)

Refactorisation du Regex (plus de fonction Select)
Suppression de 1 mot de caractère
Définition plus efficace de la fonction "f"

f = Flatten[Take[#1, All, #2]]&; 
BarChart[
     f[{##}, -1], 
     BarOrigin -> Left, 
     ChartLabels -> Placed[f[{##}, 1], After], 
     Axes -> None] 
& @@
  Take[
    SortBy[
       Tally[
         StringSplit[ToLowerCase[Import[i]], 
          RegularExpression["(\\W|\\b(.|the|and|of|to|i[tns]|or)\\b)+"]]
       ],
    Last],
  -22]

Modifier 7 → 199 caractères

BarChart[#2, BarOrigin->Left, ChartLabels->Placed[#1, After], Axes->None]&@@ 
  Transpose@Take[SortBy[Tally@StringSplit[ToLowerCase@Import@i, 
    RegularExpression@"(\\W|\\b(.|the|and|of|to|i[tns]|or)\\b)+"],Last], -22]
  • f remplacé par Transpose et Slot (#1/#2) arguments.
  • Nous n'avons pas besoin de parenthèses puantes (utilisez f@x au lieu de f[x] lorsque c'est possible)

28
Dr. belisarius

C # - 510451436446434426 422 caractères (minifiés)

Pas si court, mais maintenant probablement correct! Remarque, la version précédente n'affichait pas la première ligne des barres, ne mettait pas à l'échelle les barres correctement, téléchargeait le fichier au lieu de l'obtenir depuis stdin et n'incluait pas toute la verbosité C # requise. Vous pourriez facilement raser de nombreux coups si C # n'avait pas besoin de tant de merde supplémentaire. Peut-être que Powershell pourrait faire mieux.

using C=System.Console;   // alias for Console
using System.Linq;  // for Split, GroupBy, Select, OrderBy, etc.

class Class // must define a class
{
    static void Main()  // must define a Main
    {
        // split into words
        var allwords = System.Text.RegularExpressions.Regex.Split(
                // convert stdin to lowercase
                C.In.ReadToEnd().ToLower(),
                // eliminate stopwords and non-letters
                @"(?:\b(?:the|and|of|to|a|i[tns]?|or)\b|\W)+")
            .GroupBy(x => x)    // group by words
            .OrderBy(x => -x.Count()) // sort descending by count
            .Take(22);   // take first 22 words

        // compute length of longest bar + Word
        var lendivisor = allwords.Max(y => y.Count() / (76.0 - y.Key.Length));

        // prepare text to print
        var toPrint = allwords.Select(x=> 
            new { 
                // remember bar pseudographics (will be used in two places)
                Bar = new string('_',(int)(x.Count()/lendivisor)), 
                Word=x.Key 
            })
            .ToList();  // convert to list so we can index into it

        // print top of first bar
        C.WriteLine(" " + toPrint[0].Bar);
        toPrint.ForEach(x =>  // for each Word, print its bar and the Word
            C.WriteLine("|" + x.Bar + "| " + x.Word));
    }
}

422 caractères avec lendivisor en ligne (ce qui le rend 22 fois plus lent) dans le formulaire ci-dessous (nouvelles lignes utilisées pour certains espaces):

using System.Linq;using C=System.Console;class M{static void Main(){var
a=System.Text.RegularExpressions.Regex.Split(C.In.ReadToEnd().ToLower(),@"(?:\b(?:the|and|of|to|a|i[tns]?|or)\b|\W)+").GroupBy(x=>x).OrderBy(x=>-x.Count()).Take(22);var
b=a.Select(x=>new{p=new string('_',(int)(x.Count()/a.Max(y=>y.Count()/(76d-y.Key.Length)))),t=x.Key}).ToList();C.WriteLine(" "+b[0].p);b.ForEach(x=>C.WriteLine("|"+x.p+"| "+x.t));}}
27
Paul Creasey

Perl, 237229 209 caractères

(Mis à jour à nouveau pour battre la version Ruby avec des astuces de golf plus sales, remplaçant split/[^a-z/,lc avec lc=~/[a-z]+/g, et en éliminant la vérification de la chaîne vide à un autre endroit. Celles-ci ont été inspirées par la Ruby, donc crédit à l'endroit où le crédit est dû.)

Mise à jour: maintenant avec Perl 5.10! Remplacez print par say et utilisez ~~ pour éviter un map. Cela doit être appelé sur la ligne de commande en tant que Perl -E '<one-liner>' alice.txt. Étant donné que le script entier est sur une seule ligne, l'écrire en une seule ligne ne devrait pas poser de problème :).

 @s=qw/the and of to a i it in or is/;$c{$_}++foreach grep{!($_~~@s)}map{lc=~/[a-z]+/g}<>;@s=sort{$c{$b}<=>$c{$a}}keys%c;$f=76-length$s[0];say" "."_"x$f;say"|"."_"x($c{$_}/$c{$s[0]}*$f)."| $_ "foreach@s[0..21];

Notez que cette version se normalise pour le cas. Cela ne raccourcit pas la solution, car la suppression de ,lc (pour les minuscules) vous oblige à ajouter A-Z au regex divisé, donc c'est un lavage.

Si vous êtes sur un système où une nouvelle ligne est un caractère et non deux, vous pouvez raccourcir cela de deux autres caractères en utilisant une nouvelle ligne littérale à la place de \n. Cependant, je n'ai pas écrit l'exemple ci-dessus de cette façon, car c'est "plus clair" (ha!) De cette façon.


Voici une solution Perl généralement correcte, mais pas assez courte:

use strict;
use warnings;

my %short = map { $_ => 1 } qw/the and of to a i it in or is/;
my %count = ();

$count{$_}++ foreach grep { $_ && !$short{$_} } map { split /[^a-zA-Z]/ } (<>);
my @sorted = (sort { $count{$b} <=> $count{$a} } keys %count)[0..21];
my $widest = 76 - (length $sorted[0]);

print " " . ("_" x $widest) . "\n";
foreach (@sorted)
{
    my $width = int(($count{$_} / $count{$sorted[0]}) * $widest);
    print "|" . ("_" x $width) . "| $_ \n";
}

Ce qui suit est à peu près aussi court que possible tout en restant relativement lisible. (392 caractères).

%short = map { $_ => 1 } qw/the and of to a i it in or is/;
%count;

$count{$_}++ foreach grep { $_ && !$short{$_} } map { split /[^a-z]/, lc } (<>);
@sorted = (sort { $count{$b} <=> $count{$a} } keys %count)[0..21];
$widest = 76 - (length $sorted[0]);

print " " . "_" x $widest . "\n";
print"|" . "_" x int(($count{$_} / $count{$sorted[0]}) * $widest) . "| $_ \n" foreach @sorted;
25
JSBձոգչ

Windows PowerShell, 199 caractères

$x=$input-split'\P{L}'-notmatch'^(the|and|of|to|.?|i[tns]|or)$'|group|sort *
filter f($w){' '+'_'*$w
$x[-1..-22]|%{"|$('_'*($w*$_.Count/$x[-1].Count))| "+$_.Name}}
f(76..1|?{!((f $_)-match'.'*80)})[0]

(Le dernier saut de ligne n'est pas nécessaire, mais inclus ici pour plus de lisibilité.)

(Code actuel et mes fichiers de test disponibles dans mon référentiel SVN . J'espère que mes cas de test détectent les erreurs les plus courantes (longueur de barre, problèmes de correspondance d'expressions rationnelles et quelques autres))

Hypothèses:

  • US ASCII en entrée. Cela devient probablement bizarre avec Unicode.
  • Au moins deux mots non-stop dans le texte

Historique

Version détendue (137), car cela est désormais compté séparément, apparemment:

($x=$input-split'\P{L}'-notmatch'^(the|and|of|to|.?|i[tns]|or)$'|group|sort *)[-1..-22]|%{"|$('_'*(76*$_.Count/$x[-1].Count))| "+$_.Name}
  • ne ferme pas la première barre
  • ne tient pas compte de la longueur de mot du premier mot

Les variations des longueurs de barre d'un caractère par rapport à d'autres solutions sont dues au fait que PowerShell utilise l'arrondi au lieu de la troncature lors de la conversion de nombres à virgule flottante en entiers. Étant donné que la tâche ne nécessitait qu'une longueur de barre proportionnelle, cela devrait être bien, cependant.

Par rapport à d'autres solutions, j'ai adopté une approche légèrement différente pour déterminer la longueur de barre la plus longue en essayant simplement et en prenant la longueur la plus élevée lorsqu'aucune ligne ne dépasse 80 caractères.

Une ancienne version expliquée peut être trouvée ici .

20
Joey

Rubis, 215, 216218221224236237 caractères

mise à jour 1: Hourra ! C'est une égalité avec JS Bangs ' solution . Je ne peux pas penser à un moyen de réduire davantage :)

mise à jour 2: joué un sale tour de golf. each a été remplacé par map pour enregistrer 1 caractère :)

mise à jour 3: Changé File.read à IO.read +2. Array.group_by n'était pas très fructueux, remplacé par reduce +6. La vérification insensible à la casse n'est pas nécessaire après une casse inférieure avec downcase dans regex +1. Le tri dans l'ordre décroissant se fait facilement en annulant la valeur +6. Économies totales +15

mise à jour 4: [0] plutôt que .first, +3. (@ Shtééf)

mise à jour 5: Développez la variable l sur place, +1. Développez la variable s sur place, +2. (@ Shtééf)

mise à jour 6: utilisez l'ajout de chaînes plutôt que l'interpolation pour la première ligne, +2. (@ Shtééf)

w=(IO.read($_).downcase.scan(/[a-z]+/)-%w{the and of to a i it in or is}).reduce(Hash.new 0){|m,o|m[o]+=1;m}.sort_by{|k,v|-v}.take 22;m=76-w[0][0].size;puts' '+'_'*m;w.map{|x,f|puts"|#{'_'*(f*1.0/w[0][1]*m)}| #{x} "}

mise à jour 7: j'ai parcouru pas mal de hoopla pour détecter la première itération à l'intérieur la boucle, en utilisant des variables d'instance. Tout ce que j'ai obtenu est +1, bien qu'il y ait peut-être un potentiel. Préserver la version précédente, car je crois que celle-ci est de la magie noire. (@ Shtééf)

(IO.read($_).downcase.scan(/[a-z]+/)-%w{the and of to a i it in or is}).reduce(Hash.new 0){|m,o|m[o]+=1;m}.sort_by{|k,v|-v}.take(22).map{|x,f|@f||(@f=f;puts' '+'_'*(@m=76-x.size));puts"|#{'_'*(f*1.0/@f*@m)}| #{x} "}

Version lisible

string = File.read($_).downcase

words = string.scan(/[a-z]+/i)
allowed_words = words - %w{the and of to a i it in or is}
sorted_words = allowed_words.group_by{ |x| x }.map{ |x,y| [x, y.size] }.sort{ |a,b| b[1] <=> a[1] }.take(22)
highest_frequency = sorted_words.first
highest_frequency_count = highest_frequency[1]
highest_frequency_Word = highest_frequency[0]

Word_length = highest_frequency_Word.size
widest = 76 - Word_length

puts " #{'_' * widest}"    
sorted_words.each do |Word, freq|
  width = (freq * 1.0 / highest_frequency_count) * widest
  puts "|#{'_' * width}| #{Word} "
end

Utiliser:

echo "Alice.txt" | Ruby -ln GolfedWordFrequencies.rb

Sortie:

 _________________________________________________________________________
|_________________________________________________________________________| she 
|_______________________________________________________________| you 
|____________________________________________________________| said 
|_____________________________________________________| alice 
|_______________________________________________| was 
|___________________________________________| that 
|____________________________________| as 
|________________________________| her 
|_____________________________| with 
|_____________________________| at 
|____________________________| s 
|____________________________| t 
|__________________________| on 
|__________________________| all 
|_______________________| this 
|_______________________| for 
|_______________________| had 
|_______________________| but 
|______________________| be 
|_____________________| not 
|____________________| they 
|____________________| so 
19
Anurag

Python 2.x, approche latitudinale = 227 183 caractères

import sys,re
t=re.split('\W+',sys.stdin.read().lower())
r=sorted((-t.count(w),w)for w in set(t)if w not in'andithetoforinis')[:22]
for l,w in r:print(78-len(r[0][1]))*l/r[0][0]*'=',w

Permettant la liberté dans l'implémentation, j'ai construit une concaténation de chaînes qui contient tous les mots demandés pour l'exclusion (the, and, of, to, a, i, it, in, or, is) - en plus elle exclut également les deux fameux "mots" s et t de l'exemple - et j'ai ajouté gratuitement l'exclusion pour an, for, he. J'ai essayé toutes les concaténations de ces mots contre le corpus des mots d'Alice, de la Bible de King James et du fichier Jargon pour voir s'il y a des mots qui seront mal exclus par la chaîne. Et c'est ainsi que j'ai fini avec deux chaînes d'exclusion: itheandtoforinis et andithetoforinis.

PS. emprunté à d'autres solutions pour raccourcir le code.

=========================================================================== she 
================================================================= you
============================================================== said
====================================================== alice
================================================ was
============================================ that
===================================== as
================================= her
============================== at
============================== with
=========================== on
=========================== all
======================== this
======================== had
======================= but
====================== be
====================== not
===================== they
==================== so
=================== very
=================== what
================= little

Rant

En ce qui concerne les mots à ignorer, on pourrait penser qu'ils seraient tirés de la liste des mots les plus utilisés en anglais. Cette liste dépend du corpus de texte utilisé. Par l'une des listes les plus populaires ( http://en.wikipedia.org/wiki/Most_common_words_in_English , http://www.english-for-students.com/Frequently-Used -Words.html , http://www.sporcle.com/games/common_english_words.php ), les 10 premiers mots sont: the be(am/are/is/was/were) to of and a in that have I

Les 10 premiers mots du texte d'Alice au pays des merveilles sont the and to a of it she i you said
Les 10 premiers mots du fichier de jargon (v4.4.7) sont the a of to and in is that or for

La question est donc de savoir pourquoi or a été inclus dans la liste d'ignorance du problème, où il est ~ 30e en popularité alors que le mot that (8e plus utilisé) ne l'est pas. etc, etc. Par conséquent, je pense que la liste des ignorés devrait être fournie dynamiquement (ou pourrait être omise).

L'idée alternative serait simplement de sauter les 10 premiers mots du résultat - ce qui en fait raccourcirait la solution (élémentaire - ne devrait afficher que les 11e à 32e entrées).


Python 2.x, approche ponctuelle = 277 243 caractères

Le graphique dessiné dans le code ci-dessus est simplifié (en utilisant un seul caractère pour les barres). Si l'on veut reproduire exactement le graphique de la description du problème (ce qui n'était pas obligatoire), ce code le fera:

import sys,re
t=re.split('\W+',sys.stdin.read().lower())
r=sorted((-t.count(w),w)for w in set(t)-set(sys.argv))[:22]
h=min(9*l/(77-len(w))for l,w in r)
print'',9*r[0][0]/h*'_'
for l,w in r:print'|'+9*l/h*'_'+'|',w

Je prends un problème avec le choix quelque peu aléatoire des 10 mots à exclure the, and, of, to, a, i, it, in, or, is Donc ceux-ci doivent être passés en tant que paramètres de ligne de commande, comme ceci:
python WordFrequencyChart.py the and of to a i it in or is <"Alice's Adventures in Wonderland.txt"

Il s'agit de 213 caractères + 30 si nous tenons compte de la liste d'ignorations "d'origine" transmise sur la ligne de commande = 243

PS. Le second code fait également un "ajustement" pour les longueurs de tous les premiers mots, donc aucun d'entre eux ne débordera en cas de dégénérescence.

 _______________________________________________________________
|_______________________________________________________________| she
|_______________________________________________________| superlongstringstring
|_____________________________________________________| said
|______________________________________________| alice
|_________________________________________| was
|______________________________________| that
|_______________________________| as
|____________________________| her
|__________________________| at
|__________________________| with
|_________________________| s
|_________________________| t
|_______________________| on
|_______________________| all
|____________________| this
|____________________| for
|____________________| had
|____________________| but
|___________________| be
|___________________| not
|_________________| they
|_________________| so
19
Nas Banov

Haskell - 366351344337 333 caractères

(Un saut de ligne dans main a été ajouté pour plus de lisibilité, et aucun saut de ligne n'est nécessaire à la fin de la dernière ligne.)

import Data.List
import Data.Char
l=length
t=filter
m=map
f c|isAlpha c=toLower c|0<1=' '
h w=(-l w,head w)
x!(q,w)='|':replicate(minimum$m(q?)x)'_'++"| "++w
q?(g,w)=q*(77-l w)`div`g
b x=m(x!)x
a(l:r)=(' ':t(=='_')l):l:r
main=interact$unlines.a.b.take 22.sort.m h.group.sort
  .t(`notElem`words"the and of to a i it in or is").words.m f

Son fonctionnement est mieux vu en lisant l'argument à interact à l'envers:

  • map f alphabétique en minuscules, remplace tout le reste par des espaces.
  • words produit une liste de mots, supprimant les espaces de séparation.
  • filter (notElemwords "the and of to a i it in or is") supprime toutes les entrées contenant des mots interdits.
  • group . sort trie les mots et regroupe les mots identiques dans des listes.
  • map h mappe chaque liste de mots identiques à un Tuple de la forme (-frequency, Word).
  • take 22 . sort trie les tuples par fréquence décroissante (la première entrée de Tuple) et ne conserve que les 22 premiers tuples.
  • b mappe les tuples aux barres (voir ci-dessous).
  • a ajoute la première ligne de soulignements pour compléter la barre supérieure.
  • unlines joint toutes ces lignes avec des retours à la ligne.

Le plus difficile est d'obtenir la bonne longueur de barre. J'ai supposé que seuls les traits de soulignement comptaient pour la longueur de la barre, donc || serait une barre de longueur nulle. La fonction b mappe c x sur x, où x est la liste des histogrammes. La liste entière est passée à c, afin que chaque invocation de c puisse calculer le facteur d'échelle pour elle-même en appelant u. De cette façon, j'évite d'utiliser des mathématiques ou des rationnels à virgule flottante, dont les fonctions de conversion et les importations consomment de nombreux caractères.

Notez l'astuce d'utiliser -frequency. Cela supprime la nécessité de reverse le sort depuis le tri (croissant) -frequency placera les mots avec la plus grande fréquence en premier. Plus tard, dans la fonction u, deux -frequency les valeurs sont multipliées, ce qui annulera la négation.

12
Thomas

Version PHP CLI (450 caractères)

Cette solution prend en compte la dernière exigence que la plupart des puristes ont choisi d'ignorer. Cela a coûté 170 caractères!

Utilisation: php.exe <this.php> <file.txt>

Minifié:

<?php $a=array_count_values(array_filter(preg_split('/[^a-z]/',strtolower(file_get_contents($argv[1])),-1,1),function($x){return !preg_match("/^(.|the|and|of|to|it|in|or|is)$/",$x);}));arsort($a);$a=array_slice($a,0,22);function R($a,$F,$B){$r=array();foreach($a as$x=>$f){$l=strlen($x);$r[$x]=$b=$f*$B/$F;if($l+$b>76)return R($a,$f,76-$l);}return$r;}$c=R($a,max($a),76-strlen(key($a)));foreach($a as$x=>$f)echo '|',str_repeat('-',$c[$x]),"| $x\n";?>

Lisible par l'homme:

<?php

// Read:
$s = strtolower(file_get_contents($argv[1]));

// Split:
$a = preg_split('/[^a-z]/', $s, -1, PREG_SPLIT_NO_EMPTY);

// Remove unwanted words:
$a = array_filter($a, function($x){
       return !preg_match("/^(.|the|and|of|to|it|in|or|is)$/",$x);
     });

// Count:
$a = array_count_values($a);

// Sort:
arsort($a);

// Pick top 22:
$a=array_slice($a,0,22);


// Recursive function to adjust bar widths
// according to the last requirement:
function R($a,$F,$B){
    $r = array();
    foreach($a as $x=>$f){
        $l = strlen($x);
        $r[$x] = $b = $f * $B / $F;
        if ( $l + $b > 76 )
            return R($a,$f,76-$l);
    }
    return $r;
}

// Apply the function:
$c = R($a,max($a),76-strlen(key($a)));


// Output:
foreach ($a as $x => $f)
    echo '|',str_repeat('-',$c[$x]),"| $x\n";

?>

Sortie:

|-------------------------------------------------------------------------| she
|---------------------------------------------------------------| you
|------------------------------------------------------------| said
|-----------------------------------------------------| alice
|-----------------------------------------------| was
|-------------------------------------------| that
|------------------------------------| as
|--------------------------------| her
|-----------------------------| at
|-----------------------------| with
|--------------------------| on
|--------------------------| all
|-----------------------| this
|-----------------------| for
|-----------------------| had
|-----------------------| but
|----------------------| be
|---------------------| not
|--------------------| they
|--------------------| so
|-------------------| very
|------------------| what

Lorsqu'il y a un long mot, les barres sont ajustées correctement:

|--------------------------------------------------------| she
|---------------------------------------------------| thisisareallylongwordhere
|-------------------------------------------------| you
|-----------------------------------------------| said
|-----------------------------------------| alice
|------------------------------------| was
|---------------------------------| that
|---------------------------| as
|-------------------------| her
|-----------------------| with
|-----------------------| at
|--------------------| on
|--------------------| all
|------------------| this
|------------------| for
|------------------| had
|-----------------| but
|-----------------| be
|----------------| not
|---------------| they
|---------------| so
|--------------| very
11
user382874

JavaScript 1.8 (SpiderMonkey) - 354

x={};p='|';e=' ';z=[];c=77
while(l=readline())l.toLowerCase().replace(/\b(?!(the|and|of|to|a|i[tns]?|or)\b)\w+/g,function(y)x[y]?x[y].c++:z.Push(x[y]={w:y,c:1}))
z=z.sort(function(a,b)b.c-a.c).slice(0,22)
for each(v in z){v.r=v.c/z[0].c
c=c>(l=(77-v.w.length)/v.r)?l:c}for(k in z){v=z[k]
s=Array(v.r*c|0).join('_')
if(!+k)print(e+s+e)
print(p+s+p+e+v.w)}

Malheureusement, la for([k,v]in z) de la version Rhino ne semble pas vouloir fonctionner dans SpiderMonkey, et readFile() est un peu plus facile que d'utiliser readline() mais en passant à 1.8 nous permet d'utiliser des fermetures de fonctions pour couper quelques lignes de plus ....

Ajout d'espaces pour la lisibilité:

x={};p='|';e=' ';z=[];c=77
while(l=readline())
  l.toLowerCase().replace(/\b(?!(the|and|of|to|a|i[tns]?|or)\b)\w+/g,
   function(y) x[y] ? x[y].c++ : z.Push( x[y] = {w: y, c: 1} )
  )
z=z.sort(function(a,b) b.c - a.c).slice(0,22)
for each(v in z){
  v.r=v.c/z[0].c
  c=c>(l=(77-v.w.length)/v.r)?l:c
}
for(k in z){
  v=z[k]
  s=Array(v.r*c|0).join('_')
  if(!+k)print(e+s+e)
  print(p+s+p+e+v.w)
}

tilisation:js golf.js < input.txt

Sortie:

 _________________________________________________________________________ 
 | _________________________________________________________________________ | elle 
 | _______________________________________________________________ | vous 
 | ____________________________________________________________ | dit 
 | ____________________________________________________ | alice 
 | ______________________________________________ | était 
 | ___________________________________________ | 
 | ___________________________________ | comme 
 | ________________________________ | son 
 | _____________________________ | à 
 | _____________________________ | avec 
 | ____________________________ | s 
 | ____________________________ | t 
 | __________________________ | le 
 | _________________________ | tous 
 | _______________________ | ce 
 | ______________________ | pour 
 | ______________________ | avait 
 | ______________________ | mais 
 | _____________________ | être 
 | _____________________ | pas 
 | ___________________ | ils 
 | ___________________ | alors

(version de base - ne gère pas les largeurs de barre correctement)

JavaScript (Rhino) - 405395387377368343 304 caractères

Je pense que ma logique de tri est désactivée, mais .. je ne sais pas. Brainfart fixe.

Minified (abuser de \n Est parfois interprété comme un ;):

x={};p='|';e=' ';z=[]
readFile(arguments[0]).toLowerCase().replace(/\b(?!(the|and|of|to|a|i[tns]?|or)\b)\w+/g,function(y){x[y]?x[y].c++:z.Push(x[y]={w:y,c:1})})
z=z.sort(function(a,b){return b.c-a.c}).slice(0,22)
for([k,v]in z){s=Array((v.c/z[0].c)*70|0).join('_')
if(!+k)print(e+s+e)
print(p+s+p+e+v.w)}
11
Matt

Python 3.1 - 245 229 carats

Je suppose que l'utilisation de Counter est une sorte de tricherie :) Je viens de lire à ce sujet il y a environ une semaine, donc c'était l'occasion idéale de voir comment cela fonctionne.

import re,collections
o=collections.Counter([w for w in re.findall("[a-z]+",open("!").read().lower())if w not in"a and i in is it of or the to".split()]).most_common(22)
print('\n'.join('|'+76*v//o[0][1]*'_'+'| '+k for k,v in o))

Imprime:

|____________________________________________________________________________| she
|__________________________________________________________________| you
|_______________________________________________________________| said
|_______________________________________________________| alice
|_________________________________________________| was
|_____________________________________________| that
|_____________________________________| as
|__________________________________| her
|_______________________________| with
|_______________________________| at
|______________________________| s
|_____________________________| t
|____________________________| on
|___________________________| all
|________________________| this
|________________________| for
|________________________| had
|________________________| but
|______________________| be
|______________________| not
|_____________________| they
|____________________| so

Une partie du code a été "empruntée" à la solution d'AKX.

11
Sam Dolan

Perl, 205191 189 caractères/205 caractères (entièrement mis en œuvre)

Certaines parties ont été inspirées par les soumissions antérieures de Perl/Ruby, quelques idées similaires ont été élaborées indépendamment, les autres sont originales. La version plus courte incorpore également certaines choses que j'ai vues/apprises d'autres soumissions.

Original:

$k{$_}++for grep{$_!~/^(the|and|of|to|a|i|it|in|or|is)$/}map{lc=~/[a-z]+/g}<>;@t=sort{$k{$b}<=>$k{$a}}keys%k;$l=76-length$t[0];printf" %s
",'_'x$l;printf"|%s| $_
",'_'x int$k{$_}/$k{$t[0]}*$l for@t[0..21];

Dernière version jusqu'à 191 caractères:

/^(the|and|of|to|.|i[tns]|or)$/||$k{$_}++for map{lc=~/[a-z]+/g}<>;@e=sort{$k{$b}<=>$k{$a}}keys%k;$n=" %s
";$r=(76-y///c)/$k{$_=$e[0]};map{printf$n,'_'x($k{$_}*$r),$_;$n="|%s| %s
"}@e[0,0..21]

Dernière version jusqu'à 189 caractères:

/^(the|and|of|to|.|i[tns]|or)$/||$k{$_}++for map{lc=~/[a-z]+/g}<>;@_=sort{$k{$b}<=>$k{$a}}keys%k;$n=" %s
";$r=(76-m//)/$k{$_=$_[0]};map{printf$n,'_'x($k{$_}*$r),$_;$n="|%s| %s
"}@_[0,0..21]

Cette version (205 caractères) représente les lignes avec des mots plus longs que ce qui serait trouvé plus tard.

/^(the|and|of|to|.|i[tns]|or)$/||$k{$_}++for map{lc=~/[a-z]+/g}<>;($r)=sort{$a<=>$b}map{(76-y///c)/$k{$_}}@e=sort{$k{$b}<=>$k{$a}}keys%k;$n=" %s
";map{printf$n,'_'x($k{$_}*$r),$_;$n="|%s| %s
";}@e[0,0..21]
11
pdehaan

Perl: 203202201198195208 203/231 caractères

$/=\0;/^(the|and|of|to|.|i[tns]|or)$/i||$x{lc$_}++for<>=~/[a-z]+/gi;map{$z=$x{$_};$y||{$y=(76-y///c)/$z}&&warn" "."_"x($z*$y)."\n";printf"|%.78s\n","_"x($z*$y)."| $_"}(sort{$x{$b}<=>$x{$a}}keys%x)[0..21]

Implémentation alternative et complète, y compris le comportement indiqué (barre de compression globale) pour le cas pathologique dans lequel le mot secondaire est à la fois populaire et suffisamment long pour se combiner à plus de 80 caractères (cette implémentation est de 231 caractères):

$/=\0;/^(the|and|of|to|.|i[tns]|or)$/i||$x{lc$_}++for<>=~/[a-z]+/gi;@e=(sort{$x{$b}<=>$x{$a}}keys%x)[0..21];for(@e){$p=(76-y///c)/$x{$_};($y&&$p>$y)||($y=$p)}warn" "."_"x($x{$e[0]}*$y)."\n";for(@e){warn"|"."_"x($x{$_}*$y)."| $_\n"}

La spécification n'indiquait nulle part que cela devait aller à STDOUT, j'ai donc utilisé warn () de Perl au lieu d'imprimer - quatre caractères enregistrés là. Carte utilisée au lieu de foreach, mais j'ai l'impression qu'il pourrait encore y avoir plus d'économies dans la division (join ()). Pourtant, il est descendu à 203 - pourrait dormir dessus. Au moins Perl est désormais sous le nombre de caractères "Shell, grep, tr, grep, sort, uniq, sort, head, Perl" pour l'instant;)

PS: Reddit dit "Salut";)

Mise à jour: suppression de join () en faveur de l'affectation et de la jointure de conversion scalaire implicite. Jusqu'à 202. Veuillez également noter que j'ai profité de la règle facultative "ignorer les mots à 1 lettre" pour raser 2 caractères, alors gardez à l'esprit que le nombre de fréquences reflétera cela.

Mise à jour 2: permutation de l'affectation et jointure implicite pour avoir tué $/pour obtenir le fichier en une seule fois en utilisant <> en premier lieu. Même taille, mais plus méchant. Échangé si (! $ Y) {} pour $ y || {} &&, sauvé 1 char supplémentaire => 201.

Mise à jour 3: pris le contrôle des minuscules tôt (lc <>) en déplaçant lc hors du bloc de carte - Échange les deux expressions régulières pour ne plus utiliser l'option/i, car elle n'est plus nécessaire. Construction conditionnelle x? Y: z conditionnelle échangée pour le Perlgolf traditionnel || construction conditionnelle implicite - /^...$/i?1:$x{$}++ pour /^...$/||$x{$} ++ Enregistré trois caractères! => 198, a franchi la barrière des 200. Pourrait dormir bientôt ... peut-être.

Mise à jour 4: La privation de sommeil m'a rendu fou. Bien. Plus fou. En pensant que cela n'a qu'à analyser les fichiers de texte heureux normaux, je l'ai fait abandonner s'il atteint une valeur nulle. Enregistré deux caractères. "Longueur" remplacé par le 1-caractère plus court (et beaucoup plus golfique) y /// c - vous m'entendez, GolfScript ?? Je viens pour toi!!! sanglot

Mise à jour 5: Sleep dep m'a fait oublier la limite de 22 lignes et la limite de ligne suivante. Sauvegardez jusqu'à 208 avec ceux traités. Pas trop mal, 13 personnages à gérer ce n'est pas la fin du monde. Joué avec l'eval en ligne regex de Perl, mais ayant du mal à le faire fonctionner et enregistrer les caractères ... lol. Mise à jour de l'exemple pour correspondre à la sortie actuelle.

Mise à jour 6: Suppression des accolades inutiles protégeant (...) pour, car le bonbon syntaxique ++ permet de le heurter heureusement contre le pour. Merci à la contribution de Chas. Owens (rappelant mon cerveau fatigué), a obtenu la solution de classe de caractère i [tns] là-dedans. Redescendre à 203.

Mise à jour 7: Ajout d'un deuxième travail, mise en œuvre complète des spécifications (y compris le comportement complet de compression des barres pour les mots longs secondaires, au lieu de la troncature que la plupart des gens font, sur la base des spécifications originales sans l'exemple pathologique)

Exemples:

 _________________________________________________________________________
|_________________________________________________________________________| she
|_______________________________________________________________| you
|____________________________________________________________| said
|_____________________________________________________| alice
|_______________________________________________| was
|___________________________________________| that
|____________________________________| as
|________________________________| her
|_____________________________| with
|_____________________________| at
|__________________________| on
|__________________________| all
|_______________________| this
|_______________________| for
|_______________________| had
|_______________________| but
|______________________| be
|_____________________| not
|____________________| they
|____________________| so
|___________________| very
|__________________| what

Mise en œuvre alternative dans l'exemple de cas pathologique:

 _______________________________________________________________
|_______________________________________________________________| she
|_______________________________________________________| superlongstringstring
|____________________________________________________| said
|______________________________________________| alice
|________________________________________| was
|_____________________________________| that
|_______________________________| as
|____________________________| her
|_________________________| with
|_________________________| at
|_______________________| on
|______________________| all
|____________________| this
|____________________| for
|____________________| had
|____________________| but
|___________________| be
|__________________| not
|_________________| they
|_________________| so
|________________| very
|________________| what
10
Syntaera

F #, 452 caractères

Strightforward: obtenez une séquence a de paires Word-count, trouvez le meilleur multiplicateur Word-count-per-column k, puis imprimez les résultats.

let a=
 stdin.ReadToEnd().Split(" .?!,\":;'\r\n".ToCharArray(),enum 1)
 |>Seq.map(fun s->s.ToLower())|>Seq.countBy id
 |>Seq.filter(fun(w,n)->not(set["the";"and";"of";"to";"a";"i";"it";"in";"or";"is"].Contains w))
 |>Seq.sortBy(fun(w,n)-> -n)|>Seq.take 22
let k=a|>Seq.map(fun(w,n)->float(78-w.Length)/float n)|>Seq.min
let u n=String.replicate(int(float(n)*k)-2)"_"
printfn" %s "(u(snd(Seq.nth 0 a)))
for(w,n)in a do printfn"|%s| %s "(u n)w

Exemple (j'ai des nombres de fréquences différents de vous, je ne sais pas pourquoi):

% app.exe < Alice.txt

 _________________________________________________________________________
|_________________________________________________________________________| she
|_______________________________________________________________| you
|_____________________________________________________________| said
|_____________________________________________________| alice
|_______________________________________________| was
|___________________________________________| that
|___________________________________| as
|________________________________| her
|_____________________________| with
|_____________________________| at
|____________________________| t
|____________________________| s
|__________________________| on
|_________________________| all
|_______________________| this
|______________________| had
|______________________| for
|_____________________| but
|_____________________| be
|____________________| not
|___________________| they
|__________________| so
9
Brian

Python 2.6, 347 caractères

import re
W,x={},"a and i in is it of or the to".split()
[W.__setitem__(w,W.get(w,0)-1)for w in re.findall("[a-z]+",file("11.txt").read().lower())if w not in x]
W=sorted(W.items(),key=lambda p:p[1])[:22]
bm=(76.-len(W[0][0]))/W[0][1]
U=lambda n:"_"*int(n*bm)
print "".join(("%s\n|%s| %s "%((""if i else" "+U(n)),U(n),w))for i,(w,n)in enumerate(W))

Sortie:

 _________________________________________________________________________
|_________________________________________________________________________| she 
|_______________________________________________________________| you 
|____________________________________________________________| said 
|_____________________________________________________| alice 
|_______________________________________________| was 
|___________________________________________| that 
|____________________________________| as 
|________________________________| her 
|_____________________________| with 
|_____________________________| at 
|____________________________| s 
|____________________________| t 
|__________________________| on 
|__________________________| all 
|_______________________| this 
|_______________________| for 
|_______________________| had 
|_______________________| but 
|______________________| be 
|_____________________| not 
|____________________| they 
|____________________| so 
8
AKX

Gawk - 336 (à l'origine 507) personnages

(après avoir corrigé le formatage de sortie; corrigé le problème des contractions; peaufiné; peaufiné à nouveau; supprimé une étape de tri totalement inutile; peaufiné encore une fois; et encore (oups celui-ci a cassé le formatage); Tweak some plus; relever le défi de Matt je désespérément Tweak donc plus; trouvé un autre endroit pour en sauver quelques-uns, mais en ai donné deux pour corriger le bug de la longueur de la barre)

Heh heh! Je suis momentanément en avance sur la solution [Matt's JavaScript] [1]contre-défi! ;)  et [python AKX] [2].

Le problème semble appeler un langage qui implémente des tableaux associatifs natifs, donc bien sûr j'en ai choisi un avec un ensemble d'opérateurs horriblement déficient . En particulier, vous ne pouvez pas contrôler l'ordre dans lequel awk offre les éléments d'une carte de hachage, je scanne donc à plusieurs reprises la carte entière pour trouver la plus nombreux éléments, imprimez-le et supprimez-le du tableau.

Tout cela est terriblement inefficace, avec toutes les golfifcations que j'ai faites, cela est devenu aussi horrible.

Minifié:

{gsub("[^a-zA-Z]"," ");for(;NF;NF--)a[tolower($NF)]++}
END{split("the and of to a i it in or is",b," ");
for(w in b)delete a[b[w]];d=1;for(w in a){e=a[w]/(78-length(w));if(e>d)d=e}
for(i=22;i;--i){e=0;for(w in a)if(a[w]>e)e=a[x=w];l=a[x]/d-2;
t=sprintf(sprintf("%%%dc",l)," ");gsub(" ","_",t);if(i==22)print" "t;
print"|"t"| "x;delete a[x]}}

sauts de ligne pour plus de clarté uniquement: ils ne sont pas nécessaires et ne doivent pas être comptés.


Sortie:

$ gawk -f wordfreq.awk.min < 11.txt 
 _________________________________________________________________________
|_________________________________________________________________________| she
|_______________________________________________________________| you
|____________________________________________________________| said
|____________________________________________________| alice
|______________________________________________| was
|__________________________________________| that
|___________________________________| as
|_______________________________| her
|____________________________| with
|____________________________| at
|___________________________| s
|___________________________| t
|_________________________| on
|_________________________| all
|______________________| this
|______________________| for
|______________________| had
|_____________________| but
|____________________| be
|____________________| not
|___________________| they
|__________________| so
$ sed 's/you/superlongstring/gI' 11.txt | gawk -f wordfreq.awk.min
 ______________________________________________________________________
|______________________________________________________________________| she
|_____________________________________________________________| superlongstring
|__________________________________________________________| said
|__________________________________________________| alice
|____________________________________________| was
|_________________________________________| that
|_________________________________| as
|______________________________| her
|___________________________| with
|___________________________| at
|__________________________| s
|__________________________| t
|________________________| on
|________________________| all
|_____________________| this
|_____________________| for
|_____________________| had
|____________________| but
|___________________| be
|___________________| not
|__________________| they
|_________________| so

Lisible; 633 caractères (à l'origine 949):

{
    gsub("[^a-zA-Z]"," ");
    for(;NF;NF--)
    a[tolower($NF)]++
}
END{
    # remove "short" words
    split("the and of to a i it in or is",b," ");
    for (w in b) 
    delete a[b[w]];
    # Find the bar ratio
    d=1;
    for (w in a) {
    e=a[w]/(78-length(w));
    if (e>d)
        d=e
    }
    # Print the entries highest count first
    for (i=22; i; --i){               
    # find the highest count
    e=0;
    for (w in a) 
        if (a[w]>e)
        e=a[x=w];
        # Print the bar
    l=a[x]/d-2;
    # make a string of "_" the right length
    t=sprintf(sprintf("%%%dc",l)," ");
    gsub(" ","_",t);
    if (i==22) print" "t;
    print"|"t"| "x;
    delete a[x]
    }
}
7
dmckee

* sh (+ curl), partiel solution

Ceci est incomplet, mais pour l'enfer, voici la fréquence des mots comptant la moitié du problème en 192 octets:

curl -s http://www.gutenberg.org/files/11/11.txt|sed -e 's@[^a-z]@\n@gi'|tr '[:upper:]' '[:lower:]'|egrep -v '(^[^a-z]*$|\b(the|and|of|to|a|i|it|in|or|is)\b)' |sort|uniq -c|sort -n|tail -n 22
7
Frank Farmer

LISP commun, 670 caractères

Je suis un débutant LISP, et c'est une tentative d'utiliser une table de hachage pour compter (donc probablement pas la méthode la plus compacte).

(flet((r()(let((x(read-char t nil)))(and x(char-downcase x)))))(do((c(
make-hash-table :test 'equal))(w NIL)(x(r)(r))y)((not x)(maphash(lambda
(k v)(if(not(find k '("""the""and""of""to""a""i""it""in""or""is"):test
'equal))(Push(cons k v)y)))c)(setf y(sort y #'> :key #'cdr))(setf y
(subseq y 0(min(length y)22)))(let((f(apply #'min(mapcar(lambda(x)(/(-
76.0(length(car x)))(cdr x)))y))))(flet((o(n)(dotimes(i(floor(* n f)))
(write-char #\_))))(write-char #\Space)(o(cdar y))(write-char #\Newline)
(dolist(x y)(write-char #\|)(o(cdr x))(format t "| ~a~%"(car x))))))
(cond((char<= #\a x #\z)(Push x w))(t(incf(gethash(concatenate 'string(
reverse w))c 0))(setf w nil)))))

peut être exécuté par exemple avec cat alice.txt | clisp -C golf.LISP.

Sous forme lisible est

(flet ((r () (let ((x (read-char t nil)))
               (and x (char-downcase x)))))
  (do ((c (make-hash-table :test 'equal))  ; the Word count map
       w y                                 ; current Word and final Word list
       (x (r) (r)))  ; iteration over all chars
       ((not x)

        ; make a list with (Word . count) pairs removing stopwords
        (maphash (lambda (k v)
                   (if (not (find k '("" "the" "and" "of" "to"
                                      "a" "i" "it" "in" "or" "is")
                                  :test 'equal))
                       (Push (cons k v) y)))
                 c)

        ; sort and truncate the list
        (setf y (sort y #'> :key #'cdr))
        (setf y (subseq y 0 (min (length y) 22)))

        ; find the scaling factor
        (let ((f (apply #'min
                        (mapcar (lambda (x) (/ (- 76.0 (length (car x)))
                                               (cdr x)))
                                y))))
          ; output
          (flet ((outx (n) (dotimes (i (floor (* n f))) (write-char #\_))))
             (write-char #\Space)
             (outx (cdar y))
             (write-char #\Newline)
             (dolist (x y)
               (write-char #\|)
               (outx (cdr x))
               (format t "| ~a~%" (car x))))))

       ; add alphabetic to current Word, and bump Word counter
       ; on non-alphabetic
       (cond
        ((char<= #\a x #\z)
         (Push x w))
        (t
         (incf (gethash (concatenate 'string (reverse w)) c 0))
         (setf w nil)))))
7
6502

Perl, 185 caractères

200 (légèrement cassé)199197195193187 185 caractères. Les deux dernières nouvelles lignes sont importantes. Conforme à la spécification.

map$X{+lc}+=!/^(.|the|and|to|i[nst]|o[rf])$/i,/[a-z]+/gfor<>;
$n=$n>($:=$X{$_}/(76-y+++c))?$n:$:for@w=(sort{$X{$b}-$X{$a}}%X)[0..21];
die map{$U='_'x($X{$_}/$n);" $U
"x!$z++,"|$U| $_
"}@w

La première ligne charge le nombre de mots valides dans %X.

La deuxième ligne calcule le facteur d'échelle minimal de sorte que toutes les lignes de sortie soient <= 80 caractères.

La troisième ligne (contient deux caractères de nouvelle ligne) produit la sortie.

6
mob

C (828)

Il ressemble beaucoup au code obscurci et utilise glib pour la chaîne, la liste et le hachage. Nombre de caractères avec wc -m dit 828. Il ne prend pas en compte les mots à caractère unique. Pour calculer la longueur maximale de la barre, il faut considérer le mot le plus long possible parmi tous, pas seulement le premier 22. Est-ce un écart par rapport à la spécification?

Il ne gère pas les échecs et ne libère pas de mémoire utilisée.

#include <glib.h>
#define S(X)g_string_##X
#define H(X)g_hash_table_##X
GHashTable*h;int m,w=0,z=0;y(const void*a,const void*b){int*A,*B;A=H(lookup)(h,a);B=H(lookup)(h,b);return*B-*A;}void p(void*d,void*u){int *v=H(lookup)(h,d);if(w<22){g_printf("|");*v=*v*(77-z)/m;while(--*v>=0)g_printf("=");g_printf("| %s\n",d);w++;}}main(c){int*v;GList*l;GString*s=S(new)(NULL);h=H(new)(g_str_hash,g_str_equal);char*n[]={"the","and","of","to","it","in","or","is"};while((c=getchar())!=-1){if(isalpha(c))S(append_c)(s,tolower(c));else{if(s->len>1){for(c=0;c<8;c++)if(!strcmp(s->str,n[c]))goto x;if((v=H(lookup)(h,s->str))!=NULL)++*v;else{z=MAX(z,s->len);v=g_malloc(sizeof(int));*v=1;H(insert)(h,g_strdup(s->str),v);}}x:S(truncate)(s,0);}}l=g_list_sort(H(get_keys)(h),y);m=*(int*)H(lookup)(h,g_list_first(l)->data);g_list_foreach(l,p,NULL);}
6
ShinTakezou

Java - 886865756744742744752742714 680 caractères

  • Mises à jour avant le premier 742 : regex amélioré, suppression des types paramétrés superflus, suppression des espaces superflus.

  • Mise à jour 742> 744 caractères : correction du hack de longueur fixe. Cela ne dépend que du 1er mot, pas des autres mots (pour l'instant). Trouvé plusieurs endroits pour raccourcir le code (\\s Dans regex remplacé par et ArrayList remplacé par Vector). Je cherche maintenant un moyen rapide de supprimer la dépendance Commons IO et la lecture de stdin.

  • Mise à jour 744> 752 caractères : j'ai supprimé la dépendance des communs. Il lit maintenant depuis stdin. Collez le texte dans stdin et appuyez sur Ctrl+Z Pour obtenir le résultat.

  • Mise à jour 752> 742 caractères : j'ai supprimé public et un espace, fait du nom de classe 1 caractère au lieu de 2 et il ignore maintenant une lettre mots.

  • Mise à jour 742> 714 caractères : mise à jour selon les commentaires de Carl: suppression de l'affectation redondante (742> 730), remplacement de m.containsKey(k) par m.get(k)!=null (730> 728), introduction de la sous-chaîne de ligne (728> 714).

  • Mise à jour 714> 680 caractères : mise à jour selon les commentaires de Rotsor: calcul de la taille de la barre amélioré pour supprimer le casting inutile et split() améliorée pour supprimer inutile replaceAll().


import Java.util.*;class F{public static void main(String[]a)throws Exception{StringBuffer b=new StringBuffer();for(int c;(c=System.in.read())>0;b.append((char)c));final Map<String,Integer>m=new HashMap();for(String w:b.toString().toLowerCase().split("(\\b(.|the|and|of|to|i[tns]|or)\\b|\\W)+"))m.put(w,m.get(w)!=null?m.get(w)+1:1);List<String>l=new Vector(m.keySet());Collections.sort(l,new Comparator(){public int compare(Object l,Object r){return m.get(r)-m.get(l);}});int c=76-l.get(0).length();String s=new String(new char[c]).replace('\0','_');System.out.println(" "+s);for(String w:l.subList(0,22))System.out.println("|"+s.substring(0,m.get(w)*c/m.get(l.get(0)))+"| "+w);}}

Version plus lisible:

import Java.util.*;
class F{
 public static void main(String[]a)throws Exception{
  StringBuffer b=new StringBuffer();for(int c;(c=System.in.read())>0;b.append((char)c));
  final Map<String,Integer>m=new HashMap();for(String w:b.toString().toLowerCase().split("(\\b(.|the|and|of|to|i[tns]|or)\\b|\\W)+"))m.put(w,m.get(w)!=null?m.get(w)+1:1);
  List<String>l=new Vector(m.keySet());Collections.sort(l,new Comparator(){public int compare(Object l,Object r){return m.get(r)-m.get(l);}});
  int c=76-l.get(0).length();String s=new String(new char[c]).replace('\0','_');System.out.println(" "+s);
  for(String w:l.subList(0,22))System.out.println("|"+s.substring(0,m.get(w)*c/m.get(l.get(0)))+"| "+w);
 }
}

Sortie:

 _________________________________________________________________________ 
 | _________________________________________________________________________ | elle 
 | _______________________________________________________________ | vous 
 | ____________________________________________________________ | dit 
 | _____________________________________________________ | alice 
 | _______________________________________________ | était 
 | ___________________________________________ | que 
 | ____________________________________ | comme 
 | ________________________________ | son 
 | _____________________________ | avec 
 | _____________________________ | à 
 | __________________________ | le 
 | __________________________ | tous 
 | _______________________ | ce 
 | _______________________ | pour 
 | _______________________ | avait 
 | _______________________ | mais 
 | ______________________ | être 
 | _____________________ | pas 
 | ____________________ | ils 
 | ____________________ | donc 
 | ___________________ | très 
 | __________________ | quoi

Ça craint que Java n'a pas String#join() et fermetures (pour l'instant).

Modifier par Rotsor:

J'ai apporté plusieurs modifications à votre solution:

  • Liste remplacée par une chaîne []
  • Réutilisé l'argument 'args' au lieu de déclarer mon propre tableau String. Également utilisé comme argument pour .ToArray ()
  • StringBuffer remplacé par une chaîne (oui, oui, performances terribles)
  • Remplacé Java tri avec un tri de sélection avec arrêt précoce (seuls les 22 premiers éléments doivent être trouvés)
  • Une déclaration int agrégée en une seule déclaration
  • Implémentation de l'algorithme de non-triche trouvant la ligne de sortie la plus limitante. Mis en œuvre sans FP.
  • Correction du problème de plantage du programme lorsqu'il y avait moins de 22 mots distincts dans le texte
  • Implémentation d'un nouvel algorithme de lecture d'entrée, qui est rapide et seulement 9 caractères plus long que celui lent.

Le code condensé est 688711 684 caractères de long:

import Java.util.*;class F{public static void main(String[]l)throws Exception{Map<String,Integer>m=new HashMap();String w="";int i=0,k=0,j=8,x,y,g=22;for(;(j=System.in.read())>0;w+=(char)j);for(String W:w.toLowerCase().split("(\\b(.|the|and|of|to|i[tns]|or)\\b|\\W)+"))m.put(W,m.get(W)!=null?m.get(W)+1:1);l=m.keySet().toArray(l);x=l.length;if(x<g)g=x;for(;i<g;++i)for(j=i;++j<x;)if(m.get(l[i])<m.get(l[j])){w=l[i];l[i]=l[j];l[j]=w;}for(;k<g;k++){x=76-l[k].length();y=m.get(l[k]);if(k<1||y*i>x*j){i=x;j=y;}}String s=new String(new char[m.get(l[0])*i/j]).replace('\0','_');System.out.println(" "+s);for(k=0;k<g;k++){w=l[k];System.out.println("|"+s.substring(0,m.get(w)*i/j)+"| "+w);}}}

La version rapide (720 693 caractères)

import Java.util.*;class F{public static void main(String[]l)throws Exception{Map<String,Integer>m=new HashMap();String w="";int i=0,k=0,j=8,x,y,g=22;for(;j>0;){j=System.in.read();if(j>90)j-=32;if(j>64&j<91)w+=(char)j;else{if(!w.matches("^(|.|THE|AND|OF|TO|I[TNS]|OR)$"))m.put(w,m.get(w)!=null?m.get(w)+1:1);w="";}}l=m.keySet().toArray(l);x=l.length;if(x<g)g=x;for(;i<g;++i)for(j=i;++j<x;)if(m.get(l[i])<m.get(l[j])){w=l[i];l[i]=l[j];l[j]=w;}for(;k<g;k++){x=76-l[k].length();y=m.get(l[k]);if(k<1||y*i>x*j){i=x;j=y;}}String s=new String(new char[m.get(l[0])*i/j]).replace('\0','_');System.out.println(" "+s);for(k=0;k<g;k++){w=l[k];System.out.println("|"+s.substring(0,m.get(w)*i/j)+"| "+w);}}}

Version plus lisible:

import Java.util.*;class F{public static void main(String[]l)throws Exception{
    Map<String,Integer>m=new HashMap();String w="";
    int i=0,k=0,j=8,x,y,g=22;
    for(;j>0;){j=System.in.read();if(j>90)j-=32;if(j>64&j<91)w+=(char)j;else{
        if(!w.matches("^(|.|THE|AND|OF|TO|I[TNS]|OR)$"))m.put(w,m.get(w)!=null?m.get(w)+1:1);w="";
    }}
    l=m.keySet().toArray(l);x=l.length;if(x<g)g=x;
    for(;i<g;++i)for(j=i;++j<x;)if(m.get(l[i])<m.get(l[j])){w=l[i];l[i]=l[j];l[j]=w;}
    for(;k<g;k++){x=76-l[k].length();y=m.get(l[k]);if(k<1||y*i>x*j){i=x;j=y;}}
    String s=new String(new char[m.get(l[0])*i/j]).replace('\0','_');
    System.out.println(" "+s);
    for(k=0;k<g;k++){w=l[k];System.out.println("|"+s.substring(0,m.get(w)*i/j)+"| "+w);}}
}

La version sans amélioration du comportement est de 615 caractères:

import Java.util.*;class F{public static void main(String[]l)throws Exception{Map<String,Integer>m=new HashMap();String w="";int i=0,k=0,j=8,g=22;for(;j>0;){j=System.in.read();if(j>90)j-=32;if(j>64&j<91)w+=(char)j;else{if(!w.matches("^(|.|THE|AND|OF|TO|I[TNS]|OR)$"))m.put(w,m.get(w)!=null?m.get(w)+1:1);w="";}}l=m.keySet().toArray(l);for(;i<g;++i)for(j=i;++j<l.length;)if(m.get(l[i])<m.get(l[j])){w=l[i];l[i]=l[j];l[j]=w;}i=76-l[0].length();String s=new String(new char[i]).replace('\0','_');System.out.println(" "+s);for(k=0;k<g;k++){w=l[k];System.out.println("|"+s.substring(0,m.get(w)*i/m.get(l[0]))+"| "+w);}}}
5
BalusC

Scala, 368 caractères

Tout d'abord, une version lisible en 592 caractères:

object Alice {
  def main(args:Array[String]) {
    val s = io.Source.fromFile(args(0))
    val words = s.getLines.flatMap("(?i)\\w+\\b(?<!\\bthe|and|of|to|a|i|it|in|or|is)".r.findAllIn(_)).map(_.toLowerCase)
    val freqs = words.foldLeft(Map[String, Int]())((countmap, Word)  => countmap + (Word -> (countmap.getOrElse(Word, 0)+1)))
    val sortedFreqs = freqs.toList.sort((a, b)  => a._2 > b._2)
    val top22 = sortedFreqs.take(22)
    val highestWord = top22.head._1
    val highestCount = top22.head._2
    val widest = 76 - highestWord.length
    println(" " + "_" * widest)
    top22.foreach(t => {
      val width = Math.round((t._2 * 1.0 / highestCount) * widest).toInt
      println("|" + "_" * width + "| " + t._1)
    })
  }
}

La sortie de la console ressemble à ceci:

$ scalac alice.scala 
$ scala Alice aliceinwonderland.txt
 _________________________________________________________________________
|_________________________________________________________________________| she
|_______________________________________________________________| you
|_____________________________________________________________| said
|_____________________________________________________| alice
|_______________________________________________| was
|____________________________________________| that
|____________________________________| as
|_________________________________| her
|______________________________| at
|______________________________| with
|_____________________________| s
|_____________________________| t
|___________________________| on
|__________________________| all
|_______________________| had
|_______________________| but
|______________________| be
|______________________| not
|____________________| they
|____________________| so
|___________________| very
|___________________| what

Nous pouvons faire une minification agressive et la réduire à 415 caractères:

object A{def main(args:Array[String]){val l=io.Source.fromFile(args(0)).getLines.flatMap("(?i)\\w+\\b(?<!\\bthe|and|of|to|a|i|it|in|or|is)".r.findAllIn(_)).map(_.toLowerCase).foldLeft(Map[String, Int]())((c,w)=>c+(w->(c.getOrElse(w,0)+1))).toList.sort((a,b)=>a._2>b._2).take(22);println(" "+"_"*(76-l.head._1.length));l.foreach(t=>println("|"+"_"*Math.round((t._2*1.0/l.head._2)*(76-l.head._1.length)).toInt+"| "+t._1))}}

La session de console ressemble à ceci:

$ scalac a.scala 
$ scala A aliceinwonderland.txt
 _________________________________________________________________________
|_________________________________________________________________________| she
|_______________________________________________________________| you
|_____________________________________________________________| said
|_____________________________________________________| alice
|_______________________________________________| was
|____________________________________________| that
|____________________________________| as
|_________________________________| her
|______________________________| at
|______________________________| with
|_____________________________| s
|_____________________________| t
|___________________________| on
|__________________________| all
|_______________________| had
|_______________________| but
|______________________| be
|______________________| not
|____________________| they
|____________________| so
|___________________| very
|___________________| what

Je suis sûr qu'un expert Scala pourrait faire encore mieux.

Mise à jour: Dans les commentaires, Thomas a donné une version encore plus courte, à 368 caractères:

object A{def main(a:Array[String]){val t=(Map[String, Int]()/:(for(x<-io.Source.fromFile(a(0)).getLines;y<-"(?i)\\w+\\b(?<!\\bthe|and|of|to|a|i|it|in|or|is)".r findAllIn x) yield y.toLowerCase).toList)((c,x)=>c+(x->(c.getOrElse(x,0)+1))).toList.sortBy(_._2).reverse.take(22);val w=76-t.head._1.length;print(" "+"_"*w);t map (s=>"\n|"+"_"*(s._2*w/t.head._2)+"| "+s._1) foreach print}}

Lisiblement, à 375 caractères:

object Alice {
  def main(a:Array[String]) {
    val t = (Map[String, Int]() /: (
      for (
        x <- io.Source.fromFile(a(0)).getLines
        y <- "(?i)\\w+\\b(?<!\\bthe|and|of|to|a|i|it|in|or|is)".r.findAllIn(x)
      ) yield y.toLowerCase
    ).toList)((c, x) => c + (x -> (c.getOrElse(x, 0) + 1))).toList.sortBy(_._2).reverse.take(22)
    val w = 76 - t.head._1.length
    print (" "+"_"*w)
    t.map(s => "\n|" + "_" * (s._2 * w / t.head._2) + "| " + s._1).foreach(print)
  }
}
4
pr1001

Scala 2.8, 311 314320330332336341375 personnages

y compris l'ajustement de Word long. Des idées empruntées aux autres solutions.

Maintenant, en tant que script (a.scala):

val t="\\w+\\b(?<!\\bthe|and|of|to|a|i[tns]?|or)".r.findAllIn(io.Source.fromFile(argv(0)).mkString.toLowerCase).toSeq.groupBy(w=>w).mapValues(_.size).toSeq.sortBy(-_._2)take 22
def b(p:Int)="_"*(p*(for((w,c)<-t)yield(76.0-w.size)/c).min).toInt
println(" "+b(t(0)._2))
for(p<-t)printf("|%s| %s \n",b(p._2),p._1)

Courir avec

scala -howtorun:script a.scala alice.txt

BTW, l'édition de 314 à 311 caractères supprime en fait seulement 1 caractère. Quelqu'un s'est trompé avant (Windows CRs?).

4
mkneissl

Clojure 282 strict

(let[[[_ m]:as s](->>(Slurp *in*).toLowerCase(re-seq #"\w+\b(?<!\bthe|and|of|to|a|i[tns]?|or)")frequencies(sort-by val >)(take 22))[b](sort(map #(/(- 76(count(key %)))(val %))s))p #(do(print %1)(dotimes[_(* b %2)](print \_))(apply println %&))](p " " m)(doseq[[k v]s](p \| v \| k)))

Un peu plus lisiblement:

(let[[[_ m]:as s](->> (Slurp *in*)
                   .toLowerCase
                   (re-seq #"\w+\b(?<!\bthe|and|of|to|a|i[tns]?|or)")
                   frequencies
                   (sort-by val >)
                   (take 22))
     [b] (sort (map #(/ (- 76 (count (key %)))(val %)) s))
     p #(do
          (print %1)
          (dotimes[_(* b %2)] (print \_))
          (apply println %&))]
  (p " " m)
  (doseq[[k v] s] (p \| v \| k)))
4
Alex Taggart

C++, 647 caractères

Je ne m'attends pas à obtenir un score élevé en utilisant C++, mais ça ne fait rien. Je suis sûr que cela répond à toutes les exigences. Notez que j'ai utilisé le mot clé C++ 0x auto pour la déclaration de variable, ajustez donc votre complicateur de manière appropriée si vous décidez de tester mon code.

version minimisée

#include <iostream>
#include <cstring>
#include <map>
using namespace std;
#define C string
#define S(x)v=F/a,cout<<#x<<C(v,'_')
#define F t->first
#define G t->second
#define O &&F!=
#define L for(i=22;i-->0;--t)
int main(){map<C,int>f;char d[230];int i=1,v;for(;i<256;i++)d[i<123?i-1:i-27]=i;d[229]=0;char w[99];while(cin>>w){for(i=0;w[i];i++)w[i]=tolower(w[i]);char*p=strtok(w,d);while(p)++f[p],p=strtok(0,d);}multimap<int,C>c;for(auto t=f.end();--t!=f.begin();)if(F!="the"O"and"O"of"O"to"O"a"O"i"O"it"O"in"O"or"O"is")c.insert(pair<int,C>(G,F));auto t=--c.end();float a=0,A;L A=F/(76.0-G.length()),a=a>A?a:A;t=--c.end();S( );L S(\n|)<<"| "<<G;}

Voici une deuxième version qui est plus "C++" en utilisant string, pas char[] et strtok. C'est un peu plus grand, à 669 (+22 vs ci-dessus), mais je ne peux pas le réduire pour le moment, alors j'ai pensé le publier de toute façon.

#include <iostream>
#include <map>
using namespace std;
#define C string
#define S(x)v=F/a,cout<<#x<<C(v,'_')
#define F t->first
#define G t->second
#define O &&F!=
#define L for(i=22;i-->0;--t)
#define E e=w.find_first_of(d,g);g=w.find_first_not_of(d,e);
int main(){map<C,int>f;int i,v;C w,x,d="abcdefghijklmnopqrstuvwxyz";while(cin>>w){for(i=w.size();i-->0;)w[i]=tolower(w[i]);unsigned g=0,E while(g-e>0){x=w.substr(e,g-e),++f[x],E}}multimap<int,C>c;for(auto t=f.end();--t!=f.begin();)if(F!="the"O"and"O"of"O"to"O"a"O"i"O"it"O"in"O"or"O"is")c.insert(pair<int,C>(G,F));auto t=--c.end();float a=0,A;L A=F/(76.0-G.length()),a=a>A?a:A;t=--c.end();S( );L S(\n|)<<"| "<<G;}

J'ai supprimé la version complète, car je ne peux pas être dérangé de continuer à la mettre à jour avec mes réglages pour la version minimisée. Consultez l'historique des modifications si vous êtes intéressé par la version longue (éventuellement obsolète).

3
DMA57361

Java - 896 caractères

931 caractères

1233 caractères rendus illisibles

1977 caractères "non compressés"


Mise à jour: j'ai considérablement réduit le nombre de personnages. Omet les mots d'une seule lettre par spécification mise à jour.

J'envie tellement C # et LINQ.

import Java.util.*;import Java.io.*;import static Java.util.regex.Pattern.*;class g{public static void main(String[] a)throws Exception{PrintStream o=System.out;Map<String,Integer> w=new HashMap();Scanner s=new Scanner(new File(a[0])).useDelimiter(compile("[^a-z]+|\\b(the|and|of|to|.|it|in|or|is)\\b",2));while(s.hasNext()){String z=s.next().trim().toLowerCase();if(z.equals(""))continue;w.put(z,(w.get(z)==null?0:w.get(z))+1);}List<Integer> v=new Vector(w.values());Collections.sort(v);List<String> q=new Vector();int i,m;i=m=v.size()-1;while(q.size()<22){for(String t:w.keySet())if(!q.contains(t)&&w.get(t).equals(v.get(i)))q.add(t);i--;}int r=80-q.get(0).length()-4;String l=String.format("%1$0"+r+"d",0).replace("0","_");o.println(" "+l);o.println("|"+l+"| "+q.get(0)+" ");for(i=m-1;i>m-22;i--){o.println("|"+l.substring(0,(int)Math.round(r*(v.get(i)*1.0)/v.get(m)))+"| "+q.get(m-i)+" ");}}}

"Lisible":

import Java.util.*;
import Java.io.*;
import static Java.util.regex.Pattern.*;
class g
{
   public static void main(String[] a)throws Exception
      {
      PrintStream o = System.out;
      Map<String,Integer> w = new HashMap();
      Scanner s = new Scanner(new File(a[0]))
         .useDelimiter(compile("[^a-z]+|\\b(the|and|of|to|.|it|in|or|is)\\b",2));
      while(s.hasNext())
      {
         String z = s.next().trim().toLowerCase();
         if(z.equals(""))
            continue;
         w.put(z,(w.get(z) == null?0:w.get(z))+1);
      }
      List<Integer> v = new Vector(w.values());
      Collections.sort(v);
      List<String> q = new Vector();
      int i,m;
      i = m = v.size()-1;
      while(q.size()<22)
      {
         for(String t:w.keySet())
            if(!q.contains(t)&&w.get(t).equals(v.get(i)))
               q.add(t);
         i--;
      }
      int r = 80-q.get(0).length()-4;
      String l = String.format("%1$0"+r+"d",0).replace("0","_");
      o.println(" "+l);
      o.println("|"+l+"| "+q.get(0)+" ");
      for(i = m-1; i > m-22; i--)
      {
         o.println("|"+l.substring(0,(int)Math.round(r*(v.get(i)*1.0)/v.get(m)))+"| "+q.get(m-i)+" ");
      }
   }
}

Sortie d'Alice:

 _________________________________________________________________________
|_________________________________________________________________________| she
|_______________________________________________________________| you
|_____________________________________________________________| said
|_____________________________________________________| alice
|_______________________________________________| was
|____________________________________________| that
|____________________________________| as
|_________________________________| her
|______________________________| with
|______________________________| at
|___________________________| on
|__________________________| all
|________________________| this
|________________________| for
|_______________________| had
|_______________________| but
|______________________| be
|______________________| not
|____________________| they
|____________________| so
|___________________| very
|___________________| what

Sortie de Don Quichotte (également de Gutenberg):

 ________________________________________________________________________
|________________________________________________________________________| that
|________________________________________________________| he
|______________________________________________| for
|__________________________________________| his
|________________________________________| as
|__________________________________| with
|_________________________________| not
|_________________________________| was
|________________________________| him
|______________________________| be
|___________________________| don
|_________________________| my
|_________________________| this
|_________________________| all
|_________________________| they
|________________________| said
|_______________________| have
|_______________________| me
|______________________| on
|______________________| so
|_____________________| you
|_____________________| quixote
3
Jonathon Faust

Encore un autre python 2.x - 206 caractères (ou 232 avec "barre de largeur")

Je crois que celui-ci est pleinement conforme à la question. Ignorer la liste est ici, il vérifie complètement la longueur de la ligne (voir l'exemple où j'ai remplacé Alice par Aliceinwonderlandbylewiscarroll dans le texte faisant du cinquième élément la ligne la plus longue. Même le nom de fichier est fourni à partir de la ligne de commande à la place de codé en dur (le codage en dur supprimerait environ 10 caractères). Il a un inconvénient (mais je pense que cela convient à la question) car il calcule un diviseur entier pour rendre la ligne plus courte que 80 caractères, la ligne la plus longue est inférieure à 80 caractères, non exactement 80 caractères. La version python 3.x n'a pas ce défaut (mais est bien plus longue).

Je pense aussi que ce n'est pas si difficile à lire.

import sys,re
t=re.split("\W+(?:(?:the|and|o[fr]|to|a|i[tns]?)\W+)*",sys.stdin.read().lower())
b=sorted((-t.count(x),x)for x in set(t))[:22]
for l,w in b:print"|"+l/min(z/(78-len(e))for z,e in b)*'-'+"|",w
|----------------------------------------------------------------| she
|--------------------------------------------------------| you
|-----------------------------------------------------| said
|----------------------------------------------| aliceinwonderlandbylewiscarroll
|-----------------------------------------| was
|--------------------------------------| that
|-------------------------------| as
|----------------------------| her
|--------------------------| at
|--------------------------| with
|-------------------------| s
|-------------------------| t
|-----------------------| on
|-----------------------| all
|---------------------| this
|--------------------| for
|--------------------| had
|--------------------| but
|-------------------| be
|-------------------| not
|------------------| they
|-----------------| so

Comme il n'est pas clair si nous devons imprimer la barre max seule sur sa ligne (comme dans l'exemple de sortie). Ci-dessous est un autre qui le fait, mais 232 caractères.

import sys,re
t=re.split("\W+(?:(?:the|and|o[fr]|to|a|i[tns]?)\W+)*",sys.stdin.read().lower())
b=sorted((-t.count(x),x)for x in set(t))[:22]
f=min(z/(78-len(e))for z,e in b)
print"",b[0][0]/f*'-'
for y,w in b:print"|"+y/f*'-'+"|",w

Python 3.x - 256 caractères

En utilisant la classe Counter de python 3.x, il y avait de grands espoirs de la raccourcir (comme Counter fait tout ce dont nous avons besoin ici). Il ressort que ce n'est pas mieux. Ci-dessous mon essai de 266 caractères :

import sys,re,collections as c
b=c.Counter(re.split("\W+(?:(?:the|and|o[fr]|to|a|i[tns]?)\W+)*",
sys.stdin.read().lower())).most_common(22)
F=lambda p,x,w:print(p+'-'*int(x/max(z/(77.-len(e))for e,z in b))+w)
F(" ",b[0][1],"")
for w,y in b:F("|",y,"| "+w)

Le problème est que collections et most_common sont des mots très longs et même Counter n'est pas court ... vraiment, ne pas utiliser Counter ne rend le code que 2 caractères plus long ;-(

python 3.x introduit également d'autres contraintes: la division de deux entiers n'est plus un entier (nous devons donc transtyper en int), print est désormais une fonction (doit ajouter des parenthèses), etc. C'est pourquoi il sort 22 caractères plus longtemps que version python2.x, mais beaucoup plus rapide. Peut-être un peu plus expérimenté python 3.x aura des idées pour raccourcir le code.

3
kriss

Sensationnel, 424389378 321 caractères

remplacé b=map.get(a) par b=map[a], remplacé par split avec matcher/iterator

def r,s,m=[:],n=0;def p={println it};def w={"_".multiply it};(new URL(this.args[0]).text.toLowerCase()=~/\b\w+\b/).each{s=it;if(!(s==~/(the|and|of|to|a|i[tns]?|or)/))m[s]=m[s]==null?1:m[s]+1};m.keySet().sort{a,b->m[b]<=>m[a]}.subList(0,22).each{k->if(n++<1){r=(m[k]/(76-k.length()));p" "+w(m[k]/r)};p"|"+w(m[k]/r)+"|"+k}

(exécuté en tant que script groovy avec l'URL comme argument de ligne cmd. Aucune importation requise!)

Version lisible ici:

def r,s,m=[:],n=0;
def p={println it};
def w={"_".multiply it};
(new URL(this.args[0]).text.toLowerCase()
        =~ /\b\w+\b/
        ).each{
        s=it;
        if (!(s ==~/(the|and|of|to|a|i[tns]?|or)/))
            m[s] = m[s] == null ? 1 : m[s] + 1
        };
    m.keySet()
        .sort{
            a,b -> m[b] <=> m[a]
        }
        .subList(0,22).each{
            k ->
                if( n++ < 1 ){
                    r=(m[k]/(76-k.length()));
                    p " " + w(m[k]/r)
                };
                p "|" + w(m[k]/r) + "|" + k
}
2
Sean Patrick Floyd

Clojure - 611 caractères (non minimisés)

J'ai essayé d'écrire le code dans autant de Clojure idiomatique que possible si tard dans la nuit. Je ne suis pas trop fier du draw-chart, mais je suppose que le code en dit long sur la brièveté de Clojure.

(ns Word-freq
(:require [clojure.contrib.io :as io]))

(defn Word-freq
  [f]
  (take 22 (->> f
                io/read-lines ;;; Slurp should work too, but I love map/red
                (mapcat (fn [l] (map #(.toLowerCase %) (re-seq #"\w+" l))))
                (remove #{"the" "and" "of" "to" "a" "i" "it" "in" "or" "is"})
                (reduce #(assoc %1 %2 (inc (%1 %2 0))) {})
                (sort-by (comp - val)))))

(defn draw-chart
  [fs]
  (let [[[w f] & _] fs]
    (apply str
           (interpose \newline
                      (map (fn [[k v]] (apply str (concat "|" (repeat (int (* (- 76 (count w)) (/ v f 1))) "_") "| " k " ")) ) fs)))))

;;; (println (draw-chart (Word-freq "/Users/ghoseb/Desktop/alice.txt")))

Sortie:

|_________________________________________________________________________| she 
|_______________________________________________________________| you 
|____________________________________________________________| said 
|____________________________________________________| alice 
|_______________________________________________| was 
|___________________________________________| that 
|____________________________________| as 
|________________________________| her 
|_____________________________| with 
|_____________________________| at 
|____________________________| t 
|____________________________| s 
|__________________________| on 
|__________________________| all 
|_______________________| for 
|_______________________| had 
|_______________________| this 
|_______________________| but 
|______________________| be 
|_____________________| not 
|____________________| they 
|____________________| so

Je sais, cela ne suit pas les spécifications, mais bon, c'est du code Clojure très propre qui est déjà si petit :)

2
Baishampayan Ghose

MATLAB 335 404410 octets357 octets.390 octets.

Le code mis à jour compte désormais 335 caractères au lieu de 404 et semble bien fonctionner pour les deux exemples.


Message d'origine (Pour un code de 404 caractères)

Cette version est un peu plus longue, cependant , elle mettra correctement à l'échelle la longueur des barres s'il y a un mot ridiculement long pour qu'aucun des les colonnes dépassent 80.

Donc, mon code est de 357 octets sans redimensionnement et 410 de long avec redimensionnement.

A=textscan(fopen('11.txt'),'%s','delimiter',' 0123456789,.!?-_*^:;=+\\/(){}[]@&#$%~`|"''');
s=lower(A{1});s(cellfun('length', s)<2)=[];s(ismember(s,{'the','and','of','to','it','in','or','is'}))=[];
[w,~,i]=unique(s);N=hist(i,max(i)); [j,k]=sort(N,'descend'); b=k(1:22); n=cellfun('length',w(b));
q=80*N(b)'/N(k(1))+n; q=floor(q*78/max(q)-n); for i=1:22, fprintf('%s| %s\n',repmat('_',1,l(i)),w{k(i)});end

Résultats:

___________________________________________________________________________| she
_________________________________________________________________| you
______________________________________________________________| said
_______________________________________________________| alice
________________________________________________| was
____________________________________________| that
_____________________________________| as
_________________________________| her
______________________________| at
______________________________| with
____________________________| on
___________________________| all
_________________________| this
________________________| for
________________________| had
________________________| but
_______________________| be
_______________________| not
_____________________| they
____________________| so
___________________| very
___________________| what

Par exemple, en remplaçant toutes les instances de "vous" dans le texte d'Alice au pays des merveilles par "superlongstringofridiculousness", mon code mettra correctement à l'échelle les résultats:

____________________________________________________________________| she
_________________________________________________________| superlongstringstring
________________________________________________________| said
_________________________________________________| alice
____________________________________________| was
________________________________________| that
_________________________________| as
______________________________| her
___________________________| with
___________________________| at
_________________________| on
________________________| all
_____________________| this
_____________________| for
_____________________| had
_____________________| but
____________________| be
____________________| not
__________________| they
__________________| so
_________________| very
_________________| what

Voici le code mis à jour écrit un peu plus lisiblement:

A=textscan(fopen('t'),'%s','delimiter','':'@');
s=lower(A{1});
s(cellfun('length', s)<2|ismember(s,{'the','and','of','to','it','in','or','is'}))=[];
[w,~,i]=unique(s);
N=hist(i,max(i)); 
[j,k]=sort(N,'descend'); 
n=cellfun('length',w(k));
q=80*N(k)'/N(k(1))+n; 
q=floor(q*78/max(q)-n); 
for i=1:22, 
    fprintf('%s| %s\n',repmat('_',1,q(i)),w{k(i)});
end
2
reso

Java - 991 caractères (y compris les nouvelles lignes et les retraits)

J'ai pris le code de @ seanizer , corrigé un bug (il a omis la 1ère ligne de sortie), fait quelques améliorations pour rendre le code plus 'golfy'.

import Java.util.*;
import Java.util.regex.*;
import org.Apache.commons.io.IOUtils;
public class WF{
 public static void main(String[] a)throws Exception{
  String t=IOUtils.toString(new Java.net.URL(a[0]).openStream());
  class W implements Comparable<W> {
   String w;int f=1;W(String W){w=W;}public int compareTo(W o){return o.f-f;}
   String d(float r){char[]c=new char[(int)(f/r)];Arrays.fill(c,'_');return "|"+new String(c)+"| "+w;}
  }
  Map<String,W>M=new HashMap<String,W>();
  Matcher m=Pattern.compile("\\b\\w+\\b").matcher(t.toLowerCase());
  while(m.find()){String w=m.group();W W=M.get(w);if(W==null)M.put(w,new W(w));else W.f++;}
  M.keySet().removeAll(Arrays.asList("the,and,of,to,a,i,it,in,or,is".split(",")));
  List<W>L=new ArrayList<W>(M.values());Collections.sort(L);int l=76-L.get(0).w.length();
  System.out.println(" "+new String(new char[l]).replace('\0','_'));
  for(W w:L.subList(0,22))System.out.println(w.d((float)L.get(0).f/(float)l));
 }
}

Sortie:

 _________________________________________________________________________ 
 | _________________________________________________________________________ | elle 
 | _______________________________________________________________ | vous 
 | ____________________________________________________________ | dit 
 | _____________________________________________________ | alice 
 | _______________________________________________ | était 
 | ___________________________________________ | que 
 | ____________________________________ | comme 
 | ________________________________ | son 
 | _____________________________ | avec 
 | _____________________________ | à 
 | ____________________________ | s 
 | ____________________________ | t 
 | __________________________ | le 
 | __________________________ | tous 
 | _______________________ | ce 
 | _______________________ | pour 
 | _______________________ | avait 
 | _______________________ | mais 
 | ______________________ | être 
 | _____________________ | pas 
 | ____________________ | ils 
 | ____________________ | alors

2
BalusC

Scala, 327 caractères

Ceci a été adapté de la réponse de mkneissl inspirée d'une version Python, bien qu'elle soit plus grande. Je la laisse ici au cas où quelqu'un pourrait le raccourcir.

val f="\\w+\\b(?<!\\bthe|and|of|to|a|i[tns]?|or)".r.findAllIn(io.Source.fromFile("11.txt").mkString.toLowerCase).toSeq
val t=f.toSet[String].map(x=> -f.count(x==)->x).toSeq.sorted take 22
def b(p:Int)="_"*(-p/(for((c,w)<-t)yield-c/(76.0-w.size)).max).toInt
println(" "+b(t(0)._1))
for(p<-t)printf("|%s| %s \n",b(p._1),p._2)
2
Daniel C. Sobral

Shell, 228 caractères, avec une contrainte de 80 caractères fonctionnant

tr A-Z a-z|tr -Cs a-z "\n"|sort|egrep -v "^(the|and|of|to|a|i|it|in|or|is)$" |uniq -c|sort -r|head -22>g
n=1
while :
do
awk '{printf "|%0*s| %s\n",$1*'$n'/1e3,"",$2;}' g|tr 0 _>o 
egrep -q .{80} o&&break
n=$((n+1))
done
cat o

Je suis surpris que personne ne semble avoir utilisé la fonctionnalité étonnante * de printf.

cat 11-very.txt> golf.sh

|__________________________________________________________________________| she
|________________________________________________________________| you
|_____________________________________________________________| said
|______________________________________________________| alice
|_______________________________________________| was
|____________________________________________| that
|____________________________________| as
|_________________________________| her
|______________________________| with
|______________________________| at
|_____________________________| s
|_____________________________| t
|___________________________| on
|__________________________| all
|________________________| this
|_______________________| for
|_______________________| had
|_______________________| but
|______________________| be
|______________________| not
|____________________| they
|____________________| so

chat 11 | golf.sh

|_________________________________________________________________| she
|_________________________________________________________| verylongstringstring
|______________________________________________________| said
|_______________________________________________| alice
|__________________________________________| was
|_______________________________________| that
|________________________________| as
|_____________________________| her
|___________________________| with
|___________________________| at
|__________________________| s
|_________________________| t
|________________________| on
|_______________________| all
|_____________________| this
|_____________________| for
|_____________________| had
|____________________| but
|___________________| be
|___________________| not
|__________________| they
|__________________| so
2
mb14

Python 2.6, 273269267 266 caractères.

(Edit: Props à ChristopheD pour des suggestions de rasage de personnage)

import sys,re
t=re.findall('[a-z]+',"".join(sys.stdin).lower())
d=sorted((t.count(w),w)for w in set(t)-set("the and of to a i it in or is".split()))[:-23:-1]
r=min((78.-len(m[1]))/m[0]for m in d)
print'','_'*(int(d[0][0]*r-2))
for(a,b)in d:print"|"+"_"*(int(a*r-2))+"|",b

Sortie:

 _________________________________________________________________________
|_________________________________________________________________________| she
|_______________________________________________________________| you
|____________________________________________________________| said
|____________________________________________________| alice
|______________________________________________| was
|__________________________________________| that
|___________________________________| as
|_______________________________| her
|____________________________| with
|____________________________| at
|___________________________| s
|___________________________| t
|_________________________| on
|_________________________| all
|______________________| this
|______________________| for
|______________________| had
|_____________________| but
|____________________| be
|____________________| not
|___________________| they
|__________________| so
2
user382714

R 449 caractères

peut probablement raccourcir ...

bar <- function(w, l)
    {
    b <- rep("-", l)
    s <- rep(" ", l)
    cat(" ", b, "\n|", s, "| ", w, "\n ", b, "\n", sep="")
    }

f <- "alice.txt"
e <- c("the", "and", "of", "to", "a", "i", "it", "in", "or", "is", "")
w <- unlist(lapply(readLines(file(f)), strsplit, s=" "))
w <- tolower(w)
w <- unlist(lapply(w, gsub, pa="[^a-z]", r=""))
u <- unique(w[!w %in% e])
n <- unlist(lapply(u, function(x){length(w[w==x])}))
o <- rev(order(n))
n <- n[o]
m <- 77 - max(unlist(lapply(u[1:22], nchar)))
n <- floor(m*n/n[1])
u <- u[o]

for (i in 1:22)
    bar(u[i], n[i])
2
nico

Python, 320 caractères

import sys
i="the and of to a i it in or is".split()
d={}
for j in filter(lambda x:x not in i,sys.stdin.read().lower().split()):d[j]=d.get(j,0)+1
w=sorted(d.items(),key=lambda x:x[1])[:-23:-1]
m=sorted(dict(w).values())[-1]
print" %s\n"%("_"*(76-m)),"\n".join(map(lambda x:("|%s| "+x[0])%("_"*((76-m)*x[1]/w[0][1])),w))
1
dhruvbird

GNU Smalltalk (386)

Je pense que cela peut être un peu plus court, mais je ne sais toujours pas comment.

|q s f m|q:=Bag new. f:=FileStream stdin. m:=0.[f atEnd]whileFalse:[s:=f nextLine.(s notNil)ifTrue:[(s tokenize:'\W+')do:[:i|(((i size)>1)&({'the'.'and'.'of'.'to'.'it'.'in'.'or'.'is'}includes:i)not)ifTrue:[q add:(i asLowercase)]. m:=m max:(i size)]]].(q:=q sortedByCount)from:1to:22 do:[:i|'|'display.((i key)*(77-m)//(q first key))timesRepeat:['='display].('| %1'%{i value})displayNl]
1
ShinTakezou

Solution Lua: 478 caractères.

t,u={},{}for l in io.lines()do
for w in l:gmatch("%a+")do
w=w:lower()if not(" the and of to a i it in or is "):find(" "..w.." ")then
t[w]=1+(t[w]or 0)end
end
end
for k,v in next,t do
u[#u+1]={k,v}end
table.sort(u,function(a,b)return a[2]>b[2]end)m,n=u[1][2],math.min(#u,22)for w=80,1,-1 do
s=""for i=1,n do
a,b=u[i][1],w*u[i][2]/m
if b+#a>=78 then s=nil break end
s2=("_"):rep(b)if i==1 then
s=s.." " ..s2.."\n"end
s=s.."|"..s2.."| "..a.."\n"end
if s then print(s)break end end

Version lisible:

t,u={},{}
for line in io.lines() do
    for w in line:gmatch("%a+") do
        w = w:lower()
        if not (" the and of to a i it in or is "):find(" "..w.." ") then
            t[w] = 1 + (t[w] or 0)
        end
    end
end
for k, v in pairs(t) do
    u[#u+1]={k, v}
end

table.sort(u, function(a, b)
    return a[2] > b[2]
end)

local max = u[1][2]
local n = math.min(#u, 22)

for w = 80, 1, -1 do
    s=""
    for i = 1, n do
        f = u[i][2]
        Word = u[i][1]
        width = w * f / max
        if width + #Word >= 78 then
            s=nil
            break
        end
        s2=("_"):rep(width)
        if i==1 then
            s=s.." " .. s2 .."\n"
        end
        s=s.."|" .. s2 .. "| " .. Word.."\n"
    end
    if s then
        print(s)
        break
    end
end
1
Kristofer

Une autre solution T-SQL empruntant quelques idées à la solution de Martin (min76- etc.).

declare @ varchar(max),@w real,@j int;select s=@ into[ ]set @=(select*
from openrowset(bulk'a',single_blob)a)while @>''begin set @=stuff(@,1,
patindex('%[a-z]%',@)-1,'')+'.'set @j=patindex('%[^a-z]%',@)if @j>2insert[ ]
select lower(left(@,@j-1))set @=stuff(@,1,@j,'')end;select top(22)s,count(*)
c into # from[ ]where',the,and,of,to,it,in,or,is,'not like'%,'+s+',%'
group by s order by 2desc;select @w=min((76.-len(s))/c),@=' '+replicate(
'_',max(c)*@w)from #;select @=@+'
|'+replicate('_',c*@w)+'| '+s+' 'from #;print @

La solution entière doit être sur deux lignes (concaténer les 7 premières), bien que vous puissiez la couper, la coller et l'exécuter telle quelle. Nombre total de caractères = 507 (en comptant le saut de ligne comme 1 si vous l'enregistrez au format Unix et exécutez à l'aide de SQLCMD)

Hypothèses:

  1. Il n'y a pas de table temporaire #
  2. Il n'y a pas de table nommée [ ]
  3. L'entrée se trouve dans le dossier système par défaut, par ex. C:\windows\system32\a
  4. Votre fenêtre de requête a "activé nocount sur" actif (empêche les msgs "lignes affectées" parasites)

Et pour entrer dans la liste des solutions (<500 caractères), voici l'édition "décontractée" à 483 caractères (pas de barres verticales/pas de barre supérieure/Aucun espace de fin après Word)

declare @ varchar(max),@w real,@j int;select s=@ into[ ]set @=(select*
from openrowset(bulk'b',single_blob)a)while @>''begin set @=stuff(@,1,
patindex('%[a-z]%',@)-1,'')+'.'set @j=patindex('%[^a-z]%',@)if @j>2insert[ ]
select lower(left(@,@j-1))set @=stuff(@,1,@j,'')end;select top(22)s,count(*)
c into # from[ ]where',the,and,of,to,it,in,or,is,'not like'%,'+s+',%'
group by s order by 2desc;select @w=min((78.-len(s))/c),@=''from #;select @=@+'
'+replicate('_',c*@w)+' '+s from #;print @

Version lisible

declare @ varchar(max), @w real, @j int
select s=@ into[ ] -- shortcut to create table; use defined variable to specify column type
-- openrowset reads an entire file
set @=(select * from openrowset(bulk'a',single_blob) a) -- a bit shorter than naming 'BulkColumn'

while @>'' begin -- loop until input is empty
    set @=stuff(@,1,patindex('%[a-z]%',@)-1,'')+'.' -- remove lead up to first A-Z char *
    set @j=patindex('%[^a-z]%',@) -- find first non A-Z char. The +'.' above makes sure there is one
    if @j>2insert[ ] select lower(left(@,@j-1)) -- insert only words >1 char
    set @=stuff(@,1,@j,'') -- remove Word and trailing non A-Z char
end;

select top(22)s,count(*)c
into #
from[ ]
where ',the,and,of,to,it,in,or,is,' not like '%,'+s+',%' -- exclude list
group by s
order by 2desc; -- highest occurence, assume no ties at 22!

-- 80 - 2 vertical bars - 2 spaces = 76
-- @w = weighted frequency
-- this produces a line equal to the length of the max occurence (max(c))
select @w=min((76.-len(s))/c),@=' '+replicate('_',max(c)*@w)
from #;

-- for each Word, append it as a new line. note: embedded newline
select @=@+'
|'+replicate('_',c*@w)+'| '+s+' 'from #;
-- note: 22 words in a table should always fit on an 8k page
--       the order of processing should always be the same as the insert-orderby
--       thereby producing the correct output

print @ -- output
1
RichardTheKiwi

Java, se raccourcissant lentement (1500135812411020913 890 caractères)

dépouillé encore plus d'espace blanc et la longueur du nom var. supprimé les génériques dans la mesure du possible, supprimé la classe en ligne et le bloc try/catch trop mauvais, ma version 900 avait un bug

supprimé un autre bloc try/catch

import Java.net.*;import Java.util.*;import Java.util.regex.*;import org.Apache.commons.io.*;public class G{public static void main(String[]a)throws Exception{String text=IOUtils.toString(new URL(a[0]).openStream()).toLowerCase().replaceAll("\\b(the|and|of|to|a|i[tns]?|or)\\b","");final Map<String,Integer>p=new HashMap();Matcher m=Pattern.compile("\\b\\w+\\b").matcher(text);Integer b;while(m.find()){String w=m.group();b=p.get(w);p.put(w,b==null?1:b+1);}List<String>v=new Vector(p.keySet());Collections.sort(v,new Comparator(){public int compare(Object l,Object m){return p.get(m)-p.get(l);}});boolean t=true;float r=0;for(String w:v.subList(0,22)){if(t){t=false;r=p.get(w)/(float)(80-(w.length()+4));System.out.println(" "+new String(new char[(int)(p.get(w)/r)]).replace('\0','_'));}System.out.println("|"+new String(new char[(int)(((Integer)p.get(w))/r)]).replace('\0','_')+"|"+w);}}}

Version lisible:

import Java.net.*;
import Java.util.*;
import Java.util.regex.*;
import org.Apache.commons.io.*;

public class G{

    public static void main(String[] a) throws Exception{
        String text =
            IOUtils.toString(new URL(a[0]).openStream())
                .toLowerCase()
                .replaceAll("\\b(the|and|of|to|a|i[tns]?|or)\\b", "");
        final Map<String, Integer> p = new HashMap();
        Matcher m = Pattern.compile("\\b\\w+\\b").matcher(text);
        Integer b;
        while(m.find()){
            String w = m.group();
            b = p.get(w);
            p.put(w, b == null ? 1 : b + 1);
        }
        List<String> v = new Vector(p.keySet());
        Collections.sort(v, new Comparator(){

            public int compare(Object l, Object m){
                return p.get(m) - p.get(l);
            }
        });
        boolean t = true;
        float r = 0;
        for(String w : v.subList(0, 22)){
            if(t){
                t = false;
                r = p.get(w) / (float) (80 - (w.length() + 4));
                System.out.println(" "
                    + new String(new char[(int) (p.get(w) / r)]).replace('\0',
                        '_'));
            }
            System.out.println("|"
                + new String(new char[(int) (((Integer) p.get(w)) / r)]).replace('\0',
                    '_') + "|" + w);
        }
    }
}
1
Sean Patrick Floyd

Rubis, 205


Cette version Ruby version gère "superlongstringstring". (Les deux premières lignes sont presque identiques à la précédente Ruby programmes.)

Il doit être exécuté de cette façon:

 Ruby -n0777 golf.rb Alice.txt 


W=($_.upcase.scan(/\w+/)-%w(THE AND OF TO A I IT
IN OR IS)).group_by{|x|x}.map{|k,v|[-v.size,k]}.sort[0,22]
u=proc{|m|"_"*(W.map{|n,s|(76.0-s.size)/n}.max*m)}
puts" "+u[W[0][0]],W.map{|n,s|"|%s| "%u[n]+s}

La troisième ligne crée une fermeture ou lambda qui produit une chaîne de soulignements correctement mise à l'échelle:

 u = proc {| m | 
 "_" * 
 (W.map {| n, s | (76.0 - s.size)/n} .max * m ) 
} 

.max est utilisé à la place de .min car les nombres sont négatifs.

1
user383392

Perl, 188 caractères

La version Perl ci-dessus (ainsi que toute version basée sur le fractionnement d'expressions rationnelles) peut être raccourcie de quelques octets en incluant la liste des mots interdits en tant qu'affirmations d'anticipation négatives, plutôt qu'en tant que liste distincte. De plus, le point-virgule de fin peut être omis.

J'ai également inclus quelques autres suggestions (- au lieu de <=>, pour/foreach, "clés" supprimées) pour arriver à

$c{$_}++for grep{$_}map{lc=~/\b(?!(?:the|and|a|of|or|i[nts]?|to)\b)[a-z]+/g}<>;@s=sort{$c{$b}-$c{$a}}%c;$f=76-length$s[0];say$"."_"x$f;say"|"."_"x($c{$_}/$c{$s[0]}*$f)."| $_ "for@s[0..21]

Je ne connais pas Perl, mais je suppose que le (?! (?: ...)\b) peut perdre le?: Si la manipulation autour de lui est corrigée.

1
mvds

Javascript, 348 caractères

Après avoir fini le mien, j'ai volé quelques idées à Matt: 3

t=Prompt().toLowerCase().replace(/\b(the|and|of|to|a|i[tns]?|or)\b/gm,'');r={};o=[];t.replace(/\b([a-z]+)\b/gm,function(a,w){r[w]?++r[w]:r[w]=1});for(i in r){o.Push([i,r[i]])}m=o[0][1];o=o.slice(0,22);o.sort(function(F,D){return D[1]-F[1]});for(B in o){F=o[B];L=new Array(~~(F[1]/m*(76-F[0].length))).join('_');print(' '+L+'\n|'+L+'| '+F[0]+' \n')}

Nécessite print et Prompt support de la fonction.

1
user216441

Shell, grep, tr, grep, sort, uniq, sort, head, Perl - 194 caractères

L'ajout de quelques drapeaux -i peut faire chuter le trop long tr A-Z a-z | étape; la spécification n'a rien dit sur le cas affiché et uniq -ci supprime toutes les différences de cas.

egrep -oi [a-z]+|egrep -wiv 'the|and|o[fr]|to|a|i[tns]?'|sort|uniq -ci|sort -nr|head -22|Perl -lape'($f,$w)=@F;$.>1or($q,$x)=($f,76-length$w);$b="_"x($f/$q*$x);$_="|$b| $w ";$.>1or$_=" $b\n$_"'

C'est moins 11 pour le tr plus 2 pour les -i par rapport aux 206 caractères originaux.

edit: moins 3 pour le \\ b qui peut être omis car la correspondance de motif commencera de toute façon sur une frontière.

sort donne d'abord les minuscules et uniq -ci prend la première occurrence, donc le seul vrai changement dans la sortie sera qu'Alice conserve ses initiales majuscules.

1
mvds

Je dois aimer les grands ... Objectif-C (1070931 905 caractères)

#define S NSString
#define C countForObject
#define O objectAtIndex
#define U stringWithCString
main(int g,char**b){id c=[NSCountedSet set];S*d=[S stringWithContentsOfFile:[S U:b[1]]];id p=[NSPredicate predicateWithFormat:@"SELF MATCHES[cd]'(the|and|of|to|a|i[tns]?|or)|[^a-z]'"];[d enumerateSubstringsInRange:NSMakeRange(0,[d length])options:NSStringEnumerationByWords usingBlock:^(S*s,NSRange x,NSRange y,BOOL*z){if(![p evaluateWithObject:s])[c addObject:[s lowercaseString]];}];id s=[[c allObjects]sortedArrayUsingComparator:^(id a,id b){return(NSComparisonResult)([c C:b]-[c C:a]);}];g=[c C:[s O:0]];int j=76-[[s O:0]length];char*k=malloc(80);memset(k,'_',80);S*l=[S U:k length:80];printf(" %s\n",[[l substringToIndex:j]cString]),[[s subarrayWithRange:NSMakeRange(0,22)]enumerateObjectsUsingBlock:^(id a,NSUInteger x,BOOL*y){printf("|%s| %s\n",[[l substringToIndex:[c C:a]*j/g]cString],[a cString]);}];}

Passé à l'utilisation de nombreuses API dépréciées, supprimé une gestion de la mémoire qui n'était pas nécessaire, suppression des espaces blancs plus agressive

 _________________________________________________________________________
|_________________________________________________________________________| she
|______________________________________________________________| said
|__________________________________________________________| you
|____________________________________________________| alice
|________________________________________________| was
|_______________________________________| that
|____________________________________| as
|_________________________________| her
|______________________________| with
|______________________________| at
|___________________________| on
|__________________________| all
|________________________| this
|________________________| for
|________________________| had
|_______________________| but
|______________________| be
|______________________| not
|____________________| so
|___________________| very
|__________________| what
|_________________| they
1
Joshua Weinberg

Python 290255, 253


290 caractères en python (texte lu à partir de l'entrée standard)

import sys,re
c={}
for w in re.findall("[a-z]+",sys.stdin.read().lower()):c[w]=c.get(w,0)+1-(","+w+","in",a,i,the,and,of,to,it,in,or,is,")
r=sorted((-v,k)for k,v in c.items())[:22]
sf=max((76.0-len(k))/v for v,k in r)
print" "+"_"*int(r[0][0]*sf)
for v,k in r:print"|"+"_"*int(v*sf)+"| "+k

mais ... après avoir lu d'autres solutions, j'ai soudain réalisé que l'efficacité n'était pas une demande; c'est donc un autre plus court et beaucoup plus lent (255 caractères)

import sys,re
w=re.findall("\w+",sys.stdin.read().lower())
r=sorted((-w.count(x),x)for x in set(w)-set("the and of to a i it in or is".split()))[:22]
f=max((76.-len(k))/v for v,k in r)
print" "+"_"*int(f*r[0][0])
for v,k in r:print"|"+"_"*int(f*v)+"| "+k

et après avoir lu d'autres solutions ...

import sys,re
w=re.findall("\w+",sys.stdin.read().lower())
r=sorted((-w.count(x),x)for x in set(w)-set("the and of to a i it in or is".split()))[:22]
f=max((76.-len(k))/v for v,k in r)
print"","_"*int(f*r[0][0])
for v,k in r:print"|"+"_"*int(f*v)+"|",k

Et maintenant, cette solution est presque octet par octet identique à celle d'Astatine :-D

1
6502

R, 298 caractères

f=scan("stdin","ch")
u=unlist
s=strsplit
a=u(s(u(s(tolower(f),"[^a-z]")),"^(the|and|of|to|it|in|or|is|.|)$"))
v=unique(a)
r=sort(sapply(v,function(i) sum(a==i)),T)[2:23]  #the first item is an empty string, just skipping it
w=names(r)
q=(78-max(nchar(w)))*r/max(r)
cat(" ",rep("_",q[1])," \n",sep="")
for(i in 1:22){cat("|",rep("_",q[i]),"| ",w[i],"\n",sep="")}

La sortie est:

 _________________________________________________________________________ 
|_________________________________________________________________________| she
|_______________________________________________________________| you
|____________________________________________________________| said
|_____________________________________________________| alice
|_______________________________________________| was
|___________________________________________| that
|____________________________________| as
|________________________________| her
|_____________________________| at
|_____________________________| with
|__________________________| on
|__________________________| all
|_______________________| this
|_______________________| for
|_______________________| had
|_______________________| but
|______________________| be
|_____________________| not
|____________________| they
|____________________| so
|___________________| very
|__________________| what

Et si "vous" est remplacé par quelque chose de plus long:

 ____________________________________________________________ 
|____________________________________________________________| she
|____________________________________________________| veryverylongstring
|__________________________________________________| said
|___________________________________________| alice
|______________________________________| was
|___________________________________| that
|_____________________________| as
|__________________________| her
|________________________| at
|________________________| with
|______________________| on
|_____________________| all
|___________________| this
|___________________| for
|___________________| had
|__________________| but
|__________________| be
|__________________| not
|________________| they
|________________| so
|_______________| very
|_______________| what
1
Andrei

Go, 613 caractères, pourrait probablement être beaucoup plus petit:

package main
import(r "regexp";. "bytes";. "io/ioutil";"os";st "strings";s "sort";. "container/vector")
type z struct{c int;w string}
func(e z)Less(o interface{})bool{return o.(z).c<e.c}
func main(){b,_:=ReadAll(os.Stdin);g:=r.MustCompile
c,m,x:=g("[A-Za-z]+").AllMatchesIter(b,0),map[string]int{},g("the|and|of|it|in|or|is|to")
for w:=range c{w=ToLower(w);if len(w)>1&&!x.Match(w){m[string(w)]++}}
o,y:=&Vector{},0
for k,v:=range m{o.Push(z{v,k});if v>y{y=v}}
s.Sort(o)
for i,v:=range *o{if i>21{break};x:=v.(z);c:=int(float(x.c)/float(y)*80)
u:=st.Repeat("_",c);if i<1{println(" "+u)};println("|"+u+"| "+x.w)}}

Je me sens tellement sale.

1
user384098

TCL 554 Strict

foreach w [regexp -all -inline {[a-z]+} [string tolower [read stdin]]] {if {[lsearch {the and of to it in or is a i} $w]>=0} {continue};if {[catch {incr Ws($w)}]} {set Ws($w) 1}}
set T [lrange [lsort -decreasing -stride 2 -index 1 -integer [array get Ws]] 0 43]
foreach {w c} $T {lappend L [string length $w];lappend C $c}
set N [tcl::mathfunc::max {*}$L]
set C [lsort -integer $C]
set M [lindex $C end]
puts " [string repeat _ [expr {int((76-$N) * [lindex $T 1] / $M)}]] "
foreach {w c} $T {puts "|[string repeat _ [expr {int((76-$N) * $c / $M)}]]| $w"}

Ou, plus lisiblement

foreach w [regexp -all -inline {[a-z]+} [string tolower [read stdin]]] {
    if {[lsearch {the and of to a i it in or is} $w] >= 0} { continue }
    if {[catch {incr words($w)}]} {
        set words($w) 1
    }
}
set topwords [lrange [lsort -decreasing -stride 2 -index 1 -integer [array get words]] 0 43]
foreach {Word count} $topwords {
    lappend lengths [string length $Word]
    lappend counts $count
}
set maxlength [lindex [lsort -integer $lengths] end]
set counts [lsort -integer $counts]
set mincount [lindex $counts 0].0
set maxcount [lindex $counts end].0
puts " [string repeat _ [expr {int((76-$maxlength) * [lindex $topwords 1] / $maxcount)}]] "
foreach {Word count} $topwords {
    set barlength [expr {int((76-$maxlength) * $count / $maxcount)}]
    puts "|[string repeat _ $barlength]| $Word"
}
1
RHSeeger

Bourne Shell, 213/240 caractères

En améliorant la version Shell publiée plus tôt, je peux la réduire à 213 caractères:

tr A-Z a-z|tr -Cs a-z \\n|sort|egrep -v '^(the|and|of|to|a|i|it|in|or|is)$'|uniq -c|sort -rn|sed 22q>g
n=1
>o
until egrep -q .{80} o
do
awk '{printf "|%0*d| %s\n",$1*'$n'/1e3,0,$2}' g|tr 0 _>o 
((n++))
done
cat o

Afin d'obtenir le contour supérieur sur la barre supérieure, j'ai dû l'étendre à 240 caractères:

tr A-Z a-z|tr -Cs a-z \\n|sort|egrep -v "^(the|and|of|to|a|i|it|in|or|is)$"|uniq -c|sort -r|sed 1p\;22q>g
n=1
>o
until egrep -q .{80} o
do
awk '{printf "|%0*d| %s\n",$1*'$n'/1e3,0,NR==1?"":$2}' g|sed '1s,|, ,g'|tr 0 _>o 
((n++))
done
cat o
1
user384075

Python, 250 caractères

emprunt à tous les autres Python

import re,sys
t=re.findall("\w+","".join(sys.stdin).lower())
W=sorted((-t.count(w),w)for w in set(t)-set("the and of to a i it in or is".split()))[:22]
Z,U=W[0],lambda n:"_"*int(n*(76.-len(Z[1]))/Z[0])
print"",U(Z[0])
for(n,w)in W:print"|"+U(n)+"|",w

Si vous êtes effronté et mettez les mots à éviter comme arguments, 223 caractères

import re,sys
t=re.findall("\w+","".join(sys.stdin).lower())
W=sorted((-t.count(w),w)for w in set(t)-set(sys.argv[1:]))[:22]
Z,U=W[0],lambda n:"_"*int(n*(76.-len(Z[1]))/Z[0])
print"",U(Z[0])
for(n,w)in W:print"|"+U(n)+"|",w

La sortie est:

$ python alice4.py  the and of to a i it in or is < 11.txt 
 _________________________________________________________________________
|_________________________________________________________________________| she
|_______________________________________________________________| you
|____________________________________________________________| said
|_____________________________________________________| alice
|_______________________________________________| was
|___________________________________________| that
|____________________________________| as
|________________________________| her
|_____________________________| at
|_____________________________| with
|____________________________| s
|____________________________| t
|__________________________| on
|__________________________| all
|_______________________| this
|_______________________| for
|_______________________| had
|_______________________| but
|______________________| be
|_____________________| not
|____________________| they
|____________________| so
0
Will

Groovy, 250

Code:

m=[:]
(new URL(args[0]).text.toLowerCase()=~/\w+/).each{it==~/(the|and|of|to|a|i[tns]?|or)/?:(m[it]=1+(m[it]?:0))}
k=m.keySet().sort{a,b->m[b]<=>m[a]}
b={d,c,b->println d+'_'*c+d+' '+b}
b' ',z=77-k[0].size(),''
k[0..21].each{b'|',m[it]*z/m[k[0]],it}

Exécution:

$ groovy wordcount.groovy http://www.gutenberg.org/files/11/11.txt

Sortie:

 __________________________________________________________________________  
|__________________________________________________________________________| she
|________________________________________________________________| you
|_____________________________________________________________| said
|_____________________________________________________| alice
|_______________________________________________| was
|____________________________________________| that
|____________________________________| as
|_________________________________| her
|______________________________| at
|______________________________| with
|_____________________________| s
|_____________________________| t
|___________________________| on
|__________________________| all
|________________________| this
|_______________________| for
|_______________________| had
|_______________________| but
|______________________| be
|______________________| not
|____________________| they
|____________________| so

N.B. cela suit des règles détendues concernant les longues cordes

0
Armand

Q, 194

{t::y;{(-1')t#(.:)[b],'(!:)[b:"|",/:(((_)70*x%(*:)x)#\:"_"),\:"|"];}desc(#:')(=)($)(`$inter\:[(,/)" "vs'" "sv/:"'"vs'a(&)0<(#:')a:(_:')read0 -1!x;52#.Q.an])except`the`and`of`to`a`i`it`in`or`is`}

la fonction prend deux arguments: l'un un fichier contenant le texte et l'autre le nombre de lignes du graphique à afficher

q){t::y;{(-1')t#(.:)[b],'(!:)[b:"|",/:(((_)70*x%(*:)x)#\:"_"),\:"|"];}desc(#:')(=)($)(`$inter\:[(,/)" "vs'" "sv/:"'"vs'a(&)0<(#:')a:(_:')read0 -1!x;52#.Q.an])except`the`and`of`to`a`i`it`in`or`is`}[`a.txt;20]

sortie

|______________________________________________________________________|she
|____________________________________________________________|you
|__________________________________________________________|said
|___________________________________________________|alice
|_____________________________________________|was
|_________________________________________|that
|__________________________________|as
|_______________________________|her
|_____________________________|with
|____________________________|at
|___________________________|t
|___________________________|s
|_________________________|on
|_________________________|all
|_______________________|this
|______________________|for
|______________________|had
|_____________________|but
|_____________________|be
|_____________________|not
0
tmartin