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深拷贝的缺点吗?