人間が読める時間間隔を日付コンポーネントに変換する


16

チャレンジ

人間が読める時間間隔をフォームの日付コンポーネントに変換する最短のプログラムを作成します。

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

サンプルケース

各テストケースは2行で、入力の後に出力が続きます。

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
私はこの挑戦が好きですが、コードゴルフには不向きな言語で長くて面倒ではないものを考え出すのに苦労しています。:/
アレックス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および-)をバッファーに追加し、タイムユニット名の1つから特定の文字に到達したときにバッファーを整数として解析することで機能します。これらの文字はytdhi、およびc、これらはすべて、時間単位名に表示され、他の時間単位名の認識文字の前に表示されないという条件を満たします。言い換えると、これらの時間単位認識文字のいずれかに到達すると、これが実際に時間単位を示す場合、数値バッファは最後に表示された数字で埋められます。 t信号、その他の時間単位。どちらの場合でも、数値バッファは整数として解析され、空の場合は0に解析され、これが対応する時間単位の値に追加されます。したがって、認識文字の後に他の時間単位で表示される認識文字は効果がありません。

その他のクレイジーハックには次のものがあります。

  • ループを乱用して、数字を「無料で」スタックに残します(数字バッファーは数字バッファーとして機能します)。
  • ループはifステートメントよりもコンパクトで、最初のブロック以降の反復は効果がないため、ブロックを条件付きではなく0回または複数回繰り返します。

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を節約します。
nutki15年

ど それは今試してみるところだった。それで動作します。:)
マナトワーク

5

ルビー、119 106 86 85 84バイト

Sp3000のおかげで1バイト節約できました。

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

これは、文字列を受け取り、単に正規表現を使用して必要な数を抽出するラムダ関数です。

それを指摘してくれたMartinに感謝し\s*ます<space>*。正規表現がスペースと文字通り一致することを忘れがちです...


4

JavaScript 100105112

編集テンプレート文字列の追加(2014年12月に最初に実装されたため、このチャレンジに有効です)-当時は気づかなかった

編集ユーレカ、ついに私は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バイト

私はこれがまったく競争力のあるエントリではないことを理解しています。私は主にRで解決策を考え出したかっただけです。これを短縮する助けはもちろん歓迎します。

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}

マーティンの答えのように、これは名前のない関数です。呼び出すには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)
}

構造だけに基づいて、Rに精通していなくても、何が起こっているかを簡単に確認できます。見知らぬ人の見た目の側面について詳しく説明します。

paste0() Rが区切り文字なしで文字列を結合する方法です。

このstr_extract_all()関数は、Hadley Wickhamのstringrパッケージからのものです。ベースパッケージ内のRによる正規表現の処理には、多くの要望がありstringrます。それがどこにあるのかです。この関数は、入力文字列に一致する正規表現のリストを返します。正規表現が関数で囲まれていることにperl()注目してください。これは、正規表現がRスタイルではなくPerlスタイルであることを示しているだけです。

gsub()入力ベクトルの各要素に対して正規表現を使用して検索と置換を行います。ここでは、数字またはマイナス記号以外のすべてを空の文字列に置き換えるように指示しています。

そして、あなたはそれを持っています。詳細については、リクエストに応じて喜んで提供します。


文字列抽出を外部パッケージにアウトソーシングすることは良い考えだとは思いません。外部のコミュニティがサポートするライブラリが使用されている場合、抜け穴ではありませんか?大丈夫なのに、どうしてlibrary(stringr)ソースに含めなかったのですか?
アンドレイ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 ++の測定によって)に非常に満足しており、これよりも短くなることはないと確信しています(1つの発言で、以下を参照してください) 。また、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;};

ゴルフをしていない:

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

なぜなら、一時オブジェクトを渡すと、反復子は1つの一致だけを返すからです。これは私には正しくないと思われるので、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.