{"action":"created","issue":{"url":"https://api.github.com/repos/robrix/Madness/issues/51","labels_url":"https://api.github.com/repos/robrix/Madness/issues/51/labels{/name}","comments_url":"https://api.github.com/repos/robrix/Madness/issues/51/comments","events_url":"https://api.github.com/repos/robrix/Madness/issues/51/events","html_url":"https://github.com/robrix/Madness/issues/51","id":54626441,"number":51,"title":"“Not” combinator","user":{"login":"robrix","id":59671,"avatar_url":"https://avatars.githubusercontent.com/u/59671?v=3","gravatar_id":"","url":"https://api.github.com/users/robrix","html_url":"https://github.com/robrix","followers_url":"https://api.github.com/users/robrix/followers","following_url":"https://api.github.com/users/robrix/following{/other_user}","gists_url":"https://api.github.com/users/robrix/gists{/gist_id}","starred_url":"https://api.github.com/users/robrix/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/robrix/subscriptions","organizations_url":"https://api.github.com/users/robrix/orgs","repos_url":"https://api.github.com/users/robrix/repos","events_url":"https://api.github.com/users/robrix/events{/privacy}","received_events_url":"https://api.github.com/users/robrix/received_events","type":"User","site_admin":true},"labels":[{"url":"https://api.github.com/repos/robrix/Madness/labels/enhancement","name":"enhancement","color":"84b6eb"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2015-01-16T21:21:44Z","updated_at":"2015-02-21T13:52:40Z","closed_at":null,"body":"Matches any character not matched by the argument parser."},"comment":{"url":"https://api.github.com/repos/robrix/Madness/issues/comments/75372530","html_url":"https://github.com/robrix/Madness/issues/51#issuecomment-75372530","issue_url":"https://api.github.com/repos/robrix/Madness/issues/51","id":75372530,"user":{"login":"robrix","id":59671,"avatar_url":"https://avatars.githubusercontent.com/u/59671?v=3","gravatar_id":"","url":"https://api.github.com/users/robrix","html_url":"https://github.com/robrix","followers_url":"https://api.github.com/users/robrix/followers","following_url":"https://api.github.com/users/robrix/following{/other_user}","gists_url":"https://api.github.com/users/robrix/gists{/gist_id}","starred_url":"https://api.github.com/users/robrix/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/robrix/subscriptions","organizations_url":"https://api.github.com/users/robrix/orgs","repos_url":"https://api.github.com/users/robrix/repos","events_url":"https://api.github.com/users/robrix/events{/privacy}","received_events_url":"https://api.github.com/users/robrix/received_events","type":"User","site_admin":true},"created_at":"2015-02-21T13:52:40Z","updated_at":"2015-02-21T13:52:40Z","body":"@davidcairns: TL;DR: Makes no different how many characters the pattern matches (zero, one, n), it’s whether it returns `nil` or not.\r\n\r\n`!a` would match a single character iff `a` does not match; so it doesn’t matter if `a` would consume input because we don’t care how much it consumes, we just care whether it matches or fails.\r\n\r\nMy current thinking is that it’d be better to do [zero-width negative lookahead](http://www.regular-expressions.info/lookaround.html) instead. In that model, `?!a` would never consume any input, but would succeed iff `a` does not match. Then you’d do `?!a ++ b` to allow `b` to parse when `a` cannot.\r\n\r\nThis works because parser combinators return `(/*parseTree: */ T, /*restOfInput:*/ String)?`, so they can return the input unmodified in the tuple to do this. And they indicate failure by returning `nil`, so we can unambiguously determine whether they matched zero characters or failed.\r\n\r\nHere’s an example using `?!` to recover the behaviour described at top (parsing any single character not matched by its argument):\r\n\r\n```swift\r\nlet quote = ignore(\"\\\"\")\r\nlet string = quote ++ (?!quote ++ any)* ++ quote\r\n```"}}