Réimplémenter le wc coreutil

27

Ce défi est similaire à l'ancien , mais avec certaines parties floues de la spécification et des exigences d'E / S moins strictes.


Étant donné l'entrée d'une chaîne composée uniquement d'ASCII imprimables et de sauts de ligne, affichez ses diverses métriques (octet, mot, nombre de lignes).

Les mesures que vous devez générer sont les suivantes:

  • Nombre d'octets. Étant donné que la chaîne d'entrée reste en ASCII, il s'agit également du nombre de caractères.

  • Nombre de mots. Il s'agit de wcla définition d'un "mot:" n'importe quelle séquence non blanche. Par exemple, abc,def"ghi"est un «mot».

  • Nombre de lignes. Cela va de soi. L'entrée contiendra toujours une nouvelle ligne de fin, ce qui signifie que le nombre de lignes est synonyme de «nombre de nouvelles lignes». Il n'y aura jamais plus d'un seul saut de ligne.

La sortie doit reproduire exactement la wcsortie par défaut (à l'exception du nom de fichier):

llama@llama:~$ cat /dev/urandom | tr -cd 'A-Za-z \n' | head -90 > example.txt
llama@llama:~$ wc example.txt
  90  165 5501 example.txt

Notez que le nombre de lignes vient en premier, puis le nombre de mots et enfin le nombre d'octets. De plus, chaque comptage doit être rempli à gauche avec des espaces de sorte qu'ils soient tous de la même largeur. Dans l'exemple ci-dessus, 5501est le nombre "le plus long" à 4 chiffres, il 165est donc rempli d'un espace et 90de deux. Enfin, les numéros doivent tous être joints en une seule chaîne avec un espace entre chaque numéro.

Puisqu'il s'agit de , le code le plus court en octets gagnera.

(Oh, et au fait ... vous ne pouvez pas utiliser la wccommande dans votre réponse. Au cas où ce n'était pas déjà évident.)

Cas de test ( \nreprésente une nouvelle ligne; vous pouvez également avoir éventuellement besoin d'une nouvelle ligne supplémentaire):

"a b c d\n" -> "1 4 8"
"a b c d e f\n" -> " 1  6 12"
"  a b c d e f  \n" -> " 1  6 16"
"a\nb\nc\nd\n" -> "4 4 8"
"a\n\n\nb\nc\nd\n" -> " 6  4 10"
"abc123{}[]()...\n" -> " 1  1 16
"\n" -> "1 0 1"
"   \n" -> "1 0 4"
"\n\n\n\n\n" -> "5 0 5"
"\n\n\na\nb\n" -> "5 2 7"
Poignée de porte
la source
2
Je vais VTC l'ancien en tant que dupe de celui-ci parce que celui-ci est un bien meilleur défi.
Mego
L'entrée vide doit-elle être prise en charge?
Ton Hospel
Je ne pense pas, dit-il, toutes les entrées se terminent par \ n.
CalculatorFeline

Réponses:

8

Perl, 49 octets

+3 ajouté pour -an0

Entrée sur STDIN ou 1 ou plusieurs noms de fichiers comme arguments. Courir commeperl -an0 wc.pl

wc.pl:

/\z/g;pos=~//;printf"%@+d %@+d $`
",y/
//,~~@F

Explication:

-n0      slurps the whole input into $_ and says we will do our own printing
-a       tells perl to split the input on whitespace into array @F
/\z/g    Matches the absolute end of the input. g modifier so the position 
         is remembered in pos which will now contain the input length
pos=~//  An empy regex repeats the last succesful match, so /\z/ again.
         After that $` will contain the the number of input characters and
         the array @+ will contain the length of this number
printf   All preparation is complete, we can go print the result
"%@+d"   will become e.g. %6d if the number of characters is a number of
         length 6, so lines and words will get printed right aligned 
         in a field of length 6.
$`       $` we can directly interpolate since it won't contain a %
y/\n//   Count the number of newlines in $_
~~@F     The array of words @F in scalar context gives the number of words
Ton Hospel
la source
7

Python 2, 100 77 octets

Cette solution est une fonction Python qui accepte une chaîne de plusieurs lignes et imprime les nombres requis sur stdout. Notez que j'utilise une chaîne de format pour créer une chaîne de format (qui nécessite un %%pour échapper au premier espace réservé de format).

Edit: 23 octets enregistrés grâce aux optimisations d'impression de Dennis.

def d(b):c=len(b);a='%%%us'%len(`c`);print a%b.count('\n'),a%len(b.split()),c

Avant la minifiante, cela ressemble à ceci:

def wc(text) :
    size = len(text);
    numfmt = '%%%us' % len(`size`);
    print numfmt % text.count('\n'), numfmt % len(text.split()), size
Logic Knight
la source
7

Pyth, 21 octets

jdm.[;l`lQ`ld[@bQcQ)Q

Suite de tests

Pyth a de très belles fonctionnalités intégrées ici. Nous commençons par faire une liste ( [) des sauts de ligne dans la chaîne ( @bQ), les mots dans la chaîne ( cQ)) et la chaîne elle-même ( Q). Ensuite, nous ajoutons ( .[) la longueur de chaque chaîne ( ld) avec des espaces ( ;dans ce contexte) à la longueur du nombre de caractères ( l`lQ). Enfin, rejoignez les espaces ( jd).

isaacg
la source
6

POSIX awk, 79 75 67 65 octets

{w+=NF;c+=length+1}END{d=length(c)"d %";printf"%"d d"d\n",NR,w,c}

Edit: sauvé 4 octets depuis POSIX permet un nu length, sauvé 7 octets en actualisant la partie d'invocation, et sauvé deux octets grâce à l'astuce de Doorknob pour l'ajouter d %à d.

C'était à l'origine pour GNU awk, mais le mieux que je puisse dire, c'est qu'il utilise uniquement la fonctionnalité POSIX awk.

Mieux formaté:

gawk '{
  w += NF
  c += length($0) + 1  # length($0) misses the newline
}
END {
  d = length(c) # GNU awk's length returns the length of string representation of number
  printf "%"d"d %"d"d %d\n", NR, w, c
}'
muru
la source
@ Doorknob OK, merci pour cela. Je suppose que vous avez vu la conversation de chat? De plus, cette question devrait passer de la FAQ proposée à la FAQ .
muru
1
Oh, je ne vous ai pas vu dans le chat; votre réponse vient d'apparaître dans ma boîte de réception: PI est celui qui a ajouté [faq-propose] à cette question, alors je vais peut-être vérifier dans la salle des mods avant de la mettre à niveau vers [faq].
Poignée de porte
1
Réglage dde length(c)"d %"devrait vous permettre de changer l' printfà "%"d d"d\n", qui permet d' économiser deux octets.
Poignée de porte
1
@ Doorknob en effet, merci! Je suppose que ce n'est pas l'exotique , mais le banal qui économise des octets.
muru
6

Sérieusement , 39 octets

"
 "╩╜l;$l╝@╜sl'
╜ck`#╛#"{:>%d}"%f`M' j

Essayez-le en ligne!

Explication (les nouvelles lignes sont remplacées par \n):

"\n "╩╜l;$l╝@╜sl'\n╜ck`#╛#"{:>%d}"%f`M' j
"\n "                                      push a string containing a newline and a space
     ╩                                     push input to register 0 (we'll call it s)
      ╜l;                                  push two copies of len(s) (byte count)
         $l╝                               push len(str(len(s))) to register 1
                                            (this will serve as the field width in the output)
            @╜sl                           push word count by getting the length of the list formed by
                                            splitting s on spaces and newlines
                '\n╜c                      count newlines in input
                     k                     push stack to list
                      `#╛#"{:>%d}"%f`M     map:
                       #                     listify
                        ╛#                   push reg 1 (field width), listify
                          "{:>%d}"           push that string
                                  %          do old-style string formatting for field width
                                   f         do new-style string formatting to pad the field appropriately
                                      ' j  join on spaces
Mego
la source
Je ne peux trouver aucune documentation pour cette langue, pouvez-vous fournir un lien?
JohnEye
2
@JohnEye, github.com/Mego/Ser sérieux
awesoon
3

AppleScript, 253 octets

Cela suppose que les délimiteurs d'éléments de texte d'AppleScript sont définis sur l'espace (si j'ai besoin de compter les éléments pour forcer cette hypothèse, je vais l'ajouter).

set w to(display dialog""default answer"")'s text returned
set x to b(w)
set y to w's text item's number
set z to w's paragraph's number
a(x,z)&z&a(x,y)&y&" "&x
on a(x,n)
set o to" "
repeat b(x)-b(n)
set o to o&" "
end
o
end
on b(n)
count(n as text)
end
Addison Crump
la source
3

CJam, 31 26 octets

q_)/_S*S%@_]:,:s),f{Se[}S*

Essayez-le en ligne!

Comment ça marche

q_                         e# Read all input from STDIN and push two copies.
  )                        e# Pop the last character (linefeed) of the second copy.
   /                       e# Split the remaining string at linefeeds.
    _                      e# Push a copy.
     S*                    e# Join the copy, separating by spaces.
       S%                  e# Split at runs of spaces.
         @_                e# Rotate the original input on top and push a copy.
           ]               e# Wrap all four items in an array.
            :,             e# Get the length of each item.
              :s           e# Cast the lengths (integers) to strings.
                )          e# Pop the last length (byte count).
                 ,         e# Get the number of digits.
                  f{Se[}   e# Left-pad all three length with spaces to that length.
                        S* e# Join, separating by spaces.
Dennis
la source
3

Julia, 112 81 octets

f(s,n=endof,l="$(n(s))",g=r->lpad(n(split(s,r))-1,n(l)))=g(r"\n")" "g(r"\S+")" "l

Il s'agit d'une fonction qui accepte une chaîne et renvoie une chaîne.

Nous enregistrons les éléments suivants en tant qu'arguments de fonction:

  • n = endof , qui obtient le dernier index d'une collection indexable (dans ce cas est la longueur de la chaîne)
  • l = "$(n(s)), la longueur de l'entrée convertie en chaîne à l'aide d'une interpolation
  • Une fonction lambda gqui accepte une expression régulière et renvoie la longueur - 1 de la division d'entrée sur cette expression régulière, remplie à gauche d'espaces correspondant à la longueur de l.

Nous obtenons le nombre de lignes en utilisant g(r"\n")et le nombre de mots en utilisant g(r"\S+"), puis nous les joignons ensemble avec ldélimités par des espaces.

Enregistré 31 octets grâce à Dennis!

Alex A.
la source
2

MATL, 38 octets

'\n'32cZtttnGnw-wPZvPYbnqbnvvV!3Z"vX:!

Vous pouvez l' essayer en ligne! Mais cela ne devrait pas être si long ...

Explication, pour le calcul,

'\n'32cZt  %// Takes implicit input and replaces any \n with a space
tt         %// Duplicate that string twice
nGnw-w     %// Length of the string with \n's minus length with spaces to give number of \n's
PZvPYbnq   %// Take string with spaces, flip it, remove leading spaces, flip it again,
           %// split on spaces, find length and decrement for number of words
bn         %// get length of string with spaces, the number of characters

La dernière partie fait le formatage de sortie

vvV!       %// concatenate the 3 numbers to a column vector, convert to string and transpose
3Z"v       %// make string '   ' and concatenate on the bottom of previous string
X:!        %// linearise and transpose to get correct output (impicitly printed)
David
la source
Bien fait! Peut-être supprimer le drapeau "debug" dans le lien Essayez-le en ligne ?
Luis Mendo
Ahh oups! Merci pour l'information!
David
Je pense que vous pouvez remplacer !3Z"vX:!par Z{Zc( cellstrsuivi par strjoin)
Luis Mendo
1

JavaScript (ES6), 115 octets

s=>[/\n\/g,/\S+/g,/[^]/g].map(r=>l=(s.match(r)||[]).length).map(n=>(' '.repeat(99)+n).slice(-`${l}`.length)).join` `

Ne nécessite aucune entrée. Le formatage a été douloureux. S'il y avait une limite supérieure sur la quantité de rembourrage, je pourrais réduire (' '.repeat(99)+n)à quelque chose de plus court, par exemple ` ${n}`.

Neil
la source
Je pense que vous pouvez remplacer /[^]/gpar /./gpour économiser deux octets
Patrick Roberts
@PatrickRoberts Non, cela saute les nouvelles lignes, donc mon décompte serait hors tension.
Neil
Ah, je n'avais jamais remarqué ça avant.
Patrick Roberts
1

PowerShell, 140 octets

param($a)$c="$((($l=($a-split"`n").Count-1),($w=($a-split"\S+").Count-1),($b=$a.length)|sort)[-1])".Length;
"{0,$c} {1,$c} {2,$c}"-f$l,$w,$b

(nouvelle ligne laissée pour plus de clarté: D)

La première ligne prend une entrée $a, puis la partie suivante est une seule instruction. Nous définissons $cégal à une chaîne .length . Cela formera notre rembourrage requis. À l'intérieur de la chaîne se trouve un bloc de code immédiat $(...), de sorte que le code sera exécuté avant d'être évalué dans la chaîne.

Dans le bloc de code, nous envoyons trois éléments via la |sortcommande, puis prenons le plus gros (...)[-1]. C'est là que nous veillons à obtenir les colonnes à la bonne largeur. Les trois éléments sont $lle nombre de lignes, où nous -splitsur les nouvelles lignes, le $wnombre de mots, où nous -splitsur les espaces blancs et $bla longueur.

La deuxième ligne est notre sortie en utilisant l' -fopérateur (qui est un pseudo-raccourci pour String.Format()). C'est une autre façon d'insérer des variables développées dans des chaînes. Ici, nous disons que nous voulons que toute la sortie soit complétée vers la gauche afin que chaque colonne soit $clarge. Le rembourrage se fait via des espaces. Le 0, 1et 2correspondent à la $l, $wet $bqui sont des arguments pour l'opérateur de format, de sorte que le nombre de lignes, le nombre de mots, et le nombre d'octets sont rembourrés et de sortie de manière appropriée.

Notez que cela nécessite soit que la chaîne ait des sauts de ligne déjà développés (par exemple, en faisant un Get-Contentsur un fichier texte ou quelque chose, puis en canalisant ou en enregistrant cela dans une variable, puis en appelant ce code sur cette entrée), ou utilisez le PowerShell- caractères d'échappement de style avec des crochets (ce qui signifie `nau lieu de \n).

Exemple

PS C:\Tools\Scripts\golfing> .\reimplement-wc.ps1 "This line`nis broken`ninto three lines.`n"
 3  7 38
AdmBorkBork
la source
0

Rubis, 108 octets

f=->s{a=[s.count($/),s.split(/\S+/).size-1,s.size].map(&:to_s)
a.map{|b|" "*(a.map(&:size).max-b.size)+b}*" "}
afuous
la source
0

Perl, 71 62 61 octets

comprend +1 pour -n

$;=length($b+=y///c);$w+=split$"}{printf"%$;d %$;d $b",$.,$w

Commenté:

while (<>) {                         # implicit because of -n
    $; = length(                     # printf formatting: width
       $b += y///c                   # count characters
    );
    $w += split $"                   # count words
}{                                   # explicit: end while, begin END block
    printf "%$;d %$;d $b", $., $w    #  $. = $INPUT_LINE_NUMBER
}                                    # implicit because of -n
  • Enregistrez un autre octet, encore une fois grâce à @TonHospel.
  • Économisez 9 octets grâce à @TonHospel me montrant quelques trucs du métier!
Kenney
la source
Quelques trucs du métier: Utilisez y///ccomme une longueur plus courte de $_. split$"en contexte scalaire donne le nombre de mots en $_. En utilisant une variable de ponctuation comme $;au lieu de $Wvous pouvez mettre djuste après l'interpolation dans la chaîne de format. Ensuite , vous pouvez laisser tomber le ddans $Wet déposez la parenthèse. Et -pne gagne rien de plus -n, laissez simplement printffaire l'impression (ajoutez une nouvelle ligne au goût)
Ton Hospel
Génial, je l'apprécie!
Kenney
Une chaîne de calcul comme celle-ci $a=foo;$b=bar$apeut généralement s'écrire en $b=bar($a=foo)économisant un octet. Applicable ici à $;et $b. Vous ne vous souciez pas si $;est recalculé à chaque fois
Ton Hospel
Merci! J'ai oublié ça parce qu'il y a deux blocs ...
Kenney
0

Lua, 74 66 octets

Golfé:

t=arg[1]_,l=t:gsub('\n','')_,w=t:gsub('%S+','')print(l,w,t:len())

Non golfé:

text = arg[1]
_,lines = text:gsub('\n','')
_,words = text:gsub('%S+','')
print(lines, words, text:len())

Reçoit des entrées via des arguments de ligne de commande.

Nous renommons le premier argument ( arg[1]) pour économiser des octets. string.gsubrenvoie le nombre de remplacements ainsi que la chaîne modifiée, nous utilisons donc cela pour compter d'abord '\n'(les nouvelles lignes), puis '%S+'(les instances d'un ou plusieurs caractères non blancs, autant que possible, c'est-à-dire les mots). Nous pouvons utiliser tout ce que nous voulons pour la chaîne de remplacement, nous utilisons donc la chaîne vide ( '') pour enregistrer les octets. Ensuite, nous utilisons simplement string.lenpour trouver la longueur de la chaîne, c'est-à-dire le nombre d'octets. Enfin, nous imprimons tout.

Jesse Paroz
la source
Je ne vois pas de remplissage gauche des valeurs de lignes et de mots
Ton Hospel
0

Rétine, 65

^((\S+)|(¶)|.)*
$#3 $#2 $.0
+`(\b(.)+ )(?!.*\b(?<-2>.)+$)
a$1
a
<space>

Essayez-le en ligne!

La première étape est le programme wc réel, le reste est pour le rembourrage. L' aespace réservé n'est probablement pas nécessaire, et certains des groupes peuvent probablement être un peu simplifiés.

FryAmTheEggman
la source
0

Haskell, 140 octets

import Text.Printf
w h=let{l=length;s=show.l;c=s h;m=s.words$h;n=s.lines$h;f=maximum$map l[c, m, n];p=printf"%*s"f}in p n++' ':p m++' ':p c

La version non golfée est ci-dessous, avec des noms de variables et de fonctions étendus:

import Text.Printf

wc str =
  let charcount = show.length $ str
      wordcount = show.length.words $ str
      linecount = show.length.lines $ str
      fieldwidth = maximum $ map length [charcount, wordcount, linecount]
      printer = printf "%*s" fieldwidth
  in printer linecount ++ (' ' : printer wordcount ++ (' ' : printer charcount))

Il s'agit d'une fonction qui accepte une chaîne et renvoie une chaîne. Il utilise simplement les Preludefonctions words(resp. lines) Pour obtenir le nombre de mots (resp. Lignes) étant donné qu'ils semblent utiliser la même définition que wc, puis obtient la valeur la plus longue (sous forme de chaîne) parmi les décomptes et utilise le format printf en prenant la largeur parmi ses arguments pour le formatage.

arjanen
la source
0

C, 180 178 octets

#include <stdio.h>
#include <ctype.h>
main(b,w,l,c,d){d=' ';b=w=l=0;while((c=fgetc(stdin))!=EOF){if(!isspace(c)&&isspace(d))w++;b++;d=c;if(c==10)l++;}printf("%d %d %d\n",l,w,b);}
user2064000
la source
111 octets
plafondcat
0

05AB1E , 24 23 octets

¨¶¡¹… 
    S¡õK¹)€g§Zg>jJ¦

jest actuellement bogue, donc aurait pu être de 21 octets sans le §et J..

Essayez-le en ligne ou vérifiez tous les cas de test .

Explication:

¨          # Remove the trailing newline of the (implicit) input
 ¶¡        # And split it on newlines
¹… 
    S¡     # Take the first input again, and split it on [" \n\t"]
      õK   # Then remove all empty string items
¹          # And take the first input again as is
)          # Wrap all three value of the stack to a single list
 g        # Take the length of each of the items
   §       # Cast the integers to strings (should have been implicit, but `j` is bugged)
    Z      # Take the max (always the last / amount of bytes) (without popping the list)
     g>    # Take the length + 1 of this max
       j   # Append leading spaces so all items or of this length
        J  # Join them together (should have been done by the `j` already, but it's bugged)
         ¦ # Remove the leading space (and output implicitly to STDOUT)
Kevin Cruijssen
la source
0

Pip -s , 25 octets

sX##a-#_._M[nNa`\S+`Na#a]

Prend la chaîne multiligne comme argument de ligne de commande. Essayez-le en ligne!

Merci à la réponse CJam de Dennis de m'avoir fait réaliser que le nombre le plus long est toujours le nombre de caractères.

Explication

                           s is space; n is newline; a is 1st cmdline arg (implicit)
           [            ]  Construct a list of three elements:
            nNa             Number of newlines in a
               `\S+`Na      Regex search: number of runs of non-whitespace characters in a
                      #a    Length of a (i.e. number of characters in a)
          M                To each element of that list, map this function:
   #a                       Number of characters in a
  #                         Length of that number
     -#_                    Subtract length of each element
sX                          Construct a string of that many spaces
        ._                  Prepend it to the element
                           The resulting list is autoprinted, space-separated (-s flag)

Voici une solution de 29 octets avec des indicateurs -rsqui prend l'entrée de stdin:

[#g`\S+`NST:gY#g+1]MsX#y-#_._

Essayez-le en ligne!

DLosc
la source
0

Powershell, 123 115 octets

switch -r($args|% t*y){'\s'{$a=0}'\S'{$w+=!$a;$a=1}'(?s).'{$b++}'
'{$l++}}$c="$b".Length
"{0,$c} {1,$c} $b"-f$l,+$w

Script de test:

$f = {

switch -r($args|% t*y){    # evaluate all matched cases
    '\s'   {$a=0}          # any whitespace (newline not included)
    '\S'   {$w+=!$a;$a=1}  # any not-whitespace (newline not included)
    '(?s).'{$b++}          # any char (newline included!)
    '`n'   {$l++}          # new line char
}
$c="$b".Length
"{0,$c} {1,$c} $b"-f$l,+$w


}

@(
    , ("a b c d`n", "1 4 8")
    , ("a b c d e f`n", " 1  6 12")
    , ("  a b c d e f  `n", " 1  6 16")
    , ("a`nb`nc`nd`n", "4 4 8")
    , ("a`n`n`nb`nc`nd`n", " 6  4 10")
    , ("abc123{}[]()...`n", " 1  1 16")
    , ("`n", "1 0 1")
    , ("   `n", "1 0 4")
    , ("`n`n`n`n`n", "5 0 5")
    , ("`n`n`na`nb`n", "5 2 7")
) | % {
    $s,$e = $_
    $r = &$f $s
    "$($e-eq$r): $r"
}

Sortie:

True: 1 4 8
True:  1  6 12
True:  1  6 16
True: 4 4 8
True:  6  4 10
True:  1  1 16
True: 1 0 1
True: 1 0 4
True: 5 0 5
True: 5 2 7

Explication:

  • $args|% t*y divise les chaînes d'argument en caractères
  • switch -r($args|% t*y)évaluer tous les cas correspondants
    • '\s' cas pour tout espace blanc
    • '\S' cas pour tout espace non blanc
    • '(?s).' étui pour tout caractère (nouvelle ligne incluse)
    • '\n' cas pour newline char (newline se représente)
  • $c="$b".Lengthcalculer une longueur de nombre d'octets. $ b est toujours max ($ l, $ w, $ b) par conception
  • "{0,$c} {1,$c} $b"-f$l,+$wformater des nombres de même longueur. La variable $ w est convertie en int. Il a besoin de chaînes sans mots. Les autres variables formatent «telles quelles» car «L'entrée contiendra toujours une nouvelle ligne de fin» et $ l et $ b ne peuvent pas être 0.
mazzy
la source