Vuelva a implementar el wc coreutil

27

Este desafío es similar al anterior , pero con algunas partes poco claras de la especificación elaboradas y requisitos de E / S menos estrictos.


Dada una entrada de una cadena que consta de solo ASCII imprimible y nuevas líneas, genera sus diversas métricas (byte, palabra, recuento de líneas).

Las métricas que debe generar son las siguientes:

  • Recuento de bytes. Como la cadena de entrada permanece dentro de ASCII, este también es el recuento de caracteres.

  • El recuento de palabras. Esta es wcla definición de una "palabra:" cualquier secuencia de espacio no en blanco. Por ejemplo, abc,def"ghi"es una "palabra".

  • Recuento de líneas. Esto se explica por sí mismo. La entrada siempre contendrá una nueva línea final, lo que significa que el recuento de líneas es sinónimo de "recuento de nuevas líneas". Nunca habrá más de una nueva línea final.

La salida debe replicar exactamente la wcsalida predeterminada (excepto el nombre del archivo):

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

Tenga en cuenta que el recuento de líneas es lo primero, luego el recuento de palabras y finalmente el recuento de bytes. Además, cada recuento debe ir rellenado a la izquierda con espacios para que todos tengan el mismo ancho. En el ejemplo anterior, 5501es el número "más largo" con 4 dígitos, por lo que 165se rellena con un espacio y 90con dos. Finalmente, todos los números deben unirse en una sola cadena con un espacio entre cada número.

Como se trata de , ganará el código más corto en bytes.

(Ah, y por cierto ... no puedes usar el wccomando en tu respuesta. En caso de que eso ya no sea obvio).

Casos de prueba ( \nrepresenta una nueva línea; opcionalmente, también puede requerir una nueva línea adicional):

"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"
Pomo de la puerta
fuente
2
Voy a VTC el viejo como un tonto de este porque este es un desafío mucho mejor.
Mego
¿Debería admitirse la entrada vacía?
Ton Hospel
No lo creo, dijo que todas las entradas terminan con \ n.
CalculatorFeline

Respuestas:

8

Perl, 49 bytes

Se agregó +3 por -an0

Ingrese en STDIN o 1 o más nombres de archivo como argumentos. Correr comoperl -an0 wc.pl

wc.pl:

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

Explicación:

-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
fuente
7

Python 2, 100 77 bytes

Esta solución es una función de Python que acepta una cadena de varias líneas e imprime los recuentos necesarios en stdout. Tenga en cuenta que uso una cadena de formato para construir una cadena de formato (que requiere una %%para escapar del primer marcador de posición de formato).

Editar: Guardado 23 bytes debido a optimizaciones de impresión por Dennis.

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

Antes del minificador, se ve así:

def wc(text) :
    size = len(text);
    numfmt = '%%%us' % len(`size`);
    print numfmt % text.count('\n'), numfmt % len(text.split()), size
Caballero Lógico
fuente
7

Pyth, 21 bytes

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

Banco de pruebas

Pyth tiene algunas muy buenas incorporaciones aquí. Comenzamos haciendo una lista ( [) de las nuevas líneas en la cadena ( @bQ), las palabras en la cadena ( cQ)) y la cadena en sí ( Q). Luego, rellenamos ( .[) la longitud de cada cadena ( ld) con espacios ( ;en este contexto) a la longitud del número de caracteres ( l`lQ). Finalmente, únete en espacios ( jd).

isaacg
fuente
6

POSIX awk, 79 75 67 65 bytes

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

Editar: ahorrado 4 bytes desde POSIX permite que un desnudo length, salvó 7 bytes mediante el descuento de la parte invocación, y salvó dos bytes gracias a punta de Pomo para añadir d %a d.

Esto fue originalmente para GNU awk, pero lo mejor que puedo decir es que solo usa la funcionalidad POSIX awk.

Mejor formateado:

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
fuente
@Doorknob OK, gracias por eso. Supongo que viste la conversación de chat? Además, esa pregunta debe pasar de faq-propuestas a faq .
muru
1
Oh, no te vi en el chat; su respuesta apareció en mi bandeja de entrada: PI fue quien agregó [propuesta de preguntas frecuentes] a esa pregunta, así que tal vez revise la sala de mods antes de actualizarla a [preguntas frecuentes].
Pomo de la puerta
1
La configuración dde length(c)"d %"debería permitirle cambiar printfa "%"d d"d\n", lo que ahorra dos bytes.
Pomo de la puerta
1
@Doorknob de hecho, gracias! Supongo que no es lo exótico , sino lo mundano lo que ahorra bytes.
muru
6

En serio , 39 bytes

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

Pruébalo en línea!

Explicación (las nuevas líneas se reemplazan por \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
fuente
No puedo encontrar ninguna documentación para este idioma, ¿puede proporcionar un enlace?
JohnEye
2
@JohnEye, github.com/Mego/Seriously
awesoon
3

AppleScript, 253 bytes

Esto supone que los delimitadores de elementos de texto de AppleScript están configurados en espacio (si necesito contar las cosas para forzar esa suposición, la agregaré).

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
fuente
3

CJam, 31 26 bytes

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

Pruébalo en línea!

Cómo funciona

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
fuente
3

Julia, 112 81 bytes

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

Esta es una función que acepta una cadena y devuelve una cadena.

Guardamos lo siguiente como argumentos de función:

  • n = endof función, que obtiene el último índice de una colección indexable (en este caso es la longitud de la cadena)
  • l = "$(n(s)), la longitud de la entrada convertida en una cadena mediante interpolación
  • Una función lambda gque acepta una expresión regular y devuelve la longitud - 1 de la división de entrada en esa expresión regular, rellena a la izquierda con espacios para que coincida con la longitud de l.

Obtenemos el número de líneas usando g(r"\n")y el número de palabras usando g(r"\S+"), luego las unimos con ldelimitadas por espacios.

¡Ahorré 31 bytes gracias a Dennis!

Alex A.
fuente
2

MATL, 38 bytes

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

¡Puedes probarlo en línea! Sin embargo, esto no debería ser tan largo ...

Explicación, para el cálculo,

'\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 última parte hace el formato de salida

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
fuente
¡Bien hecho! ¿Quizás elimine la bandera de "depuración" en el enlace Probar en línea ?
Luis Mendo
Ahh whoops! ¡Gracias por el aviso!
David
Creo que se puede sustituir !3Z"vX:!por Z{Zc( cellstrseguido de strjoin)
Luis Mendo
1

JavaScript (ES6), 115 bytes

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

No requiere ninguna entrada. El formateo fue doloroso. Si hubiera un límite superior en la cantidad de relleno, podría reducirlo (' '.repeat(99)+n)a algo más corto, por ejemplo ` ${n}`.

Neil
fuente
Creo que puede reemplazar /[^]/gcon /./gpara guardar dos bytes
Patrick Roberts
@PatrickRoberts No, eso omite las nuevas líneas, por lo que mi recuento estaría apagado.
Neil
Ah, nunca lo noté antes.
Patrick Roberts
1

PowerShell, 140 bytes

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

(Nueva línea dejada en claro: D)

La primera línea toma entrada $a, y luego la siguiente parte es una sola declaración. Estamos estableciendo $cigual a algunas cadenas .length . Esto formará nuestro relleno necesario. Dentro de la cadena hay un bloque de código inmediato $(...), por lo que ese código se ejecutará antes de evaluarlo en la cadena.

En el bloque de código, enviamos tres elementos a través del |sortcomando y luego tomamos el más grande (...)[-1]. Aquí es donde nos aseguramos de que las columnas tengan el ancho correcto. Los tres elementos son $lel recuento de líneas, dónde estamos -spliten las nuevas líneas, el $wrecuento de palabras, dónde estamos -spliten los espacios en blanco y $bla longitud.

La segunda línea es nuestra salida usando el -foperador (que es una pseudo-abreviatura para String.Format()). Es otra forma de insertar variables expandidas en cadenas. Aquí, estamos diciendo que queremos que toda la salida se rellene a la izquierda para que cada columna sea $cancha. El relleno se realiza a través de espacios. El 0, 1y 2corresponden a la $l, $wy $bque son argumentos para el operador de formato, por lo que el número de líneas, recuento de palabras, y la cuenta de bytes son acolchado y salida adecuadamente.

Tenga en cuenta que esto requiere que la cadena tenga líneas nuevas ya expandidas (p. Ej., Haciendo un Get-Contenten un archivo de texto o algo, y luego canalizando o guardando eso en una variable, luego llamando a este código en esa entrada), o use el PowerShell- caracteres de escape con estilo con backticks (es decir, en `nlugar de \n).

Ejemplo

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

Ruby, 108 bytes

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}*" "}
afuo
fuente
0

Perl, 71 62 61 bytes

incluye +1 para -n

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

Comentado:

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
  • Guarde otro byte, nuevamente gracias a @TonHospel.
  • ¡Ahorre 9 bytes gracias a @TonHospel que me muestra algunos trucos del intercambio!
Kenney
fuente
Algunos trucos del oficio: usar y///ccomo una longitud más corta de $_. split$"en contexto escalar da el número de palabras en $_. Al usar una variable de puntuación como en $;lugar de $W, puede colocar un djusto después de la interpolación en la cadena de formato. A continuación, puede caer el den $Wy soltar el paréntesis. Y -pno gana nada -n, solo deja que printfhaga la impresión (agrega una nueva línea al gusto)
Ton Hospel
Impresionante, lo aprecio!
Kenney
Una cadena de cálculo como $a=foo;$b=bar$ageneralmente se puede escribir como $b=bar($a=foo), guardando un byte. Aplicable aquí a $;y $b. No te importa si $;se recalcula cada vez
Ton Hospel
¡Gracias! Pasé por alto eso porque hay dos bloques ...
Kenney
0

Lua, 74 66 bytes

Golfizado:

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

Sin golf:

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

Recibe información a través de argumentos de línea de comando.

Cambiamos el nombre del primer argumento ( arg[1]) para guardar bytes. string.gsubdevuelve el número de reemplazos, así como la cadena modificada, por lo que estamos usando eso para contar primero '\n'(nuevas líneas), luego '%S+'(instancias de uno o más caracteres que no son espacios en blanco, tantos como sea posible, es decir, palabras). Podemos usar lo que queramos para la cadena de reemplazo, por lo que usamos la cadena vacía ( '') para guardar bytes. Luego solo usamos string.lenpara encontrar la longitud de la cadena, es decir, el número de bytes. Luego, finalmente, lo imprimimos todo.

Jesse Paroz
fuente
Sin embargo
Ton Hospel
0

Retina, 65

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

Pruébalo en línea!

La primera etapa es el programa wc real, el resto es para relleno. Lo del amarcador de posición es probablemente innecesario, y algunos de los grupos probablemente se pueden simplificar un poco.

FryAmTheEggman
fuente
0

Haskell, 140 bytes

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 versión sin golf se detalla a continuación, con nombres de variables y funciones expandidos:

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))

Esta es una función que acepta una cadena y devuelve una cadena. Solo usa las Preludefunciones words(resp. lines) Para obtener el número de palabras (líneas resp.) Dado que parecen usar la misma definición wc, luego obtiene el valor más largo (como una cadena) entre los recuentos y usa el formato printf tomando el ancho entre sus argumentos para formatear.

arjanen
fuente
0

C, 180 178 bytes

#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);}
usuario2064000
fuente
111 bytes
ceilingcat
0

05AB1E , 24 23 bytes

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

jactualmente tiene errores, por lo que podría haber sido de 21 bytes sin el §y J..

Pruébelo en línea o verifique todos los casos de prueba .

Explicación:

¨          # 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
fuente
0

Pip -s , 25 bytes

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

Toma la cadena multilínea como argumento de línea de comando. Pruébalo en línea!

Gracias a la respuesta de Dennis CJam por hacerme darme cuenta de que el número más largo siempre es el recuento de caracteres.

Explicación

                           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)

Aquí hay una solución de 29 bytes con banderas -rsque toma información de stdin:

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

Pruébalo en línea!

DLosc
fuente
0

PowerShell, 123 115 bytes

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 prueba:

$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"
}

Salida:

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

Explicación:

  • $args|% t*y divide las cadenas de arumentos en caracteres
  • switch -r($args|% t*y)evaluar todos los casos coincidentes
    • '\s' caso para cualquier espacio en blanco
    • '\S' caso para cualquier espacio no en blanco
    • '(?s).' estuche para cualquier char (nueva línea incluida)
    • '\n' caso para newline char (newline se representa a sí mismo)
  • $c="$b".Lengthcalcular una longitud de número de bytes. $ b siempre es máximo ($ l, $ w, $ b) por diseño
  • "{0,$c} {1,$c} $b"-f$l,+$wNúmeros de formato con la misma longitud. La variable $ w se convierte en int. Necesita cuerdas sin palabras. Otros formatos de variables 'como están' porque 'La entrada siempre contendrá una nueva línea final' y $ ly $ b no pueden ser 0.
mazzy
fuente