Konversi interval waktu yang dapat dibaca manusia menjadi komponen tanggal

16

Tantangan

Tulis program terpendek yang mengubah interval waktu yang dapat dibaca manusia menjadi komponen-komponen formulir:

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

Contoh kasus

Setiap test case adalah dua baris, input diikuti oleh 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}

Aturan

  • Anda tidak dapat menggunakan strtotimeatau fungsi bawaan yang melakukan seluruh pekerjaan.
  • Kemenangan kode terpendek (byte)
  • Anda dapat mencetak output Anda ke stdoutatau file, hasilnya juga dapat dikembalikan oleh suatu fungsi, terserah Anda
  • Token bisa dalam bentuk tunggal atau jamak.
  • Komponen mungkin dalam urutan acak
  • Mungkin tidak ada spasi putih antara nomor dan token
  • Tanda opsional jika interval waktu positif (input dan output)
  • Jika suatu komponen muncul lebih dari satu kali nilai harus ditambahkan
  • Setiap komponen memiliki tanda tersendiri
  • Komponen-komponen harus ditangani secara terpisah (mis. 80 minutesTetap sebagai 80 dalam output)
  • Masukan dijamin huruf kecil

Selamat Golf!

fpg1503
sumber
2
Saya suka tantangan ini, tetapi saya mengalami kesulitan untuk menghasilkan sesuatu yang tidak panjang dan berantakan dalam bahasa yang tidak cocok untuk kode golf. : /
Alex A.
Apakah format output penting?
Titus
Sign is optional when the time interval is positiveApakah itu berarti bahwa input mungkin mengandung +tanda?
Titus

Jawaban:

3

CJam, 60 byte

Setelah terjebak dalam 60-an untuk waktu yang lama, saya akhirnya berhasil memeras ini hingga 60 byte. Cukup baik! Kirimkan!

Cobalah online

Terjepit:

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

Diperluas dan dikomentari:

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

Saya awalnya mulai menggunakan pendekatan berbasis token, tapi itu cukup macet di ... 61 byte. Mendesah. Jadi saya benar-benar mengubah persneling dan beralih ke pendekatan berbasis karakter ini, yang jauh lebih menarik.

Metode parsing saya berfungsi dengan menambahkan karakter numerik yang valid yang dicapai ( 0- 9dan -) ke buffer dan mengurai buffer sebagai integer ketika karakter tertentu dari salah satu nama unit waktu tercapai. Karakter-karakter yang y, t, d, h, i, danc, yang semuanya memenuhi persyaratan bahwa mereka muncul dalam nama unit waktu dan tidak muncul sebelum karakter pengenalan dalam nama unit waktu lainnya. Dengan kata lain, ketika salah satu karakter pengenalan unit waktu ini tercapai, buffer numerik akan diisi dengan angka terakhir yang terlihat jika ini benar-benar menandakan unit waktu, atau buffer numerik akan kosong jika ini hanya muncul di, tetapi tidak boleh sinyal t, beberapa unit waktu lainnya. Dalam kedua kasus, buffer numerik diuraikan sebagai integer, atau 0 jika kosong, dan ini ditambahkan ke nilai satuan waktu yang sesuai. Jadi karakter pengenalan muncul di unit waktu lain setelah karakter pengenalannya tidak berpengaruh.

Peretasan gila lainnya termasuk:

  • Abusing loop sehingga karakter numerik dibiarkan di tumpukan (yang bertindak sebagai buffer karakter numerik) "gratis."
  • Mengulangi blok nol atau beberapa kali alih-alih secara kondisional karena loop lebih kompak daripada pernyataan if, dan iterasi setelah yang pertama tidak berpengaruh.

Bagi siapa pun yang penasaran dengan solusi berbasis token saya yang macet pada 61 byte, saya akan mempostingnya di sini juga. Saya tidak pernah sempat mengembangkan atau berkomentar.

CJam, 61 byte

'{0a6*q'm-'{,64/~m*{:X/XS**}/S%2/{~0="yodhis"#_3$=@i+t}/'|*'}
Runer112
sumber
+1 Ini pasti layak mendapatkan lebih banyak upvotes.
oopbase
2
@ Forlan07 Terima kasih atas dukungannya. :) Tapi aku agak terlambat untuk menjawab, jadi itu tidak terduga. Proses menghasilkan jawaban ini cukup memuaskan.
Runer112
10

Perl: 61 karakter

Terima kasih kepada @nutki.

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

Contoh dijalankan:

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}

Upaya saya yang buruk: 78 77 karakter

s/([+-]?\d+) *(..)/$a{$2}+=$1/ge;$_="{ye|mo|da|ho|mi|se}";s/\w./$a{$&}||0/ge
manatwork
sumber
1
Beberapa perbaikan yang dapat saya temukan:s/(-?\d+) *(..)/$$2+=$1/ge;$_="{ye|mo|da|ho|mi|se}";s/\w./${$&}+0/ge
nutki
1
4 karakter lainnya:s/-?\d+ *(m.|.)/$$1+=$&/ge;$_="{y|mo|d|h|mi|s}";s/\w+/${$&}+0/ge
nutki
Wow. Trik luar biasa, @nutki.
manatwork
1
Juga ditemukan dalam solusi lain, (m.|.)-> m?(.)hemat ekstra 4.
nutki
Doh. Itu akan dicoba sekarang. Jadi itu berhasil. :)
manatwork
5

Ruby, 119 106 86 85 84 byte

Satu byte disimpan berkat Sp3000.

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

Ini adalah fungsi yang tidak disebutkan namanya, yang mengambil input sebagai string, dan mengembalikan hasilnya (juga sebagai string). Anda dapat mengujinya dengan menugaskan f, mengatakan, dan menyebutnya seperti

f["3day 9     years 4 seconds -5 minute 4 years 4 years -3seconds"]
Martin Ender
sumber
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")

Ini adalah fungsi lambda yang mengambil string dan hanya menggunakan regex untuk mengekstrak angka yang diperlukan.

Terima kasih kepada Martin karena menunjukkan hal itu \s* itu <space>*. Sangat mudah untuk melupakan bahwa regex mencocokkan ruang secara harfiah ...

Sp3000
sumber
4

JavaScript 100 105 112

Edit Menambahkan string template (pertama kali diterapkan pada Desember 2014, sangat valid untuk tantangan ini) - saat itu saya tidak menyadarinya

Sunting Eureka, akhirnya saya mendapatkan makna dari m?semua jawaban lainnya!

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

Uji

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

R, 197 byte

Saya menyadari ini bukan entri kompetitif sama sekali, saya sebagian besar hanya ingin datang dengan solusi di R. Setiap bantuan memperpendek ini tentu saja disambut baik.

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}

Seperti jawaban Martin, ini adalah fungsi yang tidak disebutkan namanya. Untuk memanggilnya, tetapkan ke fdan berikan string.

Ini sangat mengerikan, jadi mari kita lihat versi un-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)
}

Berdasarkan struktur saja mudah untuk melihat apa yang terjadi, bahkan jika Anda tidak terlalu akrab dengan R. Saya akan menguraikan beberapa aspek yang terlihat asing.

paste0() adalah bagaimana R menggabungkan string tanpa pemisah.

The str_extract_all()Fungsi berasal dari Hadley Wickham stringrpaket. Penanganan R ekspresi reguler dalam paket dasar menyisakan banyak yang diinginkan, yang mana stringrmasuk. Fungsi ini mengembalikan daftar kecocokan ekspresi reguler dalam string input. Perhatikan bagaimana regex dikelilingi dalam suatu fungsi perl()- ini hanya mengatakan bahwa regex adalah gaya-Perl, bukan gaya-R.

gsub()melakukan find-and-replace menggunakan regex untuk setiap elemen dari vektor input. Di sini kami mengatakannya untuk mengganti semua yang bukan angka atau tanda minus dengan string kosong.

Dan begitulah. Penjelasan lebih lanjut akan dengan senang hati diberikan atas permintaan.

Alex A.
sumber
Saya tidak berpikir outsourcing ekstraksi string ke paket eksternal adalah ide yang bagus. Bukankah itu celah ketika perpustakaan eksternal yang didukung komunitas digunakan? Meskipun tidak apa-apa, mengapa Anda tidak memasukkan library(stringr)sumber Anda?
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('|')]}'
Suram
sumber
2

C ++ 14, 234 229 byte

Sunting: kurangi 5 byte dengan menggunakan deklarasi gaya lama alih-alihauto.

Saya tahu pemenangnya telah dipilih, dan bahwa ini akan menjadi pengiriman terpanjang sejauh ini, tetapi saya hanya harus memposting solusi C ++, karena saya yakin tidak ada yang mengharapkannya sama sekali :)

Sejujurnya, saya cukup senang dengan betapa singkatnya ternyata (dengan pengukuran C ++, tentu saja), dan saya yakin itu tidak bisa lebih pendek dari ini (hanya dengan satu komentar, lihat di bawah) . Ini juga koleksi yang cukup bagus dari fitur-fitur baru untuk C ++ 11/14.

Tidak ada perpustakaan pihak ketiga di sini, hanya perpustakaan standar yang digunakan.

Solusinya adalah dalam bentuk fungsi 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;};

Tidak Terkumpul:

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

Untuk beberapa alasan, saya harus menulis

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

bukannya adil

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

karena iterator hanya akan mengembalikan satu kecocokan jika saya lulus dalam objek sementara. Ini sepertinya tidak benar bagi saya, jadi saya ingin tahu apakah ada masalah dengan implementasi regex GCC.

File tes lengkap (dikompilasi dengan GCC 4.9.2 dengan -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;}
}

Keluaran:

{1|2|0|0|0|3}
{5|8|-2|0|0|0}
{17|0|3|0|-5|1}
Alexander Revo
sumber
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);

mengambil input dari argumen baris perintah pertama; digunakan [,]untuk output, bukan {|}. Jalankan dengan -r.

kerusakan

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
sumber