{"action":"created","issue":{"url":"https://api.github.com/repos/aseemk/json5/issues/91","repository_url":"https://api.github.com/repos/aseemk/json5","labels_url":"https://api.github.com/repos/aseemk/json5/issues/91/labels{/name}","comments_url":"https://api.github.com/repos/aseemk/json5/issues/91/comments","events_url":"https://api.github.com/repos/aseemk/json5/issues/91/events","html_url":"https://github.com/aseemk/json5/issues/91","id":106617456,"number":91,"title":"Regexes","user":{"login":"KOLANICH","id":240344,"avatar_url":"https://avatars.githubusercontent.com/u/240344?v=3","gravatar_id":"","url":"https://api.github.com/users/KOLANICH","html_url":"https://github.com/KOLANICH","followers_url":"https://api.github.com/users/KOLANICH/followers","following_url":"https://api.github.com/users/KOLANICH/following{/other_user}","gists_url":"https://api.github.com/users/KOLANICH/gists{/gist_id}","starred_url":"https://api.github.com/users/KOLANICH/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/KOLANICH/subscriptions","organizations_url":"https://api.github.com/users/KOLANICH/orgs","repos_url":"https://api.github.com/users/KOLANICH/repos","events_url":"https://api.github.com/users/KOLANICH/events{/privacy}","received_events_url":"https://api.github.com/users/KOLANICH/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/aseemk/json5/labels/question","name":"question","color":"cc317c"}],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":4,"created_at":"2015-09-15T18:34:05Z","updated_at":"2016-03-15T22:12:27Z","closed_at":"2015-12-11T20:21:55Z","body":"PCRE is now the main regex format, included into stdlibs of the most of languages. Why not to allow inserting literal regexes into JSON5 document?"},"comment":{"url":"https://api.github.com/repos/aseemk/json5/issues/comments/197048166","html_url":"https://github.com/aseemk/json5/issues/91#issuecomment-197048166","issue_url":"https://api.github.com/repos/aseemk/json5/issues/91","id":197048166,"user":{"login":"jordanbtucker","id":468153,"avatar_url":"https://avatars.githubusercontent.com/u/468153?v=3","gravatar_id":"","url":"https://api.github.com/users/jordanbtucker","html_url":"https://github.com/jordanbtucker","followers_url":"https://api.github.com/users/jordanbtucker/followers","following_url":"https://api.github.com/users/jordanbtucker/following{/other_user}","gists_url":"https://api.github.com/users/jordanbtucker/gists{/gist_id}","starred_url":"https://api.github.com/users/jordanbtucker/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jordanbtucker/subscriptions","organizations_url":"https://api.github.com/users/jordanbtucker/orgs","repos_url":"https://api.github.com/users/jordanbtucker/repos","events_url":"https://api.github.com/users/jordanbtucker/events{/privacy}","received_events_url":"https://api.github.com/users/jordanbtucker/received_events","type":"User","site_admin":false},"created_at":"2016-03-15T22:12:27Z","updated_at":"2016-03-15T22:12:27Z","body":"It still seems that there is some desire to implement regular expressions as first class values in JSON5. So, I'm going to elaborate on why I think it's a bad idea.\r\n\r\n## Parsing\r\n\r\nI've already established that if you just treat everything between two `/` characters as a regular expression you'd have to use the native platform's regular expression parser to ensure it's valid. Bet let me entertain that idea and see how easy it would be to implement it.\r\n\r\nFirst, you'd need to make sure that at least one character exists between the two `/`s because `//` is a comment in JSON5.\r\n\r\n```js\r\n//  <- comment\r\n/a/ <- RegExp\r\n```\r\n\r\nNow, what happens if you want to match a `/` in your regular expression? You need to escape it with a `\\` character.\r\n\r\n```js\r\n/a\\/b/    // matches 'a/b'\r\n```\r\n\r\nOkay, so any occurrences of `\\/` should not terminate a regular expression. But what about this regular expression:\r\n\r\n```js\r\n/a\\\\/    // matches 'a\\\\'\r\n```\r\n\r\nIt has an occurrence of `\\/` but the `\\` is escaped as `\\\\`. So we need to check for occurrences of `\\\\` and `\\/`.\r\n\r\nOkay, we're done, right? Well, what about this regular expression?\r\n\r\n```js\r\n/a[b/c]d/    // matches 'abd', 'a/d' and 'acd'\r\n```\r\n\r\nIt's a valid regular expression with an unescaped `/` because it's inside an alternation group `[…]`. So now we need to track when an alternation group begins and ends. Not so difficult, right?\r\n\r\n```js\r\n/a\\[bc]d/    // matches 'a[bc]d'\r\n/a[b[c]d/    // matches 'abd', 'a[d' and 'acd'\r\n/a[bc\\]d/    // error: alternation group is never closed\r\n```\r\n\r\nOkay, so in the first example the `[` is escaped, but the `]` isn't because it only has special meaning in an alternation group. In the second example, the second `[` is not escaped but doesn't start new alternation group. The third example is self-explanatory. So, we need to check for `[`, `]`, `\\[`, and `\\]`, and treat `[` and `]` differently depending on whether or not we're in a alternation group.\r\n\r\nDoes that cover our bases? I don't know, but for the sake of argument, let's just say it does.\r\n\r\nLet's simplify this into a list of steps:\r\n\r\n1. When parsing a JSON5 value, if the first non-whitespace character is `/`:\r\n2. Peek the next character, and if it is `/`, parse a comment, and do not perform subsequent steps. (Otherwise, assume it's a regular expression.)\r\n3. Let *p* = \"\". *p* will store the regular expression pattern.\r\n4. Let *f* = \"\". *f* will store the regular expression flags.\r\n5. Let *a* = false. *a* will indicate whether we are in an alternation group.\r\n6. Let *c* = the next character read from the stream of characters.\r\n7. If *c* is `/` and *a* is false, skip to step 14.\r\n8. If *c* is `/` and *a* is true, concatenate *c* onto *p*, and return to step 6.\r\n9. If *c* is `[`, set *a* to true, concatenate *c* onto *p*, and return to step 6.\r\n10. If *c* is `]`, set *a* to false, concatenate *c* onto *p*, and return to step 6.\r\n11. If *c* is `\\`, concatenate *c* and the next character in the stream onto *p*, and return to step 6.\r\n12. If the end of the stream has been reached, throw a parsing error.\r\n13. Concatenate *c* onto *p*, and return to step 6.\r\n14. Let *c* = the next character read from the stream.\r\n15. If *c* matches the [*IdentifierPart*][1] production, concatenate *c* onto *f*, and return to step 13.\r\n16. Try to instantiate a `RegExp` object with the arguments *p* and *f*.\r\n\r\nStep 16 parses the flags according to the [ES5 spec][2]. This would allow implementation specific flags to be used (e.g. ES5 doesn't support the `s` flag, but does support the non-standard `y` flag).\r\n\r\nBesides the fact that this extremely minimal regular expression parser is still relatively complex, it doesn't actually *parse* the regular expression. There's no way to validate the regular expression in an implementation agnostic way without writing way more code.\r\n\r\nWe would also need to define what happens if a platform doesn't support regular expressions or can't parse the regular expression given. It wouldn't know until you tried to parse it.\r\n\r\nSo, all JSON5 documents that include regular expressions would have to be late-validated, and there would be no true JSON5 validator.\r\n\r\n## Implementation Agnostic vs Implementation Specific\r\n\r\nLet's say we did implement a full regular expression parser according to the ES5 spec. It would no longer be implementation agnostic, and we would expect all implementations of JSON5 to parse JSON5 regular expressions into an ES5 compatible format on its native platform.\r\n\r\nFurther, by creating an implementation restricted parser you're castrating the more powerful regular expression engines supported by other platforms. No more named captures, no more comments, no more look-behind, no more recursion, no more `s` flag (dot matches new line).\r\n\r\n## Solution\r\n\r\n`JSON.stringify` serializes a `RegExp` instance as en empty object (`{}`). You can modify that behavior by executing the following line of code:\r\n\r\n```js\r\nRegExp.prototype.toJSON = function() { return this.toString() }\r\n```\r\n\r\nThat's all you need to do to write code like:\r\n\r\n```js\r\nvar emailRegex = /^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$/\r\nconsole.log(JSON.stringify(emailRegex))\r\n// output: \"/^([a-z0-9_\\\\.-]+)@([\\\\da-z\\\\.-]+)\\\\.([a-z\\\\.]{2,6})$/\"\r\n``` \r\n\r\nAs an added bonus, that same line of code also applies to `JSON5.stringify` because JSON5 also checks for `toJSON()`.\r\n\r\n[1]: https://es5.github.io/#x7.6\r\n[2]: https://es5.github.io/#x7.8.5"}}