2012-03-19 16 views
18

Estoy buscando una contraparte en C simple para date.jsdate.parse().C biblioteca para analizar fechas aproximadas

Es decir, algo que entiende "semana atrás" o "ayer" como entrada. Solo en inglés está bien.

Nota: una biblioteca no debe tener licencia bajo licencia GPL, por lo que no es suficiente con date.c ni con el analizador date -d de Git. Por cierto, si se pregunta por qué no me voy a sentar y codificar esto, vaya a ver el origen de las bibliotecas mencionadas ...

+0

Por lo que vale la pena, date.js tiene licencia MIT. Entonces, si el objetivo aquí es obtener algo que pueda vincular con el código de propiedad, debería poder usar date.js como un punto de partida seguro si tiene que implementar el suyo propio. Aunque una reescritura javascript-to-C podría no ser una caminata en el parque. –

+1

Es exactamente por eso que hago esta pregunta en lugar de seguir adelante para escribir el código :-) –

+0

Si le preocupa la complejidad de la fuente para escribir su propio analizador, ¿puede usar las herramientas lex/yacc? – Jerry

Respuesta

6

La siguiente solución no es exactamente lo que ha pedido, pero espero que a pesar de no ser una simple respuesta C cubra sus necesidades. Reinventar la rueda no es un camino por recorrer, así que usemos date.js en C ejecutándolo con SpiderMonkey, el motor de JavaScript de Mozilla.

Así es como lo hice. Empecé descargando date.js y traduciéndolo a const char* llamado code definido en 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 

Luego tomé el JSAPI's Hello, World! como punto de partida.

#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; 
} 

Así es como funciona en la práctica.

$ 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 

Como se puede ver que es bastante rápido y que podría aumentar significativamente su rendimiento mediante la reutilización del contexto creado inicialmente para todas las llamadas posteriores a Date.parse.

Hablando de problemas de licencia, date.js está disponible bajo los términos de MIT y SpiderMonkey está disponible bajo MPL 1.1, GPL 2.0 o LGPL 2.1. Vincularlo dinámicamente satisface el requisito de no GPL.

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

+3

Oye, astuto truco, gracias. Creo que incluso funcionará para mi caso, ya que no necesito un alto rendimiento. Dejo la pregunta abierta en caso de que aparezca una solución honesta :-) –

-1

El formato de fecha es bastante horrible, no hay una manera fácil de hacerlo. Debe tener en cuenta los nombres de días y meses del idioma seleccionado, luego asegúrese de recibir los datos en un formato específico: "dd/mm/aaaa", "día lun, aaaa", etc. Además, como dices, debes interpretar algunas palabras clave específicas, por lo que necesitas acceder a la marca de tiempo actual (fecha, hora o fecha &) en la máquina.

Con la esperanza de que necesita que para Linux, creo que se puede comenzar a leer desde aquí: Convert textual time and date information back

O puede simplemente tokenize su cadena de entrada, mediante su división mediante unos separadores predefinidos (coma, raya vertical, menos, el espacio, etc. .), recortar los espacios de los tokens, y luego implementar un autómata para manejar la lista de tokens y construir su variable de fecha. Asegúrese de agregar algunas restricciones para el formato de fecha de entrada y lanzar errores para tokens incorrectos o incompatibles.

+0

Gracias, pero 'getdate' no entiende' ayer', etc. En cuanto a cómo analizar - Lo entiendo, pero esta pregunta es sobre una solución existente. Odiaría hacerlo yo mismo y golpear todas las trampas: a juzgar por el código existente GPLed, hay muchas. –

Cuestiones relacionadas