Сериализация RegExp
Итак, мне было интересно узнать, что JSON.stringify
уменьшает RegExp до пустого литерала объекта ( fiddle):
JSON.stringify(/^[0-9]+$/) // "{}"
Ожидается ли такое поведение? Я понимаю, что RegExp - это объект без свойств для сериализации. Тем не менее, даты тоже объекты; еще JSON.stringify()
удается создать значимую строку:
JSON.stringify(new Date) // "2014-07-03T13:42:47.905Z"
Я бы надеялся, что JSON даст RegExp такое же соображение, используя RegExp.prototype. toString()
,
6 ответов
Да, потому что в JSON нет канонического представления для объекта RegExp. Таким образом, это просто пустой объект.
редактировать - ну, теперь 2018 год; ответы, предлагающие решения с использованием .toJSON()
и т.д., вероятно, хорошо, хотя я бы добавил метод к прототипу с
Object.defineProperty(RegExp.prototype, "toJSON", {
value: RegExp.prototype.toString
});
и так далее. Это гарантирует, что имя функции не может быть перечисляемым, что делает обезьянку-патч несколько более гигиеничной.
Если кому-то будет интересно, есть хороший обходной путь. Я не думаю, что текущее поведение является правильным. Например, 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"}"
И JSON.stringify, и JSON.parse можно настроить для выполнения настраиваемой сериализации и десериализации с помощью replacer
и возродить аргументы.
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));
Вам просто нужно придумать свой собственный формат сериализации.
Вот как я решил эту проблему:
Сериализуйте это как строку:
var pattern = /foobar/i;
var serialized = JSON.stringify(pattern.toString());
Затем перегидратируйте его, используя другое регулярное выражение:
var fragments = serialized.match(/\/(.*?)\/([gimy])?$/);
var rehydrated = new RegExp(fragments[1], fragments[2] || '');
Сохраняет шаблон и флаги - надеюсь, это кому-нибудь поможет!
Я думаю, что хороший подход будет что-то вроде этого:
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"}
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)