Ponownie zaimplementuj wc coreutil

27

To wyzwanie jest podobne do tego starego , ale z pewnymi niejasnymi częściami specyfikacji i mniej surowymi wymaganiami wejścia / wyjścia.


Biorąc pod uwagę ciąg znaków składający się tylko z drukowalnego kodu ASCII i nowego wiersza, wypisz jego różne metryki (bajt, słowo, liczba wierszy).

Dane, które należy wygenerować, są następujące:

  • Liczba bajtów. Ponieważ ciąg wejściowy pozostaje w obrębie ASCII, jest to również liczba znaków.

  • Liczba słów. To jest wcdefinicja „słowa:” dowolnej sekwencji spacji. Na przykład abc,def"ghi"to jedno „słowo”.

  • Liczba linii To jest oczywiste. Dane wejściowe zawsze będą zawierać końcowy znak nowej linii, co oznacza, że ​​liczba wierszy jest równoznaczna z „liczbą nowych wierszy”. Nigdy nie będzie więcej niż jedna nowa linia końcowa.

Dane wyjściowe muszą dokładnie replikować dane wcwyjściowe (z wyjątkiem nazwy pliku):

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

Zauważ, że najpierw pojawia się liczba wierszy, potem liczba słów, a na końcu liczba bajtów. Ponadto każda liczba musi być wypełniona lewą spacją, tak aby wszystkie miały tę samą szerokość. W powyższym przykładzie 5501„najdłuższa” liczba składa się z 4 cyfr, więc 165jest uzupełniona jedną spacją i 90dwiema. Na koniec wszystkie liczby muszą być połączone w jeden ciąg ze spacją między każdą liczbą.

Ponieważ jest to , wygra najkrótszy kod w bajtach.

(A tak przy okazji ... nie możesz użyć wcpolecenia w swojej odpowiedzi. W przypadku, gdy nie było to już oczywiste).

Przypadki testowe ( \nreprezentuje znak nowej linii; opcjonalnie możesz również wymagać wprowadzenia nowej linii końcowej):

"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"
Klamka
źródło
2
Będę VTC stary jako duplikat tego, ponieważ ten jest o wiele lepszym wyzwaniem.
Mego
Czy powinno być obsługiwane puste wejście?
Ton Hospel
Nie sądzę, powiedział, że wszystkie dane wejściowe kończą się na \ n.
CalculatorFeline

Odpowiedzi:

8

Perl, 49 bajtów

Dodano +3 do -an0

Wprowadź jako STDIN lub 1 lub więcej nazw plików jako argumenty. Uruchom jakoperl -an0 wc.pl

wc.pl:

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

Wyjaśnienie:

-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
źródło
7

Python 2, 100 77 bajtów

To rozwiązanie jest funkcją Pythona, która akceptuje wieloliniowy ciąg znaków i drukuje wymagane liczby na standardowe wyjście. Zauważ, że używam ciągu formatu do zbudowania ciągu formatu (który wymaga %%zmiany znaku zastępczego pierwszego formatu).

Edycja: Zapisano 23 bajty dzięki optymalizacji drukowania przez Dennisa.

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

Przed minizatorem wygląda to tak:

def wc(text) :
    size = len(text);
    numfmt = '%%%us' % len(`size`);
    print numfmt % text.count('\n'), numfmt % len(text.split()), size
Logic Knight
źródło
7

Pyth, 21 bajtów

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

Zestaw testowy

Pyth ma tutaj kilka bardzo fajnych wbudowanych funkcji. Zaczynamy od utworzenia listy ( [) nowych wierszy w ciągu ( @bQ), słów w ciągu ( cQ)) i samego ciągu ( Q). Następnie dopełniamy ( .[) długość każdego łańcucha ( ld) spacjami ( ;w tym kontekście) do długości liczby znaków ( l`lQ). Na koniec dołącz do spacji ( jd).

isaacg
źródło
6

POSIX awk, 79 75 67 65 bajtów

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

Edit: zapamiętanych 4 bajty od POSIX pozwala nagie length, zapisywane 7 bajtów poprzez zdyskontowanie część wywołania, a zapisane dwa bajty dzięki końcówce klamce za dodanie d %do d.

To było pierwotnie dla GNU awk, ale co mogę powiedzieć, wykorzystuje tylko funkcjonalność POSIX awk.

Lepiej sformatowany:

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
źródło
@Doorknob OK, dzięki za to. Chyba widziałeś rozmowę na czacie? Ponadto pytanie to powinno przejść od pytania najczęściej zadawanego do najczęściej zadawanych pytań .
muru
1
Och, nie widziałem cię na czacie; Twoja odpowiedź właśnie pojawiła się w mojej skrzynce odbiorczej: PI był tym, który dodał [najczęściej zadawane pytania] do tego pytania, więc może sprawdzę pokój modów przed uaktualnieniem go do [faq].
Klamka
1
Ustawianie dsię length(c)"d %"powinno pozwolić na zmianę printfcelu "%"d d"d\n", co pozwala zaoszczędzić dwa bajty.
Klamka
1
@Doorknob rzeczywiście, dzięki! Chyba nie jest to egzotyczne , ale zwykłe, które oszczędza bajty.
muru
6

Poważnie , 39 bajtów

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

Wypróbuj online!

Objaśnienie (nowe znaki są zastępowane przez \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
źródło
Nie mogę znaleźć dokumentacji dla tego języka, czy możesz podać link?
JohnEye
2
@JohnEye, github.com/Mego/Seriously
awesoon
3

AppleScript, 253 bajty

Zakłada się, że ograniczniki elementów tekstowych AppleScript są ustawione na spację (jeśli muszę policzyć rzeczy, aby wymusić to założenie, dodam je).

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
źródło
3

CJam, 31 26 bajtów

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

Wypróbuj online!

Jak to działa

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
źródło
3

Julia, 112 81 bajtów

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

Ta funkcja przyjmuje łańcuch i zwraca łańcuch.

Zapisujemy następujące jako argumenty funkcji:

  • n = endof funkcja, która pobiera ostatni indeks kolekcji indeksowalnej (w tym przypadku jest to długość łańcucha)
  • l = "$(n(s)), długość danych wejściowych konwertowanych na ciąg przy użyciu interpolacji
  • Funkcja lambda, gktóra akceptuje wyrażenie regularne i zwraca długość - 1 wartości wejściowej podzielonej w tym wyrażeniu regularnym, po lewej stronie jest wypełniona spacjami, aby dopasować długość l.

Otrzymujemy liczbę używanych wierszy g(r"\n")i liczbę używanych słów g(r"\S+"), a następnie łączymy je razem ze lznakami spacji.

Zaoszczędzono 31 bajtów dzięki Dennisowi!

Alex A.
źródło
2

MATL, 38 bajtów

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

Możesz spróbować online! To nie powinno tak długo trwać ...

Wyjaśnienie do obliczeń

'\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

Ostatnia część wykonuje formatowanie wyjściowe

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
źródło
Ładnie wykonane! Może usunąć flagę „debugowanie” w linku Wypróbuj online ?
Luis Mendo,
Ahh ups! Dzięki za heads-up!
David
Myślę, że można zastąpić !3Z"vX:!przez Z{Zc( cellstrnastępnie strjoin)
Luis Mendo
1

JavaScript (ES6), 115 bajtów

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

Nie wymaga żadnych danych wejściowych. Formatowanie było bolesne. Gdyby istniała górna granica ilości wypełnienia, mogłabym zredukować ją (' '.repeat(99)+n)do czegoś krótszego np ` ${n}`.

Neil
źródło
Myślę, że można zastąpić /[^]/gz /./gaby zapisać dwa bajty
Patrick Roberts
@PatrickRoberts Nie, to pomija nowe linie, więc moja liczba byłaby wyłączona.
Neil
Ach, nigdy wcześniej tego nie zauważyłem.
Patrick Roberts,
1

PowerShell, 140 bajtów

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

(dla jasności pozostawiono nowy wiersz: D)

Pierwszy wiersz pobiera dane wejściowe $a, a następnie kolejna część to jedna instrukcja. Ustawiamy wartość $crówną niektórym strunom .length . To stworzy nasze wymagane wypełnienie. Wewnątrz ciągu znajduje się natychmiastowy blok kodu $(...), dzięki czemu kod zostanie wykonany przed przetworzeniem na ciąg.

W bloku kodu wysyłamy trzy |sortpolecenia za pomocą polecenia, a następnie przyjmujemy największy (...)[-1]. Zapewniamy, aby kolumny miały odpowiednią szerokość. Te trzy elementy to $lliczba wierszy, gdzie jesteśmy -splitna znakach nowej linii, $wliczba słów, gdzie jesteśmy -splitna białych znakach i $bdługość.

Drugi wiersz to nasze dane wyjściowe przy użyciu -foperatora (który jest pseudo-skrótem dla String.Format()). Jest to inny sposób wstawiania rozszerzonych zmiennych do ciągów. Mówimy tutaj, że chcemy, aby wszystkie dane wyjściowe były wypełnione w lewo, aby każda kolumna była $cszeroka. Wypełnienie odbywa się za pomocą spacji. 0, 1I 2odpowiadają $l, $wi $bże są argumenty do operatora formatu, więc liczba linii, liczba słów, a liczba bajtów są wyściełane i wyjście odpowiednio.

Zauważ, że wymaga to, aby ciąg miał już rozwinięte znaki nowej linii (np. Robienie Get-Contentna pliku tekstowym lub coś, a następnie albo przesyłanie potokowe lub zapisywanie do zmiennej, a następnie wywoływanie tego kodu na tym wejściu), lub użycie PowerShell- stylowe znaki ucieczki z backtickami (czyli `nzamiast \n).

Przykład

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

Rubinowy, 108 bajtów

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}*" "}
obolały
źródło
0

Perl, 71 62 61 bajtów

zawiera +1 dla -n

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

Skomentowano:

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
  • Zapisz kolejny bajt, ponownie dzięki @TonHospel.
  • Zaoszczędź 9 bajtów dzięki @TonHospel pokazując mi kilka sztuczek!
Kenney
źródło
Kilka sztuczek w handlu: użyj y///cjako krótszej długości $_. split$"w kontekście skalarnym podaje liczbę słów w $_. Używając zmiennej interpunkcyjnej, takiej jak $;zamiast $W, możesz wstawić dtuż po interpolacji w ciągu formatu. Następnie można upuścić din $Wi upuść nawias. I -pnic nie zyskuje -n, po prostu pozwól printfdrukować (dodaj nową linię do smaku)
Ton Hospel
Świetnie, doceniam to!
Kenney
Łańcuch obliczeniowy jak $a=foo;$b=bar$azwykle można zapisać jako $b=bar($a=foo), oszczędzając jeden bajt. Dotyczy tutaj $;i $b. Nie obchodzi Cię, czy $;jest przeliczane za każdym razem
Ton Hospel
Dzięki! Przeoczyłem to, ponieważ są dwa bloki ...
Kenney
0

Lua, 74 66 bajtów

Gra w golfa:

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

Nie golfowany:

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

Odbiera dane wejściowe za pomocą argumentów wiersza poleceń.

Zmieniamy nazwę pierwszego argumentu ( arg[1]), aby zapisać bajty. string.gsubzwraca liczbę zamienników, a także zmodyfikowany ciąg, więc używamy go do liczenia najpierw '\n'(nowych linii), a następnie '%S+'(wystąpień jednego lub więcej znaków spacji, jak największej liczby, tj. słów). Możemy użyć wszystkiego, co chcemy, do zastąpienia ciągu, więc używamy pustego ciągu ( ''), aby zapisać bajty. Następnie używamy tylko string.lendo znalezienia długości ciągu, tj. Liczby bajtów. Następnie drukujemy wszystko.

Jesse Paroz
źródło
Nie widzę jednak żadnego dopełnienia wartości wierszy i słów
Ton Hospel
0

Retina, 65

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

Wypróbuj online!

Pierwszym etapem jest aktualny program wc, reszta służy do wypełnienia. Symbol azastępczy jest prawdopodobnie niepotrzebny, a niektóre grupy prawdopodobnie można nieco uprościć.

FryAmTheEggman
źródło
0

Haskell, 140 bajtów

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

Wersja bez golfa jest poniżej, z rozszerzonymi nazwami zmiennych i funkcji:

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

Ta funkcja przyjmuje łańcuch i zwraca łańcuch. Po prostu używa Preludefunkcji words(odpowiednio. lines), Aby uzyskać liczbę słów (względnie linii), biorąc pod uwagę, że wydają się używać tej samej definicji co wc, a następnie pobiera najdłuższą wartość (jako ciąg) spośród zliczeń i używa formatu printf biorąc szerokość wśród argumentów za formatowaniem.

arjanen
źródło
0

C, 180 178 bajtów

#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
źródło
111 bajtów
ceilingcat
0

05AB1E , 24 23 bajty

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

jjest obecnie błędny, więc mogło być 21 bajtów bez §i J

Wypróbuj online lub sprawdź wszystkie przypadki testowe .

Wyjaśnienie:

¨          # 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
źródło
0

Pip -s , 25 bajtów

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

Bierze ciąg multilinii jako argument wiersza poleceń. Wypróbuj online!

Dzięki odpowiedzi Dennisa na CJam za uświadomienie mi, że najdłuższa liczba jest zawsze liczbą znaków.

Wyjaśnienie

                           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)

Oto 29-bajtowe rozwiązanie z flagami, -rsktóre pobierają dane wejściowe ze standardowego wejścia:

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

Wypróbuj online!

DLosc
źródło
0

PowerShell, 123 115 bajtów

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

Skrypt testowy:

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

Wydajność:

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

Wyjaśnienie:

  • $args|% t*y dzieli ciągi argumentów na znaki
  • switch -r($args|% t*y)oceń wszystkie dopasowane przypadki
    • '\s' skrzynka na dowolne białe znaki
    • '\S' przypadek dla dowolnej spacji
    • '(?s).' skrzynka na dowolny znak (zawiera nową linię)
    • '\n' przypadek znaku nowej linii (nowa linia reprezentuje się)
  • $c="$b".Lengthobliczyć długość liczby bajtów. $ b jest zawsze maksymalne ($ l, $ w, $ b) według projektu
  • "{0,$c} {1,$c} $b"-f$l,+$wformatuj liczby o tej samej długości. Zmienna $ w konwertuje na int. Potrzebuje ciągów bez słów. Inne zmienne mają format „taki jaki jest”, ponieważ „Dane wejściowe zawsze będą zawierały znak nowej linii”, a $ l i $ b nie mogą wynosić 0.
mazzy
źródło