Reimplementar o wc coreutil

27

Esse desafio é semelhante ao anterior , mas com algumas partes pouco claras das especificações e requisitos de E / S menos rigorosos.


Dada a entrada de uma sequência que consiste apenas em ASCII e novas linhas imprimíveis, produz várias métricas (bytes, palavras, contagem de linhas).

As métricas que você deve gerar são as seguintes:

  • Contagem de bytes. Como a sequência de entrada permanece em ASCII, também é a contagem de caracteres.

  • Contagem de palavras. Esta é wca definição de uma "palavra": qualquer sequência de espaço não em branco. Por exemplo, abc,def"ghi"é uma "palavra".

  • Contagem de linhas. Isso é auto-explicativo. A entrada sempre conterá uma nova linha à direita, o que significa que a contagem de linhas é sinônimo de "contagem de novas linhas". Nunca haverá mais do que uma única nova linha à direita.

A saída deve replicar exatamente a wcsaída padrão (exceto o nome do arquivo):

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

Observe que a contagem de linhas vem primeiro, depois a contagem de palavras e, finalmente, a contagem de bytes. Além disso, cada contagem deve ser preenchida à esquerda com espaços para que tenham a mesma largura. No exemplo acima, 5501é o número "mais longo" com 4 dígitos, portanto, 165é preenchido com um espaço e 90com dois. Finalmente, todos os números devem ser unidos em uma única sequência de caracteres com um espaço entre cada número.

Como esse é o , o código mais curto em bytes será vencedor.

(Ah, e a propósito ... você não pode usar o wccomando na sua resposta. Caso isso já não fosse óbvio.)

Casos de teste ( \nrepresenta uma nova linha; opcionalmente, você também pode precisar de uma nova linha à direita):

"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"
Maçaneta da porta
fonte
2
Vou VTC o antigo como um idiota deste porque este é um desafio muito melhor.
Mego 26/02
A entrada vazia deve ser suportada?
Ton Hospel
Acho que não, ele disse que todas as entradas terminam com \ n.
CalculatorFeline

Respostas:

8

Perl, 49 bytes

Adicionado +3 para -an0

Entrada em STDIN ou 1 ou mais nomes de arquivos como argumentos. Correr comoperl -an0 wc.pl

wc.pl:

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

Explicação:

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

Python 2, 100 77 bytes

Esta solução é uma função Python que aceita uma string de várias linhas e imprime as contagens necessárias no stdout. Observe que eu uso uma string de formato para criar uma string de formato (que requer um %%para escapar do primeiro espaço reservado de formato).

Editar: salvou 23 bytes devido a otimizações de impressão de Dennis.

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

Antes do minifier, fica assim:

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

Pitão, 21 bytes

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

Suíte de teste

Pyth tem alguns ótimos embutidos aqui. Começamos fazendo uma lista ( [) das novas linhas da string ( @bQ), das palavras da string ( cQ)) e da própria string ( Q). Em seguida, preenchemos ( .[) o comprimento de cada string ( ld) com espaços ( ;nesse contexto) para o comprimento do número de caracteres ( l`lQ). Por fim, junte-se aos espaços ( jd).

isaacg
fonte
6

Awk POSIX, 79 75 67 65 bytes

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

Edit: salvo 4 bytes desde POSIX permite que um nu length, salvo 7 bytes descontando a parte invocação, e salvou dois bytes, graças a ponta do Doorknob para adicionar d %a d.

Isso foi originalmente para o GNU awk, mas o melhor que posso dizer é que ele usa apenas a funcionalidade do POSIX awk.

Melhor formatado:

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
fonte
@ Doorknob OK, obrigado por isso. Acho que você viu a conversa no chat? Além disso, essa pergunta deve passar de faq-proposta para faq .
muru
1
Oh, eu não te vi no chat; sua resposta acabou de aparecer na minha caixa de entrada: PI foi quem adicionou [proposta de faq] a essa pergunta, então talvez eu deva verificar a sala de mods antes de atualizá-la para [faq].
Maçaneta
1
Definir dcomo length(c)"d %"deve permitir que você altere printfpara "%"d d"d\n", o que salva dois bytes.
Maçaneta
1
@ Doorknob de fato, obrigado! Acho que não é o exótico , mas o mundano que salva bytes.
Muni
6

Sério , 39 bytes

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

Experimente online!

Explicação (novas linhas são substituídas 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
fonte
Não consigo encontrar nenhuma documentação para esse idioma. Você pode fornecer um link?
JohnEye 26/02
2
@JohnEye, github.com/Mego/Seriously
awesoon
3

AppleScript, 253 bytes

Isso pressupõe que os delimitadores de itens de texto do AppleScript estejam configurados no espaço (se precisar contar as coisas para forçar essa suposição, adicionarei).

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

CJam, 31 26 bytes

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

Experimente online!

Como 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
fonte
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 é uma função que aceita uma string e retorna uma string.

Salvamos o seguinte como argumentos de função:

  • n = endof função, que obtém o último índice de uma coleção indexável (nesse caso, é o comprimento da string)
  • l = "$(n(s)), o comprimento da entrada convertida em uma sequência usando interpolação
  • Uma função lambda gque aceita uma expressão regular e retorna o comprimento - 1 da divisão de entrada nesse regex, preenchida à esquerda com espaços para corresponder ao comprimento de l.

Nós obtemos o número de linhas usando g(r"\n")e o número de palavras usando g(r"\S+"), depois juntamos as que são ldelimitadas por espaços.

Economizou 31 bytes graças a Dennis!

Alex A.
fonte
2

MATL, 38 bytes

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

Você pode experimentá-lo online! Isso não deve demorar tanto ...

Explicação, para o 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

A última parte faz a formatação de saída

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
fonte
Bem feito! Talvez remova o sinalizador "debug" no link Experimente online ?
Luis Mendo
Ahh gritos! Obrigado pela atenção!
David
Eu acho que você pode substituir !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` `

Não requer nenhuma entrada. A formatação foi dolorosa. Se houvesse um limite superior na quantidade de preenchimento, eu poderia reduzir (' '.repeat(99)+n)para algo mais curto, por exemplo ` ${n}`.

Neil
fonte
Eu acho que você pode substituir /[^]/gcom /./ga salvar dois bytes
Patrick Roberts
@PatrickRoberts Não, isso pula as novas linhas, então minha contagem estaria desativada.
Neil
Ah, nunca notei isso 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

(nova linha deixada para maior clareza: D)

A primeira linha recebe entrada $ae, em seguida, a próxima parte é toda uma declaração. Estamos definindo $cigual a algumas cordas .length . Isso formará nosso preenchimento necessário. Dentro da sequência há um bloco de código imediato $(...), para que o código seja executado antes de ser avaliado na sequência.

No bloco de código, estamos enviando três itens através do |sortcomando e, em seguida, pegando o maior (...)[-1]. É aqui que garantimos que as colunas tenham a largura correta. Os três itens são $la contagem de linhas, onde estamos -splitem novas linhas, a $wcontagem de palavras, onde estamos -splitem espaços em branco e $bo comprimento.

A segunda linha é a nossa saída usando o -foperador (que é uma pseudo-abreviação para String.Format()). É outra maneira de inserir variáveis ​​expandidas em strings. Aqui, estamos dizendo que queremos que toda a saída seja preenchida à esquerda para que cada coluna seja $clarga. O preenchimento é feito através de espaços. A 0, 1, e 2correspondem a uma $l, $we $bque são argumentos para o operador de formato, de modo que o número de linhas, número de palavra, e contagem de bytes são acolchoado e saída de forma apropriada.

Observe que isso exige que a string tenha novas linhas já expandidas (por exemplo, fazendo um Get-Contentem um arquivo de texto ou algo assim, e então canalizando ou salvando isso em uma variável e chamando esse código nessa entrada) ou use o PowerShell- caracteres de escape com estilo com reticências (ou seja, em `nvez de \n).

Exemplo

PS C:\Tools\Scripts\golfing> .\reimplement-wc.ps1 "This line`nis broken`ninto three lines.`n"
 3  7 38
AdmBorkBork
fonte
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}*" "}
úmido
fonte
0

Perl, 71 62 61 bytes

inclui +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
  • Salve outro byte, novamente graças a @TonHospel.
  • Economize 9 bytes graças a @TonHospel, mostrando-me alguns truques do comércio!
Kenney
fonte
Alguns truques do comércio: Use y///ccomo um comprimento menor de $_. split$"no contexto escalar fornece o número de palavras em $_. Usando uma variável de pontuação como em $;vez de $Wvocê pode colocar um dlogo após a interpolação na string de formato. Depois, você pode soltar o dem $We soltar o parêntese. E -pnão ganha nada mais -n, deixe-o printffazer a impressão (adicionar uma nova linha a gosto)
Ton Hospel
Incrível, eu aprecio isso!
Kenney
Uma cadeia de cálculo como $a=foo;$b=bar$ageralmente pode ser escrita como $b=bar($a=foo), economizando um byte. Aplicável aqui a $;e $b. Você não se importa se $;é recalculado toda vez
Ton Hospel
Obrigado! I esquecer que porque há dois blocos ...
Kenney
0

Lua, 74 66 bytes

Golfe:

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

Ungolfed:

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

Recebe entrada através de argumentos de linha de comando.

Renomeamos o primeiro argumento ( arg[1]) para salvar bytes. string.gsubretorna o número de substituições e a sequência modificada. Por isso, usamos isso para contar primeiro '\n'(novas linhas) e, em seguida,'%S+' (instâncias de um ou mais caracteres que não sejam espaços em branco, o maior número possível, ou seja, palavras). Podemos usar o que quisermos para a string de substituição, portanto, usamos a string vazia ( '') para salvar bytes. Então nós apenas usamos string.lenpara encontrar o comprimento da string, ou seja, o número de bytes. Então, finalmente, imprimimos tudo.

Jesse Paroz
fonte
Não vejo nenhum preenchimento esquerdo dos valores de linhas e palavras
Ton Hospel 27/16/16
0

Retina, 65

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

Experimente Online!

O primeiro estágio é o programa wc real, o restante é para preenchimento. O aespaço reservado provavelmente é desnecessário, e alguns dos grupos provavelmente podem ser um pouco simplificados.

FryAmTheEggman
fonte
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

A versão ungolfed está abaixo, com nomes expandidos de variáveis ​​e funções:

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 é uma função que aceita uma string e retorna uma string. Apenas usa as Preludefunções words(resp.lines ) Para obter o número de palavras (resp. Linhas), uma vez que elas parecem usar a mesma definição de wc, então obtém o maior valor (como uma string) entre as contagens e usam o formato printf usando a largura entre seus argumentos para formatação.

arjanen
fonte
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);}
user2064000
fonte
111 bytes
ceilingcat
0

05AB1E , 24 23 bytes

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

j está atualmente com problemas, então poderia ter 21 bytes sem o § e J..

Experimente online ou verifique todos os casos de teste .

Explicação:

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

Pip -s , 25 bytes

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

Leva a cadeia de linhas múltiplas como um argumento da linha de comandos. Experimente online!

Graças a resposta CJam de Dennis por me fazer perceber que o número mais longo é sempre a contagem de caracteres.

Explicação

                           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)

Aqui está uma solução de 29 bytes com sinalizadores -rsque recebe a entrada do stdin:

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

Experimente online!

DLosc
fonte
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 teste:

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

Saída:

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

Explicação:

  • $args|% t*y divide seqüências de caracteres de argumentos em caracteres
  • switch -r($args|% t*y)avaliar todos os casos correspondentes
    • '\s' caso para qualquer espaço em branco
    • '\S' caso para qualquer espaço não em branco
    • '(?s).' caso de qualquer caractere (nova linha incluída)
    • '\n' caso para newline char (nova linha representa a si mesma)
  • $c="$b".Lengthcalcular um comprimento de número de bytes. $ b é sempre máximo ($ l, $ w, $ b) por design
  • "{0,$c} {1,$c} $b"-f$l,+$wformatar números com o mesmo comprimento. A variável $ w é convertida em int. Precisa de strings sem palavras. Outras variáveis ​​são formatadas 'como estão' porque 'A entrada sempre conterá uma nova linha à direita' e $ le $ b não podem ser 0.
confuso
fonte