2012-03-19 9 views
18

Sto cercando una semplice controparte C per date.jsdate.parse().Libreria C per analizzare date approssimative

Cioè qualcosa che capisce "settimana fa" o "ieri" come input. Solo in inglese è OK.

Nota: una libreria non deve essere concessa in licenza in GPL, quindi Git's date.c o parser per GNU date -d non funzionerebbe. A proposito, se ti chiedi perché non dovrei semplicemente sedermi e scrivere il codice, vai a guardare la fonte delle librerie citate ...

+0

Per quel che vale, date.js è concesso in licenza MIT. Quindi se l'obiettivo qui è quello di ottenere qualcosa che puoi collegare con il codice proprietario, dovresti essere in grado di utilizzare date.js come punto di partenza sicuro se devi eseguire il rollover. Anche se una riscrittura javascript-to-C potrebbe non essere una passeggiata nel parco. –

+1

Questo è esattamente il motivo per cui sto facendo questa domanda invece di andare avanti per scrivere il codice :-) –

+0

Se sei preoccupato della complessità della sorgente per scrivere il tuo parser, puoi usare gli strumenti lex/yacc? – Jerry

risposta

6

La seguente soluzione non è esattamente quello che hai chiesto, ma spero che, nonostante non sia una semplice risposta C, coprirà le tue esigenze. Reinventare la ruota non è un modo per andare, quindi usiamo date.js in C eseguendolo con SpiderMonkey, il motore JavaScript di Mozilla.

Ecco come l'ho fatto. Ho iniziato a scaricare date.js e a tradurlo in const char* denominato code definito in date.js.h.

(\ 
    echo 'const char *code =' ; \ 
    curl https://datejs.googlecode.com/files/date.js | \ 
    sed -e 's/\\/\\\\/g; s/"/\\"/g; s/^/"/; s/\r\?$/\\n"/'; \ 
    echo ';' \ 
) > date.js.h 

Quindi ho preso il JSAPI's Hello, World! come punto di partenza.

#include "jsapi.h" 
#include "date.js.h" 

static JSClass global_class = { "global", JSCLASS_GLOBAL_FLAGS, 
    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, 
    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, 
    JSCLASS_NO_OPTIONAL_MEMBERS }; 

void reportError(JSContext *cx, const char *message, JSErrorReport *report) { 
    fprintf(stderr, "%s:%u:%s\n", 
     report->filename ? report->filename : "<no filename>", 
     (unsigned int) report->lineno, message); 
} 

int main(int argc, const char *argv[]) { 
    JSRuntime *rt; 
    JSContext *cx; 
    JSObject *global; 
    rt = JS_NewRuntime(8L * 1024L * 1024L); 
    if (rt == NULL) return 1; 
    cx = JS_NewContext(rt, 8192); 
    if (cx == NULL) return 1; 
    JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_JIT | JSOPTION_METHODJIT); 
    JS_SetVersion(cx, JSVERSION_LATEST); 
    JS_SetErrorReporter(cx, reportError); 
    global = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL); 
    if (global == NULL) return 1; 
    if (!JS_InitStandardClasses(cx, global)) return 1; 

    /* Here's where the interesting stuff is starting to take place. 
    * Begin by evaluating sources of date.js */ 

    jsval out; 
    if (!JS_EvaluateScript(cx, global, code, strlen(code), "code", 1, &out)) 
    return 1; 

    /* Now create a call to Date.parse and evaluate it. The return value should 
    * be a timestamp of a given date. If no errors occur convert the timestamp 
    * to a double and print it. */ 

    const int buflen = 1024; 
    char parse[buflen + 1]; 
    snprintf(parse, buflen, "Date.parse(\"%s\").getTime();", argv[1]); 

    if (!JS_EvaluateScript(cx, global, parse, strlen(parse), "parse", 1, &out)) 
    return 1; 

    double val; 
    JS_ValueToNumber(cx, out, &val); 
    printf("%i\n", (int) (val/1000)); 

    /* Finally, clean everything up. */ 

    JS_DestroyContext(cx); 
    JS_DestroyRuntime(rt); 
    JS_ShutDown(); 
    return 0; 
} 

Ecco come funziona in pratica.

$ time ./parse "week ago" 
1331938800 
0.01user 0.00system 0:00.02elapsed 92%CPU (0avgtext+0avgdata 6168maxresident)k 
0inputs+0outputs (0major+1651minor)pagefaults 0swaps 
$ time ./parse yesterday 
1332457200 
0.01user 0.00system 0:00.02elapsed 84%CPU (0avgtext+0avgdata 6168maxresident)k 
0inputs+0outputs (0major+1653minor)pagefaults 0swaps 

Come si può vedere è abbastanza veloce e si potrebbe aumentare in modo significativo le sue prestazioni riutilizzando contesto inizialmente creata per tutte le chiamate successive a Date.parse.

Parlando di problemi di licenza, date.js è disponibile in base al MIT e SpiderMonkey è disponibile in MPL 1.1, GPL 2.0 o LGPL 2.1. Il collegamento soddisfa in modo dinamico il requisito non GPL.

TL; DR:git clone https://gist.github.com/2180739.git && cd 2180739 && make && ./parse yesterday

+3

Ehi, trucco intelligente, grazie. Penso che funzionerà anche per il mio caso, poiché non ho bisogno di prestazioni elevate. Lascio la domanda aperta nel caso emerga una soluzione onesta :-) –

-1

La formattazione delle date è piuttosto macabra, non c'è un modo semplice per farlo. È necessario tenere conto dei nomi giorno e mese della lingua selezionata, quindi assicurarsi di ricevere i dati in un formato specifico: "gg/mm/aaaa", "giorno lun, gg." E così via. Inoltre, come dici tu, devi interpretare alcune parole chiave specifiche, quindi devi accedere al timestamp corrente (data, ora o data &) sulla macchina.

Sperando è necessario che per Linux, penso che si può iniziare la lettura da qui: Convert textual time and date information back

Oppure si può semplicemente tokenize la stringa di input, suddividendo utilizzando alcuni separatori predefiniti (Virgola, Barra, meno, spazio, ecc .), ritagliare gli spazi dei token e quindi implementare un automa per gestire l'elenco di token e creare la variabile data. Assicurarsi di aggiungere alcune restrizioni per il formato della data di input e generare errori per token errati o incompatibili.

+0

Grazie, ma 'getdate' non capisce' ieri' ecc. Per quanto riguarda come analizzare - Ho capito, ma questa domanda riguarda una soluzione esistente. Odio farlo da solo e colpire tutte le insidie: a giudicare dal codice GPL già esistente ce ne sono molte. –

Problemi correlati