近似日期解析的C库

18

我正在寻找一个纯C语言版本的 date.js date.parse() 副本。

也就是说,希望能够理解“一周前”或“昨天”等词汇。仅支持英文也可以。

注意:一个库不应该被授权为GPL,因此Git的date.c或GNU date -d的解析器不适用。顺便提一句,如果你想知道为什么我不能坐下来编写代码,那就去看看上述库的源代码吧...


就此而言,date.js是MIT许可的。因此,如果您的目标是获取可以与专有代码链接的内容,那么如果您必须自己编写代码,您应该能够使用date.js作为安全起点。尽管将JavaScript重写为C可能并不容易。 - Brian McFarland
1
这正是我提出这个问题而不是直接编写代码的原因 :-) - Alexander Gladysh
如果您担心编写自己的解析器的源代码复杂度,那么您可以使用lex/yacc工具吗? - Jerry
1
@Jerry,如果你看一下date -d的源代码,你会发现最复杂的事情不是解析器。 - Alexander Gladysh
一个旧的帖子可能会有所帮助 https://dev59.com/IknSa4cB1Zd3GeqPM1Kn - llj098
2个回答

6
以下解决方案可能不完全符合您的要求,但我希望尽管它不是纯C语言的答案,它仍然可以满足您的需求。重复造轮子并不是一种好方法,所以让我们通过在Mozilla JavaScript引擎SpiderMonkey中运行它来使用C语言中的date.js。
这是我的做法。我首先下载了date.js,并将其翻译成一个名为codeconst char*,定义在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

于是我以JSAPI中的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要求。

简述:git clone https://gist.github.com/2180739.git && cd 2180739 && make && ./parse yesterday


3
聪明的技巧,谢谢。我认为它甚至可以适用于我的情况,因为我不需要高性能。我会保持问题开放,以防一个诚实的解决方案出现 :-)。Translated: 聰明的技巧,謝謝。我認為它甚至適用於我的情況,因為我不需要高性能。我會保持問題開放,以防一個誠實的解決方案出現 :-)。 - Alexander Gladysh

-1

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

希望你需要的是Linux系统,我想你可以从这里开始阅读:将文本时间和日期信息转换回去

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


谢谢,但 getdate 不理解 yesterday 等等。至于如何解析 - 我明白,但这个问题是关于现有解决方案的。我不想自己做并遇到所有陷阱 - 根据现有的 GPL 代码来判断,有很多。 - Alexander Gladysh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接