แปลงช่วงเวลาที่มนุษย์อ่านได้เป็นองค์ประกอบวันที่


16

ท้าทาย

เขียนโปรแกรมที่สั้นที่สุดที่แปลงช่วงเวลาที่มนุษย์อ่านได้เป็นองค์ประกอบวันที่ของแบบฟอร์ม:

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

กรณีตัวอย่าง

แต่ละกรณีทดสอบคือสองบรรทัดอินพุตตามด้วยเอาต์พุต:

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}

กฎระเบียบ

  • คุณไม่สามารถใช้strtotimeหรือฟังก์ชั่นในตัวที่ทำงานได้ทั้งหมด
  • รหัสที่สั้นที่สุดชนะ (ไบต์)
  • คุณสามารถพิมพ์ผลลัพธ์ของคุณไปยังstdoutไฟล์หรือผลลัพธ์ก็สามารถถูกส่งกลับโดยฟังก์ชั่นมันขึ้นอยู่กับคุณ
  • โทเค็นสามารถอยู่ในรูปเอกพจน์หรือพหูพจน์
  • ส่วนประกอบอาจอยู่ในลำดับแบบสุ่ม
  • อาจไม่มีช่องว่างระหว่างหมายเลขและโทเค็น
  • เครื่องหมายเป็นทางเลือกเมื่อช่วงเวลาเป็นค่าบวก (อินพุตและเอาต์พุต)
  • หากส่วนประกอบปรากฏมากกว่าหนึ่งครั้งควรเพิ่มค่า
  • แต่ละองค์ประกอบมีเครื่องหมายของตนเอง
  • ควรจัดการส่วนประกอบแยกต่างหาก (เช่น80 minutesยังคงเป็น 80 ในเอาต์พุต)
  • อินพุตรับประกันว่าเป็นตัวพิมพ์เล็ก

มีความสุขในการเล่นกอล์ฟ!


2
ฉันชอบความท้าทายนี้ แต่ฉันมีช่วงเวลาที่ยากลำบากในการหาอะไรที่ไม่นานและยุ่งเหยิงในภาษาที่ไม่เหมาะสำหรับการเล่นกอล์ฟ : /
Alex A.

รูปแบบผลลัพธ์มีความสำคัญหรือไม่
ติตัส

Sign is optional when the time interval is positiveนั่นหมายความว่าสัญญาณนั้นอาจมี+สัญญาณหรือไม่?
ติตัส

คำตอบ:


3

CJam, 60 ไบต์

หลังจากติดอยู่ในยุค 60 เป็นเวลานานในที่สุดฉันก็สามารถบีบมันลงได้ถึง 60 ไบต์ ดีพอแล้ว! จัดส่ง!

ลองออนไลน์

กรุ:

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

ขยายและแสดงความคิดเห็น:

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

ตอนแรกฉันเริ่มใช้วิธีที่ใช้โทเค็น แต่มันติดแน่นอยู่ที่ ... 61 ไบต์ ถอนหายใจ ดังนั้นฉันจึงเปลี่ยนเกียร์โดยสิ้นเชิงและเปลี่ยนไปใช้วิธีการแสดงตัวละครซึ่งน่าสนใจกว่ามาก

วิธีการวิเคราะห์คำของฉันทำงานโดยการเพิ่มอักขระตัวเลขที่ถูกต้องถึง ( 0- 9และ-) ลงในบัฟเฟอร์และวิเคราะห์บัฟเฟอร์เป็นจำนวนเต็มเมื่อถึงอักขระจากชื่อหน่วยเวลาหนึ่ง ตัวละครเหล่านี้คือy, t, d, h, iและcซึ่งทั้งหมดเป็นไปตามเงื่อนไขที่ปรากฏในชื่อหน่วยเวลาและไม่ปรากฏก่อนอักขระการรับรู้ในชื่อหน่วยเวลาอื่น กล่าวอีกนัยหนึ่งเมื่อถึงหนึ่งในหน่วยการรู้จำเวลาหน่วยเหล่านี้บัฟเฟอร์ตัวเลขจะถูกเติมด้วยหมายเลขสุดท้ายที่เห็นหากนี่เป็นการส่งสัญญาณหน่วยเวลาจริงหรือบัฟเฟอร์ตัวเลขจะว่างเปล่าหากสิ่งนี้เพิ่งปรากฏขึ้น แต่ไม่ควร ' สัญญาณทีบางหน่วยเวลาอื่น ๆ ในกรณีใดกรณีหนึ่งบัฟเฟอร์ตัวเลขจะถูกวิเคราะห์เป็นจำนวนเต็มหรือ 0 ถ้ามันว่างเปล่าและจะถูกเพิ่มเข้าไปในค่าหน่วยเวลาที่สอดคล้องกัน ดังนั้นอักขระการรู้จำที่ปรากฏในหน่วยเวลาอื่นหลังจากอักขระการรู้จำไม่มีผล

แฮ็กบ้าอื่น ๆ ได้แก่ :

  • การใช้ลูปที่ไม่เหมาะสมดังนั้นอักขระตัวเลขจะถูกทิ้งไว้บนสแต็ก (ซึ่งทำหน้าที่เป็นบัฟเฟอร์อักขระตัวเลข) "ฟรี"
  • ทำซ้ำบล็อกศูนย์หรือหลาย ๆ ครั้งแทนที่จะเป็นแบบมีเงื่อนไขเนื่องจากการวนซ้ำนั้นเล็กกว่าคำสั่ง if และการวนซ้ำหลังจากครั้งแรกจะไม่มีผลกระทบ

สำหรับใครที่อยากรู้วิธีแก้ปัญหาโทเค็นของฉันที่ติดที่ 61 ไบต์ฉันจะโพสต์ที่นี่เช่นกัน แม้ว่าฉันจะไม่เคยขยายหรือแสดงความคิดเห็น

CJam, 61 ไบต์

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

+1 สิ่งนี้สมควรได้รับการโหวตมากขึ้น
oopbase

2
@ Forlan07 ขอบคุณสำหรับการสนับสนุน :) แต่ฉันตอบช้าไปหน่อยมันจึงไม่คาดคิด กระบวนการสร้างคำตอบนี้ได้รับความพึงพอใจเพียงพอแล้ว
Runer112

10

Perl: 61 ตัวอักษร

ขอบคุณ @nutki

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

วิ่งตัวอย่าง:

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}

ความพยายามของฉันไม่ดี: 78 77 ตัวอักษร

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
nutki

1
อีก 4 ตัวอักษร:s/-?\d+ *(m.|.)/$$1+=$&/ge;$_="{y|mo|d|h|mi|s}";s/\w+/${$&}+0/ge
nutki

ว้าว. เทคนิคที่ยอดเยี่ยม @ nutki
จัดการ

1
นอกจากนี้ยังพบในโซลูชันอื่น ๆ(m.|.)-> m?(.)บันทึกเพิ่มเติม 4
nutki

Doh กำลังจะลองตอนนี้ ดังนั้นมันใช้งานได้ :)
จัดการ

5

Ruby, 119 106 86 85 84 ไบต์

บันทึกหนึ่งไบต์ด้วย Sp3000

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

นี่คือฟังก์ชันที่ไม่มีชื่อซึ่งรับอินพุตเป็นสตริงและส่งคืนผลลัพธ์ (เช่นเดียวกับสตริง) คุณสามารถทดสอบโดยการกำหนดให้fพูดและเรียกมันว่าชอบ

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

5

Python 2, 99 ไบต์

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

นี่คือฟังก์ชั่นแลมบ์ดาซึ่งรับค่าสตริงและใช้ regex เพื่อแยกตัวเลขที่จำเป็น

ขอบคุณ Martin ที่ชี้ให้เห็นว่า\s*เป็น<space>*ไปได้ มันง่ายที่จะลืมว่า regexes จับคู่ช่องว่างอย่างแท้จริง ...


4

JavaScript 100 105 112

แก้ไขการเพิ่มสตริงเทมเพลต (ใช้งานครั้งแรกธันวาคม 2014 ดังนั้นจึงถูกต้องสำหรับความท้าทายนี้) - ในเวลาที่ฉันไม่ได้ตระหนักถึงพวกเขา

แก้ไขยูเรก้าในที่สุดฉันก็ได้ความหมายm?ในคำตอบอื่น ๆ ทั้งหมด!

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

ทดสอบ

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 ไบต์

ฉันรู้ว่านี่ไม่ใช่การแข่งขัน แต่อย่างใดฉันส่วนใหญ่แค่ต้องการหาวิธีแก้ปัญหาในอาร์ความช่วยเหลือใด ๆ ที่สั้นลงนี้คือการต้อนรับ

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 นี่คือฟังก์ชั่นที่ไม่มีชื่อ หากต้องการเรียกใช้ให้กำหนดfและส่งสตริง

นี่เป็นสิ่งที่ค่อนข้างน่ากลัวดังนั้นลองมาดูเวอร์ชั่นที่ไม่ได้ตีกอล์ฟ

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

จากโครงสร้างเพียงอย่างเดียวมันเป็นเรื่องง่ายที่จะเห็นว่าเกิดอะไรขึ้นแม้ว่าคุณจะไม่คุ้นเคยกับอาร์ฉันก็จะอธิบายรายละเอียดเกี่ยวกับลักษณะของคนแปลกหน้า

paste0() คือวิธีที่ R รวมสตริงโดยไม่มีตัวคั่น

str_extract_all()ฟังก์ชั่นมาจากฮัดลีย์วิกแคมของstringrแพคเกจ การจัดการนิพจน์ปกติในแพ็กเกจฐานทำให้ต้องการได้มากซึ่งเป็นสิ่งที่เข้าstringrมาฟังก์ชันนี้จะคืนค่ารายการของนิพจน์ทั่วไปที่ตรงกันในสตริงอินพุต สังเกตว่า regex ถูกล้อมรอบในฟังก์ชั่น - perl()แค่บอกว่า regex เป็น Perl-style ไม่ใช่ R-style

gsub()จะหาและแทนที่โดยใช้ regex สำหรับแต่ละองค์ประกอบของเวกเตอร์การป้อนข้อมูล ที่นี่เรากำลังบอกให้แทนที่ทุกอย่างที่ไม่ใช่ตัวเลขหรือเครื่องหมายลบด้วยสตริงว่าง

และคุณมีมัน คำอธิบายเพิ่มเติมจะได้รับการยินดีเมื่อมีการร้องขอ


ฉันไม่คิดว่าการแยกสตริงออกจากแพ็คเกจภายนอกเป็นความคิดที่ดี มันเป็นช่องโหว่หรือไม่เมื่อมีการใช้ห้องสมุดที่สนับสนุนชุมชนภายนอก แม้ว่ามันจะเป็นไปได้ทำไมคุณไม่รวมlibrary(stringr)อยู่ในแหล่งที่มาของคุณ?
Andreï Kostyrka

2

งูเห่า - 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 ไบต์

แก้ไข:ลดลง 5 autoไบต์โดยใช้การประกาศแบบเก่าแทน

ฉันรู้ว่าผู้ชนะได้รับการคัดเลือกแล้วและนี่จะเป็นการส่งที่ยาวที่สุดเท่าที่เคยมีมา แต่ฉันเพิ่งโพสต์โซลูชั่น C ++ เพราะฉันพนันว่าไม่มีใครคาดคิดเลย :)

พูดตามตรงฉันมีความสุขมากกับระยะเวลาที่สั้นลง (โดยการวัด C ++ ของหลักสูตร) ​​และฉันแน่ใจว่ามันสั้นกว่านี้ไม่ได้เลย (มีเพียงคำพูดเดียวดูด้านล่าง) . นอกจากนี้ยังเป็นคอลเลกชันที่ค่อนข้างดีของคุณสมบัติใหม่สำหรับ C ++ 11/14

ไม่มีไลบรารีของบุคคลที่สามที่นี่ใช้ไลบรารีมาตรฐานเท่านั้น

การแก้ปัญหาอยู่ในรูปแบบของฟังก์ชั่นแลมบ์ดา:

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

ด้วยเหตุผลบางอย่างฉันต้องเขียน

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

แทนที่จะเป็นเพียงแค่

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

เพราะตัววนซ้ำจะส่งคืนการแข่งขันหนึ่งครั้งถ้าฉันผ่านวัตถุชั่วคราว สิ่งนี้ดูไม่ถูกต้องสำหรับฉันดังนั้นฉันสงสัยว่ามีปัญหากับการใช้งาน regex ของ GCC หรือไม่

ไฟล์ทดสอบเต็มรูปแบบ (รวบรวมด้วย GCC 4.9.2 ด้วย-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;}
}

เอาท์พุท:

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

0

PHP, 141 ไบต์

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

รับอินพุตจากอาร์กิวเมนต์บรรทัดคำสั่งแรก ใช้สำหรับการส่งออกแทน[,] ทำงานด้วย{|}-r

ชำรุด

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]"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.