我正在尋找一個普通的C對應date.jsdate.parse()
。C庫解析大致日期
也就是說,可以理解「一週前」或「昨天」作爲輸入。只有英文是可以的。
注意:庫不應該根據GPL授權,因此Git的date.c
或GNU date -d
的解析器不會這樣做。順便說一句,如果你想知道爲什麼我不會坐下來編碼這個,去看看提到的庫的來源...
我正在尋找一個普通的C對應date.jsdate.parse()
。C庫解析大致日期
也就是說,可以理解「一週前」或「昨天」作爲輸入。只有英文是可以的。
注意:庫不應該根據GPL授權,因此Git的date.c
或GNU date -d
的解析器不會這樣做。順便說一句,如果你想知道爲什麼我不會坐下來編碼這個,去看看提到的庫的來源...
以下解決方案並不完全符合您的要求,但我希望儘管不是簡單的C答案,它將涵蓋您的需求。重新創建輪子不是一種方法,所以我們使用Mozilla JavaScript引擎SpiderMonkey運行C中的date.js。
下面是我做到的。我已經開始下載date.js並將其翻譯成date.js.h
中定義的名爲code
的const 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
嘿,聰明的把戲,謝謝。我認爲它甚至適用於我的情況,因爲我不需要高性能。如果一個誠實的解決方案彈出,我會離開這個問題開放:-) – 2012-03-24 16:13:07
日期格式是非常可怕的,沒有簡單的方法做到這一點。 您需要考慮所選語言的日期和月份名稱,然後確保您以特定格式接收數據:「dd/mm/yyyy」,「day mon,yyyy」等。另外,正如您所說的,您需要解釋一些特定的關鍵字,因此您需要訪問機器上當前的時間戳(日期,時間或日期&時間)。
願你需要一個用於Linux,我想你可以從這裏開始閱讀:Convert textual time and date information back
或者你可以簡單地標記化你輸入的字符串,通過使用一些預定義的分隔符(逗號分割它,斜線,減,空間等),修剪令牌的空間,然後實現一個自動機來處理令牌列表並建立你的日期變量。 確保您爲輸入日期格式添加了一些限制,併爲錯誤或不兼容的令牌拋出錯誤。
謝謝,但'getdate'不明白'昨天'等至於如何解析 - 我明白了,但這個問題是關於現有解決方案的。我討厭自己做這件事,並且遇到了所有的陷阱 - 從現有的GPL編碼看,有很多。 – 2012-03-24 07:01:34
對於它的價值,date.js是MIT許可。因此,如果您的目標是獲得可以與專有代碼鏈接的內容,那麼您必須能夠使用date.js作爲安全的起點,如果您必須自行推出。儘管JavaScript-to-C重寫可能不是在公園散步。 – 2012-03-19 21:39:36
這正是我問這個問題的原因,而不是直接寫代碼:-) – 2012-03-19 21:57:36
如果您擔心編寫自己的解析器的源代碼複雜性,您可以使用lex/yacc工具嗎? – Jerry 2012-03-20 05:19:15