2012-03-19 49 views
18

我正在寻找一个普通的C对应date.jsdate.parse()C库解析大致日期

也就是说,可以理解“一周前”或“昨天”作为输入。只有英文是可以的。

注意:库不应该根据GPL授权,因此Git的date.c或GNU date -d的解析器不会这样做。顺便说一句,如果你想知道为什么我不会坐下来编码这个,去看看提到的库的来源...

+0

对于它的价值,date.js是MIT许可。因此,如果您的目标是获得可以与专有代码链接的内容,那么您必须能够使用date.js作为安全的起点,如果您必须自行推出。尽管JavaScript-to-C重写可能不是在公园散步。 – 2012-03-19 21:39:36

+1

这正是我问这个问题的原因,而不是直接写代码:-) – 2012-03-19 21:57:36

+0

如果您担心编写自己的解析器的源代码复杂性,您可以使用lex/yacc工具吗? – Jerry 2012-03-20 05:19:15

回答

6

以下解决方案并不完全符合您的要求,但我希望尽管不是简单的C答案,它将涵盖您的需求。重新创建轮子不是一种方法,所以我们使用Mozilla JavaScript引擎SpiderMonkey运行C中的date.js。

下面是我做到的。我已经开始下载date.js并将其翻译成date.js.h中定义的名为codeconst char*

(\ 
    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 

然后我以JSAPI's Hello, World!为起点。

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

下面是它在实践中的工作原理。

$ 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 

正如你可以看到它是相当快的,你可以显著增加重用为所有后续调用Date.parse最初创建的背景下其性能。

说到授权问题,date.js可以根据MIT的条款获得,SpiderMonkey可以在MPL 1.1,GPL 2.0或LGPL 2.1下使用。动态链接它满足非GPL要求。

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

+3

嘿,聪明的把戏,谢谢。我认为它甚至适用于我的情况,因为我不需要高性能。如果一个诚实的解决方案弹出,我会离开这个问题开放:-) – 2012-03-24 16:13:07

-1

日期格式是非常可怕的,没有简单的方法做到这一点。 您需要考虑所选语言的日期和月份名称,然后确保您以特定格式接收数据:“dd/mm/yyyy”,“day mon,yyyy”等。另外,正如您所说的,您需要解释一些特定的关键字,因此您需要访问机器上当前的时间戳(日期,时间或日期&时间)。

愿你需要一个用于Linux,我想你可以从这里开始阅读:Convert textual time and date information back

或者你可以简单地标记化你输入的字符串,通过使用一些预定义的分隔符(逗号分割它,斜线,减,空间等),修剪令牌的空间,然后实现一个自动机来处理令牌列表并建立你的日期变量。 确保您为输入日期格式添加了一些限制,并为错误或不兼容的令牌抛出错误。

+0

谢谢,但'getdate'不明白'昨天'等至于如何解析 - 我明白了,但这个问题是关于现有解决方案的。我讨厌自己做这件事,并且遇到了所有的陷阱 - 从现有的GPL编码看,有很多。 – 2012-03-24 07:01:34