Convertir l'intervalle de temps lisible par l'homme en composants de date

16

Défi

Écrivez le programme le plus court qui convertit un intervalle de temps lisible par l'homme pour dater les composants du formulaire:

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

Exemples de cas

Chaque scénario de test est composé de deux lignes, entrée suivie d'une sortie:

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}

Règles

  • Vous ne pouvez pas utiliser strtotimeou toute fonction intégrée qui fait tout le travail.
  • Victoires de code les plus courtes (octets)
  • Vous pouvez imprimer votre sortie stdoutou un fichier, le résultat peut également être retourné par une fonction, c'est à vous
  • Le jeton peut être au singulier ou au pluriel.
  • Les composants peuvent être dans un ordre aléatoire
  • Il ne doit pas y avoir d'espace blanc entre le numéro et le jeton
  • Le signe est facultatif lorsque l'intervalle de temps est positif (entrée et sortie)
  • Si un composant apparaît plus d'une fois, les valeurs doivent être ajoutées
  • Chaque composant a son propre signe
  • Les composants doivent être traités séparément (par exemple, 80 minutesreste égal à 80 dans la sortie)
  • L'entrée est garantie en minuscules

Bon golf!

fpg1503
la source
2
J'aime ce défi, mais j'ai du mal à trouver quoi que ce soit qui ne soit pas long et désordonné dans des langues qui ne conviennent pas au golf de code. : /
Alex A.
Le format de sortie est-il important?
Titus
Sign is optional when the time interval is positiveEst-ce à dire que l'entrée peut contenir des +signes?
Titus

Réponses:

3

CJam, 60 octets

Après avoir été coincé dans les années 60 pendant longtemps, j'ai finalement réussi à le réduire à 60 octets. Assez bien! Expédier!

Essayez-le en ligne

Écrasé:

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

Développé et commenté:

'{              "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";

J'ai d'abord commencé à utiliser une approche basée sur des jetons, mais celle-ci est restée assez fermement bloquée à ... 61 octets. Soupir. J'ai donc totalement changé de vitesse et suis passé à cette approche basée sur les personnages, qui est de toute façon beaucoup plus intéressante.

Ma méthode d'analyse fonctionne en ajoutant tous les caractères numériques valides atteints ( 0- 9et -) à un tampon et en analysant le tampon comme un entier lorsqu'un certain caractère de l'un des noms d'unité de temps est atteint. Ces personnages sont y, t, d, h, ietc, qui remplissent tous les conditions d'apparition dans un nom d'unité de temps et n'apparaissent pas avant le caractère de reconnaissance dans un autre nom d'unité de temps. En d'autres termes, lorsque l'un de ces caractères de reconnaissance d'unité de temps est atteint, le tampon numérique sera rempli avec le dernier chiffre vu si cela signale réellement une unité de temps, ou le tampon numérique sera vide si cela n'apparaît que dans, mais ne devrait pas signal t, une autre unité de temps. Dans les deux cas, le tampon numérique est analysé comme un entier, ou 0 s'il était vide, et cela est ajouté à la valeur d'unité de temps correspondante. Ainsi, les caractères de reconnaissance apparaissant dans d'autres unités de temps après leur caractère de reconnaissance n'ont aucun effet.

D'autres hacks fous incluent:

  • Abuser des boucles pour laisser des caractères numériques sur la pile (qui agit comme tampon de caractères numériques) "gratuitement".
  • Répéter un bloc zéro ou plusieurs fois au lieu de conditionnellement car la boucle est plus compacte qu'une instruction if et les itérations après la première n'ont aucun effet.

Pour toute personne curieuse de ma solution basée sur des jetons qui s'est bloquée à 61 octets, je la publierai ici également. Cependant, je n'ai jamais réussi à l'étendre ou à le commenter.

CJam, 61 octets

'{0a6*q'm-'{,64/~m*{:X/XS**}/S%2/{~0="yodhis"#_3$=@i+t}/'|*'}
Runer112
la source
+1 Cela mérite certainement plus de votes positifs.
oopbase
2
@ Forlan07 Merci pour le soutien. :) Mais j'étais un peu en retard pour répondre, donc ce n'est pas inattendu. Le processus de production de cette réponse était de toute façon assez satisfaisant.
Runer112
10

Perl: 61 caractères

Merci à @nutki.

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

Exemple d'exécution:

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}

Mes pauvres efforts: 78 77 caractères

s/([+-]?\d+) *(..)/$a{$2}+=$1/ge;$_="{ye|mo|da|ho|mi|se}";s/\w./$a{$&}||0/ge
homme au travail
la source
1
Quelques améliorations que j'ai pu trouver:s/(-?\d+) *(..)/$$2+=$1/ge;$_="{ye|mo|da|ho|mi|se}";s/\w./${$&}+0/ge
nutki
1
4 autres caractères:s/-?\d+ *(m.|.)/$$1+=$&/ge;$_="{y|mo|d|h|mi|s}";s/\w+/${$&}+0/ge
nutki
Sensationnel. Grands tours, @nutki.
manatwork
1
Également trouvé dans d'autres solutions, (m.|.)-> m?(.)économise 4 supplémentaires.
nutki
Doh. C'était sur le point d'essayer maintenant. Donc ça marche. :)
manatwork
5

Ruby, 119 106 86 85 84 octets

Un octet enregistré grâce au Sp3000.

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

Il s'agit d'une fonction sans nom, qui prend l'entrée sous forme de chaîne et renvoie le résultat (également sous forme de chaîne). Vous pouvez le tester en l'affectant f, disons et en l'appelant comme

f["3day 9     years 4 seconds -5 minute 4 years 4 years -3seconds"]
Martin Ender
la source
5

Python 2, 99 octets

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

Il s'agit d'une fonction lambda qui prend une chaîne et utilise simplement une expression régulière pour extraire les nombres nécessaires.

Merci à Martin d'avoir souligné que cela \s*pourrait être le cas <space>*. Il est facile d'oublier que les expressions rationnelles correspondent littéralement aux espaces ...

Sp3000
la source
4

JavaScript 100105112

Modifier l' ajout de chaînes de modèle (mis en œuvre pour la première fois en décembre 2014, donc valable pour ce défi) - à l'époque, je ne les connaissais pas

Edit Eureka, j'ai enfin compris le sens de m?toutes les autres réponses!

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

Tester

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

edc65
la source
3

R, 197 octets

Je me rends compte que ce n'est pas une entrée compétitive du tout, je voulais surtout trouver une solution dans R. Toute aide raccourcissant cela est bien sûr la bienvenue.

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}

Comme la réponse de Martin, il s'agit d'une fonction sans nom. Pour l'appeler, affectez-le fet passez une chaîne.

C'est assez hideux, alors jetons un coup d'œil à une version non golfée.

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

Sur la seule base de la structure, il est facile de voir ce qui se passe, même si vous n'êtes pas trop familier avec R. Je développerai certains aspects d'aspect étranger.

paste0() est la façon dont R combine les chaînes sans séparateur.

La str_extract_all()fonction provient du stringrpackage de Hadley Wickham . La gestion par R des expressions régulières dans le package de base laisse beaucoup à désirer, c'est là stringrqu'intervient. Cette fonction renvoie une liste de correspondances d'expressions régulières dans la chaîne d'entrée. Remarquez comment le regex est entouré dans une fonction perl()- c'est juste dire que le regex est de style Perl, pas de style R.

gsub()effectue une recherche et un remplacement à l'aide d'une expression régulière pour chaque élément du vecteur d'entrée. Ici, nous lui disons de remplacer tout ce qui n'est pas un nombre ou un signe moins par une chaîne vide.

Et voila. De plus amples explications seront fournies avec plaisir sur demande.

Alex A.
la source
Je ne pense pas que l'externalisation de l'extraction de chaînes vers un package externe soit une bonne idée. N'est-ce pas une faille lorsqu'une bibliothèque externe prise en charge par la communauté est utilisée? Même si c'est OK, pourquoi n'avez-vous pas inclus library(stringr)dans votre source?
Andreï Kostyrka
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('|')]}'
Οurous
la source
2

C ++ 14, 234 229 octets

Edit: réduisez 5 octets en utilisant l'ancienne déclaration de style au lieu deauto.

Je sais que le gagnant a déjà été choisi et que ce sera la soumission la plus longue jusqu'à présent, mais je viens de publier une solution C ++, car je parie que personne ne s'y attendait du tout :)

Pour être honnête, je suis assez satisfait de la brièveté du résultat (par des mesures C ++, bien sûr), et je suis sûr qu'il ne peut pas être plus court que cela (avec une seule remarque, voir ci-dessous) . C'est aussi une belle collection de fonctionnalités nouvelles pour C ++ 11/14.

Pas de bibliothèques tierces ici, seule la bibliothèque standard est utilisée.

La solution se présente sous une forme de fonction 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;};

Non golfé:

[](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;
}

Pour une raison quelconque, j'ai dû écrire

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

au lieu de juste

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

parce que l'itérateur ne retournerait qu'une seule correspondance si je passe un objet temporaire. Cela ne me semble pas juste, donc je me demande s'il y a un problème avec la mise en œuvre des expressions régulières de GCC.

Fichier de test complet (compilé avec GCC 4.9.2 avec -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;}
}

Production:

{1|2|0|0|0|3}
{5|8|-2|0|0|0}
{17|0|3|0|-5|1}
Alexander Revo
la source
0

PHP, 141 octets

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

prend l'entrée du premier argument de la ligne de commande; utilise [,]pour la sortie au lieu de {|}. Courez avec -r.

panne

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]"
Titus
la source