RegExp的序列化

Posted

技术标签:

【中文标题】RegExp的序列化【英文标题】:Serialization of RegExp 【发布时间】:2012-08-18 01:00:36 【问题描述】:

所以,我很感兴趣地发现 JSON.stringify 将 RegExp 简化为空的对象文字 (fiddle):

JSON.stringify(/^[0-9]+$/) // ""

这是预期的行为吗?我意识到 RegExp 是一个没有要序列化的属性的对象。也就是说,日期也是对象。然而JSON.stringify() 设法产生了一个有意义的字符串:

JSON.stringify(new Date) // "2014-07-03T13:42:47.905Z"

我希望 JSON 能够通过使用 RegExp.prototype.@987654322@ 给予 RegExp 相同的考虑。

【问题讨论】:

您应该将其转换为字符串并稍后使用RegExp 对象进行反序列化 @shiplu.mokadd.im 我并不是真的在寻找解决方法。手动序列化正则表达式很容易。 是的,我知道。这就是为什么我没有回答而是发表评论。 @canon 真正的问题是正则表达式对象没有字符串、数字和布尔值那样的通用性。 JSON 是一种数据交换格式,因此 JSON 可以在尽可能多的语言环境中使用非常重要。将 RegExp 实例反序列化为具有明显不同的正则表达式机制(或没有这种机制)的语言将是有问题的。 【参考方案1】:

是的,因为 JSON 中没有 RegExp 对象的规范表示。因此,它只是一个空对象。

edit——现在是 2018 年了;建议使用.toJSON() 等解决方案的答案可能很好,尽管我会将该方法添加到原型中

Object.defineProperty(RegExp.prototype, "toJSON", 
  value: RegExp.prototype.toString
);

等等。这确保了函数名称不可枚举,这使得猴子补丁更加卫生。

【讨论】:

我认为,由于它已经在 javascript 中具有文字表示,因此可以很好地转换为 JSON;我想不会。 是的 - 它是一个没有属性的对象,这就是 JSON 可以看到的所有内容。我猜你可以把它转换成一个字符串,但它仍然不是一个真正的 RegExp 实例。 显然这是一个错误。 @tenbits 响应应该是答案。 @tgoneil 这不是一个“错误”; JSON 规范根本不包括作为原始值类型的正则表达式。它也不包括日期和其他各种东西。【参考方案2】:

如果有人感兴趣,有一个很好的解决方法。我不认为,当前的行为是正确的。例如,Date 实例不会像RegExp 那样序列化为空对象,尽管它是object 并且也没有 JSON 表示形式。

RegExp.prototype.toJSON = RegExp.prototype.toString;


// sample
var foo =  rgx: /qux$/ig, date: new Date 

JSON.stringify(foo);
//> "rgx":"/qux$/gi","date":"2014-03-21T23:11:33.749Z""

【讨论】:

很好,我不知道toJSON() @matthoiland,我总是使用它,但我不知道任何实际用例,当它不能使用或导致未定义的行为时。但正如你所见,它扩展了 RegExp 的原型虽然你可以通过 Object.defineProperty 扩展它以使其不可枚举(但你是否曾经迭代过 regexp 实例?);它还改变了默认的 JSON 行为,所以这个主题可能是推测性的,但根据我的经验,我发现这种方法和这种行为是正确的。 我认为他们应该对此进行标准化。将其作为 JSON 解析器/字符串化器的默认行为会很有意义。 @goofballLogic,你不能这样做:new RegExp(x.toString()),因为toString 创建了正则表达式文字符号,它有尾部正斜杠,并且也以正斜杠结尾,可选地后跟正则表达式标志: /REGEXP_STRING/FLAGS。所以new RegExp("foo", "i").toString() 产生:“/foo/i”字符串。考虑我的编辑:gist.github.com/tenbits/ec7f0155b57b2d61a6cc90ef3d5f8b49 @tenbits,是的。我将避免使用这种模式,因为人们无疑会错误地假设该字符串可以被 RegExp 构造函数使用。【参考方案3】:
RegExp.prototype.toJSON = RegExp.prototype.toString;

var regexp = /^[0-9]+$/;
var foo =  rgx: regexp.source, date: new Date ;
var stringified = JSON.stringify(foo);
new RegExp(JSON.parse(stringified).rgx)

【讨论】:

我的示例与上面的示例不同,因为使用我的示例,您可以使用 JSON.stringify/parse 序列化/反序列化并获得相同的正则表达式结果。 您可以通过 toString 方法中的 toString 源来改进这一点。 RegExp.prototype.toJSON = function() return this.source.toString(); ; 你甚至没有使用你分配的原型方法 @HutchMoore 试试JSON.stringify( rgx: regexp ); @Sagi 你在它上面明确地调用了.source,它返回了一个搅拌。我就是这么说的【参考方案4】:

JSON.stringify 和 JSON.parse 都可以通过使用 replacer 和 reviver 参数进行自定义序列化和反序列化。

var o = 
  foo: "bar",
  re: /foo/gi
;

function replacer(key, value) 
  if (value instanceof RegExp)
    return ("__REGEXP " + value.toString());
  else
    return value;


function reviver(key, value) 
  if (value.toString().indexOf("__REGEXP ") == 0) 
    var m = value.split("__REGEXP ")[1].match(/\/(.*)\/(.*)?/);
    return new RegExp(m[1], m[2] || "");
   else
    return value;


console.log(JSON.parse(JSON.stringify(o, replacer, 2), reviver));

你只需要想出你自己的序列化格式。

【讨论】:

很好,我觉得可能有一个 js 库只是用于序列化/反序列化正则表达式。 做 reClone = eval(re.toString()) 更短,更容易理解(并且有效)。我不是说你应该这样做,我是在问一个问题。有谁知道eval 方法比这里使用的方法慢吗? 有你可以使用的 npm lib npmjs.com/package/serialize-javascript【参考方案5】:

我是这样解决这个问题的:

将其序列化为字符串:

var pattern = /foobar/i;
var serialized = JSON.stringify(pattern.toString());

然后使用另一个正则表达式对其进行补水:

var fragments = serialized.match(/\/(.*?)\/([a-z]*)?$/i);
var rehydrated = new RegExp(fragments[1], fragments[2] || '');

保留模式和标志 - 希望这对某人有所帮助!

【讨论】:

使用[a-zA-Z]+ 而不是[gimy]? 更具前瞻性(目前有6个标志;也可以有多个标志......事实上我认为使用它们全部,例如/x/gimsuy 是有效的!) 在 2019 年是的,我认为其中一些在我的 OG 回答时并未使用 :)【参考方案6】:

我认为一个好的方法是这样的:

function stringifyFilter(key,value) 
    if (value instanceof RegExp) 
        return value.toString();
    

    return value;


var myObj = 
    text : 'Howdy ho!',
    pattern : /[a-z]+/i


JSON.stringify(myObj,stringifyFilter); // output: "text":"Howdy ho!","pattern":"/[a-z]+/i"

【讨论】:

那太好了,我不知道JSON.stringify的第二个参数是一个过滤器。

以上是关于RegExp的序列化的主要内容,如果未能解决你的问题,请参考以下文章

json深拷贝有正则表达式的时候会返回空对象,就是js用json深拷贝的缺点吗?

正则表达式(RegExp)

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

正则 基础

php 正则

正则-所有字符