İnsan tarafından okunabilir zaman aralığını tarih bileşenlerine dönüştürme


16

Meydan okuma

İnsan tarafından okunabilir bir zaman aralığını formun tarih bileşenlerine dönüştüren en kısa programı yazın:

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

Örnek vakalar

Her test durumu iki satırdan oluşur, giriş ve ardından çıkış:

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}

kurallar

  • strtotimeTüm işi yapan herhangi bir yerleşik işlevi kullanamazsınız .
  • En kısa kod kazanır (bayt)
  • Çıktınızı stdoutveya bir dosyaya yazdırabilirsiniz , sonuç bir işlevle de döndürülebilir, size kalmış
  • Jeton tekil veya çoğul biçimde olabilir.
  • Bileşenler rastgele sırada olabilir
  • Sayı ve belirteç arasında beyaz boşluk olmayabilir
  • Zaman aralığı pozitif olduğunda (giriş ve çıkış) işaret isteğe bağlıdır
  • Bir bileşen birden çok kez görünüyorsa değerler eklenmelidir
  • Her bileşenin kendi işareti vardır
  • Bileşenler ayrı ayrı ele alınmalıdır (örneğin 80 minutesçıktıda 80 olarak kalır)
  • Girişin küçük harf olacağı garanti edilir

Mutlu Golf!


2
Ben bu meydan okuma gibi ama kod golf için uygun olmayan dillerde uzun ve dağınık olmayan bir şey geliyor zor bir zaman yaşıyorum. : /
Alex A.

Çıktı formatı önemli mi?
Titus

Sign is optional when the time interval is positiveBu, girdinin +işaret içerebileceği anlamına mı geliyor ?
Titus

Yanıtlar:


3

CJam, 60 bayt

60'larda uzun süre sıkıştıktan sonra, sonunda bunu 60 bayta kadar sıkıştırmayı başardım. Yeterince iyi! Onu yükle!

Çevrimiçi deneyin

ezilmiş:

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

Genişletilmiş ve yorum yapılan:

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

Başlangıçta token tabanlı bir yaklaşım kullanmaya başladım, ancak bu ... 61 baytta oldukça sıkı bir şekilde sıkıştı. İç çekmek. Bu yüzden vitesleri tamamen değiştirdim ve bu karakter temelli yaklaşıma geçtim, ki bu zaten çok daha ilginç.

Ayrıştırma yöntemim , bir ara belleğe ulaşılan geçerli sayısal karakterleri ( 0- 9ve -) ekleyerek ve zaman birimi adlarından birinden belirli bir karaktere ulaşıldığında arabelleği bir tamsayı olarak ayrıştırmak suretiyle çalışır. Bunlar karakterler y, t, d, h, i, vecbunların tümü, bir zaman birimi adında göründükleri ve başka bir zaman birimi adında tanıma karakterinden önce görünmeyen koşulları karşılar. Başka bir deyişle, bu zaman birimi tanıma karakterlerinden birine ulaşıldığında, sayısal arabellek aslında bir zaman birimini işaret ediyorsa en son görülen sayıyla doldurulur veya sayısal arabellek sadece görünüyorsa görünür, ancak ' t sinyali, başka bir zaman birimi. Her iki durumda da, sayısal tampon bir tamsayı olarak ayrılır veya boşsa 0 olur ve bu karşılık gelen zaman birimi değerine eklenir. Dolayısıyla, tanıma karakterlerinden sonra diğer zaman birimlerinde görünen tanıma karakterlerinin bir etkisi yoktur.

Diğer çılgın saldırılar şunları içerir:

  • İstismar döngüleri, sayısal karakterler yığın üzerinde bırakılır (sayısal karakter arabelleği görevi görür) "ücretsiz."
  • Döngü bir if ifadesinden daha kompakt olduğundan ve ilkinden sonraki yinelemelerin bir etkisi olmadığı için koşullu yerine sıfır veya birden çok kez yinelenmesi.

61 baytta takılan token tabanlı çözümümü merak eden herkes için buraya da gönderirim. Yine de, onu genişletmeye veya yorum yapmaya hiç uğraşmadım.

CJam, 61 bayt

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

+1 Bu kesinlikle daha fazla oyu hak ediyor.
oopbase

2
@ Forlan07 Destek için teşekkürler. :) Ama cevap vermek için biraz geç kaldım, bu yüzden beklenmedik değil. Bu cevabı üretme süreci zaten yeterince tatmin ediciydi.
Run1112

10

Perl: 61 karakter

@Nutki için teşekkürler.

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

Örnek çalışma:

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}

Kötü çabalarım: 78 77 karakter

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

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

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

Vay. Harika numaralar, @nutki.
manatwork

1
Diğer çözümlerde de bulunur, (m.|.)-> m?(.)ekstra 4 kaydeder.
nutki

Hamuru. Şimdi denemek üzereydi. Yani işe yarıyor. :)
manatwork

5

Yakut, 119 106 86 85 84 bayt

Sp3000 sayesinde bir bayt kurtarıldı.

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

Bu, girdiyi dize olarak alan ve sonucu döndüren (ayrıca bir dize olarak) adsız bir işlevdir. fSöyle ve söyleyerek ve aşağıdaki gibi çağırarak test edebilirsiniz.

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

5

Python 2, 99 bayt

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

Bu, bir dizeyi alan ve gerekli sayıları çıkarmak için bir normal ifade kullanan bir lambda işlevidir.

Bunun \s*olabileceğine işaret ettiği için Martin'e teşekkürler <space>*. Normal ifadelerin tam anlamıyla boşluklarla eşleştiğini unutmak kolaydır ...


4

JavaScript 100105112

Düzenleme Şablon dizeleri ekleme (ilk olarak Aralık 2014'te uygulandı, bu meydan okuma için çok geçerli) - bunların farkında değildim

Düzen Eureka, son I'de anlamını got m?diğer tüm yanıtlar!

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

Ölçek

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 bayt

Bunun rekabetçi bir giriş olmadığının farkındayım, çoğunlukla sadece R'de bir çözüm bulmak istedim.

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}

Martin'in cevabı gibi, bu isimsiz bir fonksiyondur. Onu aramak için, fdizeye atayın ve bir dizeyi iletin.

Bu oldukça iğrenç, bu yüzden golf oynamayan bir versiyona bakalım.

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

Sadece yapıya dayanarak, neler olduğunu görmek kolaydır, R'ye çok aşina olmasanız bile, yabancı görünümlü bazı yönleri ayrıntılı olarak açıklayacağım.

paste0() R, dizeleri ayırıcı olmadan nasıl birleştirir.

str_extract_all()Fonksiyon Hadley Wickham'ın gelen stringrpaketin. R'nin temel paketteki normal ifadeleri işlemesi, istenen çok şey bırakıyor, bu da devreye stringrgiriyor. Bu işlev, giriş dizesindeki normal ifade eşleşmelerinin bir listesini döndürür. perl()Normal ifadenin bir fonksiyonda nasıl çevrildiğine dikkat edin - bu sadece normal ifadenin R tarzı değil Perl tarzı olduğunu söylüyor.

gsub()girdi vektörünün her elemanı için bir regex kullanarak bir bul-değiştir yapar. Burada sayı veya eksi işareti olmayan her şeyi boş bir dize ile değiştirmesini söylüyoruz.

İşte buyur. Talep üzerine daha fazla açıklama memnuniyetle sağlanacaktır.


Dış bir pakete dize çıkarma dış kaynak kullanımı iyi bir fikir olduğunu sanmıyorum. Topluluk tarafından desteklenen harici bir kitaplık kullanıldığında boşluk olmaz mı? Tamam olsa bile, neden library(stringr)kaynağınıza dahil etmediniz?
Andreï Kostyrka

2

Kobra - 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 bayt

Düzenleme: yerine eski stil bildirimi kullanarak 5 bayt kesinauto.

Kazanın zaten seçildiğini biliyorum ve bu şimdiye kadarki en uzun sunum olacaktı, ama sadece bir C ++ çözümü yayınlamak zorunda kaldım, çünkü hiç kimsenin beklemediğinden eminim :)

Dürüst olmak gerekirse, ne kadar kısa olduğu konusunda oldukça mutluyum (elbette C ++ ölçümleriyle) ve bunun daha kısa bir süre elde edemeyeceğinden eminim (sadece bir açıklama ile aşağıya bakın) . Ayrıca C ++ 11/14 için yeni özelliklerin oldukça güzel bir koleksiyonudur.

Burada hiçbir üçüncü taraf kütüphanesi yok, sadece standart kütüphane kullanılıyor.

Çözüm lambda fonksiyonu biçimindedir:

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

Nedense yazmak zorunda kaldım

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

sadece yerine

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

çünkü yineleyici geçici bir nesneden geçersem yalnızca bir eşleşme döndürür. Bu benim için doğru görünmüyor, bu yüzden GCC'nin normal ifade uygulamasında bir sorun olup olmadığını merak ediyorum.

Tam test dosyası (GCC 4.9.2 ile derlenmiştir -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;}
}

Çıktı:

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

0

PHP, 141 bayt

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

ilk komut satırı bağımsız değişkeninden girdi alır; [,]yerine çıktı için kullanır {|}. İle çalıştırın -r.

Yıkmak

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]"
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.