Stringifying a regular expression? - javascript

Of course, JSON does not support Regex literals.
So,
JSON.stringify(/foo/)
gives:
{ }
Any workarounds?

I think this is the closest you can get:
RegExp.prototype.toJSON = function() { return this.source; };
JSON.stringify({ re: /foo/ }); // { "re": "foo" }

You can pass a a custom replacer function to JSON.stringify and convert the regular expression to a string (assuming that the expression is part of an array or object):
JSON.stringify(value, function(key, value) {
if (value instanceof RegExp) {
return value.toString();
}
return value;
});
If you don't actually want/need to create JSON, just call the toString() method of the expression.

Although JavaScript objects allow you to put regex as values, JSON does not as it is meant to store only data, not code.
As a workaround, you could convert your regular expression to a string using the toString() method.
var str = /([a-z]+)/.toString(); // "/([a-z]+)/"

You can use a replacer function:
JSON.stringify(/foo/,
function(k, v) {
if (v && v.exec == RegExp.prototype.exec) return '' + v;
else return v;
})

Related

Always getting "[object Object]" as output from custom string format function

I'm using a string format function copied direct from the StackOverflow source code; you can test it right now in the developer console with the following code:
"Logged in as {tag}, on {guilds} guild{s}".formatUnicorn({ tag: "TAG_HERE", guilds: "GUILD_COUNT", s: "s" });
I'm trying to use this exact same function, yet am always getting [object Object] as the output.
logger.info("bot", "Logged in as {tag}, on {guilds} guild{s}".format({ tag: client.user.tag, guilds: client.guilds.size, s: client.guilds.size === 1 ? "" : "s" }));
I've tried require("util").inspect(...)ing the Object that's returned, but that just outputs '[object Object]', essentially the exact same thing but with single quotes surrounding it.
Here's the function, if that helps. I've renamed some of the variables for this question, though in testing the code it was a direct copy from the SO source:
String.prototype.format = () => {
let string = this.toString();
if(!arguments.length)
return string;
let type = typeof arguments[0],
replacements = "string" == type || "number" == type ? Array.prototype.slice.call(arguments) : arguments[0];
for(const index in replacements)
string = string.replace(new RegExp("\\{" + index + "\\}", "gi"), replacements[index]);
return string;
}
This is likely a simple mistake with a simple solution but I've worked quite a while to try to diagnose the issue/get it working but finding nothing to fix it myself.
Arrow functions does not bind its own arguments so your function will not work.
Changing from String.prototype.format = () => {} to String.prototype.format = function () {} will fix it for you.
it hapens because you are using this.toString(); and this is a json Object.
try it :
String.prototype.format = function() { ...
instead:
String.prototype.format = () => { ...

String to Object conversion?

I have a string variable that is a string representation of an object. Like this:
{
"column": "'asdf'",
"sort": "true",
"search": "{\"asdf\":\"searchval\"}"
}
I would like to transform the above string into an object that looks like this:
{
column: 'asdf',
sort: 'true',
search: {
asdf: 'searchval'
}
}
I am planning on doing a search and replace regex expression for quotes and back slashes, and then using eval(), but that seems unsafe and innefficient. Is there an alternative method that would work better?
I am planning on assigning the object value of the string to an object variable.
Have you tried JSON.parse(); yet?
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse
var myOriginalData = JSON.stringify({"column": "'asdf'","sort": "true","search": "{\"asdf\":\"searchval\"}"});
myNewData = JSON.parse(myOriginalData, function (key, value) {
var type;
if (value && typeof value === 'object') {
type = value.type;
if (typeof type === 'string' && typeof window[type] === 'function') {
return new (window[type])(value);
}
}
return value;
});
console.log('myNewData -----------------------------------------------------------');
console.log(myNewData);
Working Example: http://plnkr.co/edit/2jLGIxx3AVEceVQsOpxL?p=preview
Immediately after posting this, I found out there is a JSON.parse(); function. The only reason I don't delete the question, is it might save someone time later.
All you need to do is pass the string variable as a parameter and it will output an object.
If anyone sees any problems with this solution, or knows a better solution, please make an answer!

Serialization of RegExp

So, I was interested to find that JSON.stringify reduces a RegExp to an empty object-literal (fiddle):
JSON.stringify(/^[0-9]+$/) // "{}"
Is this behavior expected? I realize that a RegExp is an object with no properties to serialize. That said, dates are objects too; yet JSON.stringify() manages to produce a meaningful string:
JSON.stringify(new Date) // "2014-07-03T13:42:47.905Z"
I would have hoped that JSON would give RegExp the same consideration by using RegExp.prototype.toString().
If somebody would be interested, there is a nice workaround. I don't think, that current behaviour is correct. For example, Date instance is not serialized to empty object like RegExp, though it is an object and also has no JSON representation.
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"}"
Both JSON.stringify and JSON.parse can be customized to do custom serialization and deserialization by using the replacer and reviver arguments.
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));
You just have to come up with your own serialization format.
Yes, because there's no canonical representation for a RegExp object in JSON. Thus, it's just an empty object.
edit — well it's 2018 now; the answers suggesting solutions using .toJSON() etc are probably fine, though I'd add the method to the prototype with
Object.defineProperty(RegExp.prototype, "toJSON", {
value: RegExp.prototype.toString
});
and so on. That ensures that the function name isn't enumerable, which makes the monkey-patch somewhat more hygienic.
Here's how I solved this issue:
Serialize it as a string:
var pattern = /foobar/i;
var serialized = JSON.stringify(pattern.toString());
Then rehydrate it using another regex:
var fragments = serialized.match(/\/(.*?)\/([a-z]*)?$/i);
var rehydrated = new RegExp(fragments[1], fragments[2] || '');
Preserves the pattern and flags - hope this helps someone!
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)
I think a good approach would be something like this:
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"}

JavaScript Json.stringify replacer converts values to string

I am using the javascript JSON.stringify function with a replacer (second parameter) to format date values in a certain way:
var s = JSON.stringify(data, function (key, value) {
if (key === "") return value;
if (jQuery.type(value) === "date") return "Date(" + value.getTime() + ")";
return value;
});
I have valid datetime values in my object "data". However, when the replacer function is executed with this value, the datetime value is automatically converted to a string and therefore jQuery.type(value) = "string" and not "date" anymore.
I could simply replace all datetime values in the value-object before I call stringify, but I would prefer not to modify the original data.
Is this how the replacer function should behave or is this a strange feature of IE (I'm using IE9)? How could I solve this problem?
Try
Date.prototype.toJSON = function() {
return "Date(" + this.getTime() + ")";
};
Without the replacer.

"in" statement in Javascript/jQuery

Does Javascript or jQuery have sometime like the "in" statement in Python?
"a" in "dea" -> True
Googling for the word in is hopeless :(
It does have an in operator but is restricted to object keys only:
var object = {
a: "foo",
b: "bar"
};
// print ab
for (var key in object) {
print(key);
}
And you may also use it for checks like this one:
if ("a" in object) {
print("Object has a property named a");
}
For string checking though you need to use the indexOf() method:
if ("abc".indexOf("a") > -1) {
print("Exists");
}
you would need to use indexOf
e.g
"dea".indexOf("a"); will return 2
If its not in the item then it will return -1
I think thats what you are after.
Sounds like you need regular expressions!
if ("dea".match(/a/))
{
return true;
}
How about indexOf?
With the indexOf function, you can extend the String like such:
String.prototype.in = function (exp) {
return exp.indexOf(this) >= 0;
}
if ("ab".in("abcde")) { //true
}

Categories