Вопрос по javascript, json, stringify – Сериализация RegExp

22

Итак, мне было интересно узнать, чтоJSON.stringify уменьшает RegExp до пустого объекта-литерала (играть на скрипке):

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

Ожидается ли такое поведение? Я понимаю, что RegExp - это объект без свойств для сериализации. Тем не менее, даты тоже объекты; ещеJSON.stringify() удается создать значимую строку:

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

Я бы надеялся, что JSON даст RegExp такое же соображение, используяRegExp.prototype.нанизывать().

@ canon реальная проблема заключается в том, что объекты регулярных выражений не обладают такой же универсальностью, как строки, числа и логические значения. JSON - это формат обмена данными, поэтому важно, чтобы JSON можно было использовать в максимально возможном количестве языковых контекстов. Десериализация экземпляра RegExp в язык со значительно отличающимся механизмом регулярных выражений - или без такого механизма - была бы проблематичной. Pointy
Да, знаю. вот почему я не отвечал, но комментировал. Shiplu Mokaddim
@ shiplu.mokadd.im Я действительно не ищу обходной путь. Достаточно легко вручную сериализовать регулярное выражение. anon
Вы должны преобразовать его в строку и использоватьRegExp объект позже для десериализации Shiplu Mokaddim

Ваш Ответ

6   ответов
35

Если кому-то будет интересно, есть хороший обходной путь. Я не думаю, что текущее поведение является правильным. Например,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"}"
@tenbits, да. Я собираюсь избегать использования этого шаблона, потому что люди, несомненно, допустят ошибку, предполагая, что эта строка будет использоваться конструктором RegExp.
Хорошо, я не знал оtoJSON().
Я думаю, что они должны стандартизировать это. Было бы разумно использовать это как поведение по умолчанию парсера / строкового модификатора JSON.
@matthoiland, я использую это всегда, и я не знаю ни одного практического варианта использования, когда это не может быть использовано или ведет к неопределенному поведению. Но, как вы можете видеть, он расширяет прототипы RegExp.though you can extend it via Object.defineProperty to make it not enumerable (but have you ever iterated over regexp instances?); и это также изменяет поведение по умолчанию tojson, так что эта тема может быть умозрительной, но с моим опытом я считаю этот подход и такое поведение правильным.
@goofballLogic, вы не можете сделать это:new RegExp(x.toString()), какtoString создает буквенную нотацию RegExp, она имеет косую черту в конце и заканчивается также косой чертой, за которой необязательно следуют флаги регулярного выражения:/REGEXP_STRING/FLAGS, Такnew RegExp("foo", "i").toString() производит: & quot; / foo / i & quot; строка. Рассмотрим мои правки:gist.github.com/tenbits/ec7f0155b57b2d61a6cc90ef3d5f8b49
24

И то и другое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));

Вам просто нужно придумать свой собственный формат сериализации.

Хорошо, я чувствую, что может быть библиотека js только для сериализации / десериализации регулярного выражения.
1

Я думаю, что хороший подход будет что-то вроде этого:

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 был фильтр.
2

Вот как я решил эту проблему:

Сериализуйте это как строку:

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

Затем перегидратируйте его, используя другое регулярное выражение:

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

Сохраняет шаблон и флаги - надеюсь, это кому-нибудь поможет!

11

Да, потому что в JSON нет канонического представления для объекта RegExp. Таким образом, это просто пустой объект.

edit & # X2014; ну, теперь 2018 год; ответы, предлагающие решения с использованием.toJSON() и т.д., вероятно, все в порядке, хотя я бы добавил метод в прототип с

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

и так далее. Это гарантирует, что имя функции не может быть перечисляемым, что делает «обезьянью заплатку» несколько более гигиеничной.

Понятно, что это ошибка. Ответ @tenbits должен быть ответом.
Да, это объект без свойств, и это все, что видит JSON. Я думаю, вы могли бы преобразовать ее в строку, но тогда она все еще не является экземпляром RegExp.
Я бы подумал, что, поскольку он уже имеет буквальное представление в javascript, это хорошо отразится на JSON; Я полагаю, нет.
@tgoneil это не "ошибка"; спецификация JSON просто не включает регулярные выражения в качестве примитивного типа значения. Он также не включает даты и другие вещи.
2
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(st,ringified).rgx)
Мой пример отличается от приведенного выше, потому что, используя мой, вы можете сериализовать / десериализовать с помощью JSON.stringify / parse и получить тот же результат регулярного выражения.
Вы можете улучшить это путем toString источника в методе toJSON.RegExp.prototype.toJSON = function() { return this.source.toString(); };

Похожие вопросы