Converti l'intervallo di tempo leggibile dall'uomo in componenti della data


16

Sfida

Scrivi il programma più breve che converte un intervallo di tempo leggibile dall'uomo in componenti della data:

{±YEARS|±MONTHS|±DAYS|±HOURS|±MINUTES|±SECONDS}

Casi di esempio

Ogni test case è composto da due righe, input seguito da output:

1 year 2 months 3 seconds
{1|2|0|0|0|3}

-2 day 5 year 8months
{5|8|-2|0|0|0}

3day 9     years 4 seconds -5 minute 4 years 4 years -3seconds
{17|0|3|0|-5|1}

Regole

  • Non puoi usare strtotime o alcuna funzione integrata che svolge l'intero lavoro.
  • Vince il codice più breve (byte)
  • Puoi stampare il tuo output su stdouto un file, il risultato può anche essere restituito da una funzione, dipende da te
  • Il token può essere in forma singolare o plurale.
  • I componenti possono essere in ordine casuale
  • Potrebbe non esserci spazio bianco tra il numero e il token
  • Il segno è facoltativo quando l'intervallo di tempo è positivo (input e output)
  • Se un componente appare più di una volta, è necessario aggiungere i valori
  • Ogni componente ha il suo segno
  • I componenti devono essere gestiti separatamente (ad es. 80 minutesRimangono come 80 in uscita)
  • L'ingresso è garantito in minuscolo

Buon golf!


2
Mi piace questa sfida, ma faccio fatica a trovare qualcosa che non sia lungo e disordinato in lingue inadatte al golf del codice. : /
Alex A.

Il formato di output è importante?
Titus

Sign is optional when the time interval is positive Significa che l'input può contenere + segni?
Tito

Risposte:


3

CJam, 60 byte

Dopo essere stato bloccato negli anni '60 per molto tempo, sono finalmente riuscito a comprimerlo fino a 60 byte. Abbastanza buono! Spediscilo!

Provalo online

schiacciata:

'{0a6*q[{_A,s'-+#)!{"ytdhic"#:I){]'0+iA/I_3$=@+t[}*}*}/'|*'}

Ampliato e commentato:

'{              "Add '{' to output";
0a6*            "Initialize time to a list of 6 zeros";
q               "Read the input";
[               "Open an empty numeric character buffer";
{               "For each character in the input:";
  _               "Append the character to the numeric character buffer";
  A,s'-+#)!       "Check if the character is not part of a number";
  {               "If so:";
    "ytdhic"#:I     "Remove the character from the numeric character buffer and
                     convert it to the corresponding time unit index, or -1 if
                     not recognized
                     (Time units are recognized by a character in their name
                     that does not appear before the recognition character
                     in any other name)";
    ){              "Repeat (time unit index + 1) times:";
      ]'0+iA/         "Close the numeric character buffer and parse it as an
                       integer (empty buffer is parsed as 0)";
      I_3$=@+t        "Add the integer to the value of the indexed time unit";
      [               "Open an empty numeric character buffer";
    }*              "End repeat
                     (This is used like an if statement, taking advantage of
                     the fact that iterations after the first have no effect)";
  }*              "End if";
}/              "End for";
'|*             "Insert a '|' between each time unit value (implicitly added to
                 output)";
'}              "Add '}' to output";

Inizialmente ho iniziato a utilizzare un approccio basato su token, ma che si è bloccato piuttosto saldamente a ... 61 byte. Sospiro. Quindi ho completamente cambiato marcia e sono passato a questo approccio basato sui personaggi, che è comunque molto più interessante.

Il mio metodo di analisi funziona aggiungendo tutti i caratteri numerici validi raggiunti ( 0- 9e- ) a un buffer e analizzando il buffer come numero intero quando viene raggiunto un determinato carattere da uno dei nomi delle unità di tempo. Quei personaggi sono y, t, d, h, i, ec, che soddisfano tutte le condizioni che compaiono nel nome di un'unità di tempo e non compaiono prima del carattere di riconoscimento in nessun altro nome di unità di tempo. In altre parole, quando viene raggiunto uno di questi caratteri di riconoscimento di unità di tempo, il buffer numerico verrà riempito con l'ultimo numero visualizzato se questo in realtà segnala un'unità di tempo, oppure il buffer numerico sarà vuoto se questo appare solo in, ma non dovrebbe segnale t, qualche altra unità di tempo. In entrambi i casi, il buffer numerico viene analizzato come un numero intero o 0 se era vuoto e questo viene aggiunto al corrispondente valore di unità di tempo. Pertanto, i caratteri di riconoscimento che appaiono in altre unità di tempo dopo il loro carattere di riconoscimento non hanno alcun effetto.

Altri hack pazzi includono:

  • Abuso di cicli in modo che i caratteri numerici vengano lasciati nello stack (che funge da buffer dei caratteri numerici) "gratuitamente".
  • Ripetendo un blocco zero o più volte invece che in modo condizionale perché il ciclo è più compatto di un'istruzione if e le iterazioni dopo la prima non hanno alcun effetto.

Per chiunque sia curioso della mia soluzione basata su token bloccata a 61 byte, la posterò anche qui. Tuttavia, non sono mai riuscito ad espandermi o commentarlo.

CJam, 61 byte

'{0a6*q'm-'{,64/~m*{:X/XS**}/S%2/{~0="yodhis"#_3$=@i+t}/'|*'}

+1 Questo merita sicuramente più voti.
oopbase,

2
@ Forlan07 Grazie per il supporto. :) Ma ero in ritardo per rispondere, quindi non è inaspettato. Il processo di produzione di questa risposta è stato comunque abbastanza soddisfacente.
Runer112,

10

Perl: 61 caratteri

Grazie a @nutki.

s/-?\d+ *m?(.)/$$1+=$&/ge;$_="{y|o|d|h|i|s}";s/\w/${$&}+0/ge

Esecuzione di esempio:

bash-4.3$ perl -pe 's/-?\d+ *m?(.)/$$1+=$&/ge;$_="{y|o|d|h|i|s}";s/\w/${$&}+0/ge' <<< '1 year 2 months 3 seconds'
{1|2|0|0|0|3}

bash-4.3$ perl -pe 's/-?\d+ *m?(.)/$$1+=$&/ge;$_="{y|o|d|h|i|s}";s/\w/${$&}+0/ge' <<< '-2 day 5 year 8months'
{5|8|-2|0|0|0}

bash-4.3$ perl -pe 's/-?\d+ *m?(.)/$$1+=$&/ge;$_="{y|o|d|h|i|s}";s/\w/${$&}+0/ge' <<< '3day 9     years 4 seconds -5 minute 4 years 4 years -3seconds'
{17|0|3|0|-5|1}

I miei scarsi sforzi: 78 77 caratteri

s/([+-]?\d+) *(..)/$a{$2}+=$1/ge;$_="{ye|mo|da|ho|mi|se}";s/\w./$a{$&}||0/ge

1
Alcuni miglioramenti che ho potuto trovare:s/(-?\d+) *(..)/$$2+=$1/ge;$_="{ye|mo|da|ho|mi|se}";s/\w./${$&}+0/ge
nutki

1
Altri 4 caratteri:s/-?\d+ *(m.|.)/$$1+=$&/ge;$_="{y|mo|d|h|mi|s}";s/\w+/${$&}+0/ge
nutki

Wow. Grandi trucchi, @nutki.
arte

1
Anche trovato in altre soluzioni, (m.|.)-> m?(.)risparmia 4.
nutki

Doh. Stava per provare ora. Quindi funziona. :)
Opera d'arte

5

Rubino, 119 106 86 85 84 byte

Un byte salvato grazie a Sp3000.

->i{?{+"yodhis".chars.map{|w|s=0;i.scan(/-?\d+(?= *m?#{w})/){|n|s+=n.to_i};s}*?|+?}}

Questa è una funzione senza nome, che accetta l'input come stringa e restituisce il risultato (anche come stringa). Puoi testarlo assegnandolo a f, diciamo, e chiamandolo come

f["3day 9     years 4 seconds -5 minute 4 years 4 years -3seconds"]

5

Python 2, 99 byte

import re
f=lambda I:"{%s}"%"|".join(`sum(map(int,re.findall("(-?\d+) *m?"+t,I)))`for t in"yodhis")

Questa è una funzione lambda che accetta una stringa e usa semplicemente una regex per estrarre i numeri necessari.

Grazie a Martin per averci sottolineato che \s*potrebbe essere <space>*. È facile dimenticare che le regex corrispondono letteralmente agli spazi ...


4

JavaScript 100 105 112

Modifica Aggiunta di stringhe modello (implementata per la prima volta nel 2014, quindi valida per questa sfida) - al momento non ne ero a conoscenza

Modifica Eureka, finalmente ho avuto il significato di m?in tutte le altre risposte!

s=>s.replace(/(-?\d+) *m?(.)/g,(a,b,c)=>o['yodhis'.search(c)]-=-b,o=[0,0,0,0,0,0])&&`{${o.join`|`}}`

Test

F=
s=>s.replace(/(-?\d+) *m?(.)/g,(a,b,c)=>o['yodhis'.search(c)]-=-b,o=[0,0,0,0,0,0])&&`{${o.join`|`}}`

;['1 year 2 months 3 seconds','-2 day 5 year 8months'
,'3day 9     years 4 seconds -5 minute 4 years 4 years -3seconds']
.forEach(i=>console.log(i,F(i)))


3

R, 197 byte

Mi rendo conto che questa non è affatto una voce competitiva, per lo più volevo solo trovare una soluzione in R. Qualsiasi aiuto per accorciarlo è ovviamente il benvenuto.

function(x){s="{";for(c in strsplit("yodhis","")[[1]])s=paste0(s,ifelse(c=="y","","|"),sum(as.numeric(gsub("[^0-9-]","",str_extract_all(x,perl(paste0("(-?\\d+) *m?",c)))[[1]]))));s=paste0(s,"}");s}

Come la risposta di Martin, questa è una funzione senza nome. Per chiamarlo, assegnalo af e passa una stringa.

È piuttosto orribile, quindi diamo un'occhiata a una versione non giocata a golf.

function(x) {
    s <- "{"
    for (c in strsplit("yodhis", "")[[1]]) {
        matches <- str_extract_all(x, perl(paste0("(-?\\d+) *m?", c)))[[1]]
        nums <- gsub("[^0-9-]", "", matches)
        y <- sum(as.numeric(nums))
        s <- paste0(s, ifelse(c == "y", "", "|"), y)
    }
    s <- paste0(s, "}")
    return(s)
}

Basandoti solo sulla struttura è facile vedere cosa sta succedendo, anche se non hai troppa familiarità con R. Elaborerò alcuni aspetti dall'aspetto estraneo.

paste0() è il modo in cui R combina stringhe senza separatore.

La str_extract_all()funzione viene dal stringrpacchetto di Hadley Wickham . La gestione di R di espressioni regolari nel pacchetto di base lascia molto a desiderare, ed è qui che stringrentra in gioco. Questa funzione restituisce un elenco di corrispondenze di espressioni regolari nella stringa di input. Notate come il regex è circondato in una funzione - perl()questo sta solo dicendo che il regex è in stile Perl, non in stile R.

gsub()esegue una ricerca e sostituzione usando una regex per ogni elemento del vettore di input. Qui lo diciamo per sostituire tutto ciò che non è un numero o un segno meno con una stringa vuota.

E il gioco è fatto. Ulteriori spiegazioni saranno fornite volentieri su richiesta.


Non credo che l'outsourcing dell'estrazione di stringhe in un pacchetto esterno sia una buona idea. Non è una scappatoia quando viene utilizzata una libreria esterna supportata dalla comunità? Anche se va bene, perché non hai incluso library(stringr)nella tua fonte?
Andreï Kostyrka l'

2

Cobra - 165

def f(s='')
    l=int[](6)
    for i in 6,for n in RegularExpressions.Regex.matches(s,'(-?\\d+) *m?['yodhis'[i]]'),l[i]+=int.parse('[n.groups[1]]')
    print'{[l.join('|')]}'

2

C ++ 14, 234 229 byte

Modifica: abbassa 5 byte utilizzando la dichiarazione di vecchio stile anzichéauto.

So che il vincitore è già stato scelto e che questa sarebbe stata la presentazione più lunga finora, ma dovevo solo pubblicare una soluzione C ++, perché scommetto che nessuno se lo aspettava affatto :)

Ad essere onesti, sono abbastanza contento di quanto sia stato breve (dalle misurazioni C ++, ovviamente), e sono sicuro che non può essere più breve di questo (con una sola osservazione, vedi sotto) . È anche una bella collezione di funzionalità nuove in C ++ 11/14.

Nessuna libreria di terze parti qui, viene utilizzata solo la libreria standard.

La soluzione è in una forma di funzione lambda:

[](auto&s){sregex_iterator e;auto r="{"s;for(auto&t:{"y","mo","d","h","mi","s"}){int a=0;regex g("-?\\d+ *"s+t);decltype(e)i(begin(s),end(s),g);for_each(i,e,[&](auto&b){a+=stoi(b.str());});r+=to_string(a)+"|";}r.back()='}';s=r;};

Ungolfed:

[](auto&s)
{
    sregex_iterator e;
    auto r="{"s;
    for(auto&t:{"y","mo","d","h","mi","s"})
    {
        int a=0;
        regex g("-?\\d+\\s*"s+t);
        decltype(e)i(begin(s),end(s),g);
        for_each(i,e,[&](auto&b)
        {
            a+=stoi(b.str());
        });
        r+=to_string(a)+"|";
    }
    r.back()='}';
    s=r;
}

Per qualche motivo, ho dovuto scrivere

regex g("-?\\d+\\s*"s+t);
decltype(e)i(begin(s),end(s),g);

invece di solo

decltype(e)i(begin(s),end(s),regex("-?\\d+\\s*"s+t));

perché l'iteratore restituisce una corrispondenza solo se passo un oggetto temporaneo. Questo non mi sembra giusto, quindi mi chiedo se ci sia un problema con l'implementazione regex di GCC.

File di test completo (compilato con GCC 4.9.2 con -std=c++14):

#include <iostream>
#include <string>
#include <regex>

using namespace std;

int main()
{
    string arr[] = {"1 year 2 months 3 seconds",
                    "-2 day 5 year 8months",
                    "3day 9     years 4 seconds -5 minute 4 years 4 years -3seconds"};
    for_each(begin(arr), end(arr), [](auto&s){sregex_iterator e;auto r="{"s;for(auto&t:{"y","mo","d","h","mi","s"}){int a=0;auto g=regex("-?\\d+ *"s+t);decltype(e)i(begin(s),end(s),g);for_each(i,e,[&](auto&b){a+=stoi(b.str());});r+=to_string(a)+"|";}r.back()='}';s=r;});
    for(auto &s : arr) {cout << s << endl;}
}

Produzione:

{1|2|0|0|0|3}
{5|8|-2|0|0|0}
{17|0|3|0|-5|1}

0

PHP, 141 byte

preg_match_all("#(.?\d+)\s*m?(.)#",$argv[1],$m);$r=[0,0,0,0,0,0];foreach($m[1]as$i=>$n)$r[strpos(yodhis,$m[2][$i])]+=$n;echo json_encode($r);

accetta input dal primo argomento della riga di comando; utilizza [,]per l'output anziché {|}. Corri con -r.

abbattersi

preg_match_all("#(.?\d+)\s*m?(.)#",$argv[1],$m);    # find intervals.
# (The initial dot will match the sign, the space before the number or a first digit.)
$r=[0,0,0,0,0,0];                   # init result
foreach($m[1]as$i=>$n)              # loop through matches
    $r[strpos(yodhis,$m[2][$i])]+=$n;   # map token to result index, increase value
echo json_encode($r);               # print result: "[1,2,3,4,5,6]"
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.