如何扩展 EJSON 以序列化 RegEx 以进行 Meteor 客户端-服务器交互?

Posted

技术标签:

【中文标题】如何扩展 EJSON 以序列化 RegEx 以进行 Meteor 客户端-服务器交互?【英文标题】:How to extend EJSON to serialize RegEx for Meteor Client-Server interactions? 【发布时间】:2016-06-03 15:11:35 【问题描述】:

我有一个任意的 (E)JSON,它在我的 Meteor 应用程序中创建并通过线路从客户端发送到服务器。它使用RegExp 对象将结果归零:

# on the client
selector = 
  "roles.user":  "$ne": null  
  "profile.email": /^admin@/gi 

在客户端一切都很好,但是如果我通过Meteor.callMeteor.subscribe 将其传递给服务器,则生成的 (E)JSON 采用以下形式:

# on the server
selector =
  "roles.user":  "$ne": null 
  "profile.email": 

...在某个地方,一位工程师在内心深处死去。

网上有很多资源可以解释为什么 RegEx 无法通过 JSON.stringify/JSON.parse 或等效的 EJSON 方法进行序列化。

我不相信 RegEx 序列化是不可能的。那么怎么做呢?

【问题讨论】:

【参考方案1】:

查看this HowTo和the Meteor EJSON Docs后,我们可以使用EJSON.addType方法序列化RegEx。

Extend RegExp - 为 RegExp 提供 EJSON.addType 实现所需的方法。

RegExp::options = ->
  opts = []
  opts.push 'g' if @global
  opts.push 'i' if @ignoreCase
  opts.push 'm' if @multiline
  return opts.join('')

RegExp::clone = ->
  self = @
  return new RegExp(self.source, self.options())

RegExp::equals = (other) ->
  self = @
  if other isnt instanceOf RegExp
    return false
  return EJSON.stringify(self) is EJSON.stringify(other)

RegExp::typeName = ->
  return "RegExp"

RegExp::toJSONValue = ->
  self = @
  return 
    'regex': self.source
    'options': self.options()
  

调用 EJSON.addType - 在任何地方执行此操作。最好让它对客户端和服务器可用。这将反序列化上面toJSONValue 中定义的对象。

EJSON.addType "RegExp", (value) ->
  return new RegExp(value['regex'], value['options'])

在您的控制台中测试 - 不要相信我的话。自己看吧。

> o = EJSON.stringify(/^Mooo/ig)
""$type":"RegExp","$value":"regex":"^Mooo","options":"ig""
> EJSON.parse(o)
/^Mooo/gi

你有一个正则表达式在客户端和服务器上被序列化和解析,能够通过网络传递,保存在会话中,甚至可能存储在查询集合中!

编辑添加 IE10+ 错误:在严格模式下不允许分配给只读属性由 cmets 中的 @Tim Fletcher 提供

import  EJSON  from 'meteor/ejson';

function getOptions(self) 
  const opts = [];
  if (self.global) opts.push('g');
  if (self.ignoreCase) opts.push('i');
  if (self.multiline) opts.push('m');
  return opts.join('');


RegExp.prototype.clone = function clone() 
  return new RegExp(this.source, getOptions(this));
;

RegExp.prototype.equals = function equals(other) 
  if (!(other instanceof RegExp)) return false;
  return EJSON.stringify(this) === EJSON.stringify(other);
;

RegExp.prototype.typeName = function typeName() 
  return 'RegExp';
;

RegExp.prototype.toJSONValue = function toJSONValue() 
  return  regex: this.source, options: getOptions(this) ;
;

EJSON.addType('RegExp', value => new RegExp(value.regex, value.options));

【讨论】:

感谢您的回答。这在 Chrome 中确实很有效,但在 IE 10+ 中使用 Assignment to read-only properties is not allowed in strict mode 杀死了 Meteor。我用这个版本(ES6)修复了它gist.github.com/TimFletcher/1fc43b36a2710f09895613ecdd7c39a7【参考方案2】:

有一个更简单的解决方案: 通过.toString() 对您的正则表达式进行字符串化,将其发送到服务器,然后将其解析回正则表达式。

【讨论】:

以上是关于如何扩展 EJSON 以序列化 RegEx 以进行 Meteor 客户端-服务器交互?的主要内容,如果未能解决你的问题,请参考以下文章

如何以编程方式处理英文缩写 [Regex, JS, Ruby]

如何使用 RegEx 检查表单输入是不是以 .pdf 结尾

R中可扩展的结转以创建每日时间序列

使用 Linq 和 Regex 比较 2 个字符串数组以进行部分匹配

如何在 Excel 中创建函数以使用 RegEx 验证单元格

Python RegEx