Answer
Unscrew your hard work, I just want to answer! Ok, here you go ...
var regex = /^path(?:(?=\?)(?:[?&]foo=(\d*)(?=[]|$)|(?![?&]foo=)[^#])+)?(?=#|$)/, URIs = [ 'path',
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>
Study
In the request for the request, βreliable and / or official sourcesβ are requested, so I will quote the RFC along the lines of the request .
The request component contains non-hierarchical data, which, together with the data in the path component (section 3.3), serves to identify the resource in the framework of the URI scheme and naming authority (if any). The request component is indicated by the symbol of the first question mark ("?") And ends with a license plate symbol ("#") or to the end of the URI.
This seems rather vague: does the query line begin with the first ? and ends with # (start of binding) or end of URI (or line / line in our case). They further mention that most datasets are in key=value pairs, which is similar to what you would expect from parsing (so let's assume this is the case).
However, since query components are often used to carry identifying information in the form of key-value pairs, and one frequently used value is a reference to another URI, it is sometimes better to use the ability to avoid percent encoding of these characters.
Given all this, let me suggest a few things about your URIs:
- Your examples start with a path, so the path will start from the beginning of the line to
? (query string), # (anchor) or end of line. - The query string is part of iffy, since the RFC does not really define a "norm". The browser typically expects the query string to be generated from the form view and will be a list of
key=value pairs added by & . Keeping this mentality:- The key cannot be
null , is it preceded by ? or & and cannot contain = , & or # . - The value is optional; it is preceded by
key= and cannot contain & or # .
- Everything after the
# symbol is an anchor.
To begin!
Let's start by mapping our basic URI structure . Do you have a path that is a character starting with a string, and up to ? , # or end of line. Do you have an optional query string that starts with ? and continues to # or the end of the line. And you have an extra anchor that starts with # and goes to the end of the line.
^ ([^?
Let do some cleanup before delving into the query string. You can easily require that the path be equal to a specific value by replacing the first capture group. Regardless of the fact that you replace it ( path ), it must be followed by an optional query string, an optional anchor and the end of the string (no more, no less). Since you do not need to parse the binding, the capture group can be replaced by ending the match at either # or the end of the line (which is the end of the query parameter).
^path (?: \? ([^
Stop Messing Around
Well, I tuned a lot without worrying about your specific example. The following example will correspond to a certain path ( path ) and optionally correspond to the query string when capturing the value of the foo parameter. This means that you can stop here and check the compliance. If the match is valid, then the first capture group must be a null or non-negative integer. But that was not your question, was it. This has become much more complicated , so I will explain the inline expression:
^ (?# match beginning of the string) path (?# match path literally) (?: (?# begin optional non-capturing group) (?=\?) (?# lookahead for a literal ?) (?: (?# begin optional non-capturing group) [?&] (?# keys are preceded by ? or &) foo (?# match key literally) (?: (?# begin optional non-capturing group) = (?# values are preceded by =) ([^&#]*) (?# values are 0+ length and do not contain & or #) ) (?# end optional non-capturing group) | (?# OR) [^#] (?# query strings are non-# characters) )+ (?# end repeating non-capturing group) )? (?# end optional non-capturing group) (?=#|$) (?# lookahead for a literal # or end of the string)
Some key outputs here:
- Javascript does not support lookbehinds, that is, you can not look behind
? or & in front of the foo key, which means that you really need to match one of these characters, which means the beginning of your request, the string (which is looking for ? ) should be lookout, so you actually don't match ? . It also means that your query string will always be at least one character ( ? ), So you want to repeat the query string [^#] 1+ times. - The query line now repeats one character at a time in the group without capture .. if it does not see the key
foo , in which case it captures an optional value and continues to be repeated. - Since this group of non-capture request strings is repeated all the way to the binding or end of the URI, the second value foo (
path?foo=123&foo=bar ) will overwrite the initial committed value. You may not be able to rely 100% on the above solution.
The final decision?
Good. Now I grabbed the foo value, time to kill the match for values ββthat are not positive integers .
^ (?
Let's take a closer look at some of the juju that went into this expression:
- After finding
foo=\d* we use lookahead to make sure that it is followed by & , # or the end of the line (the end of the query string value). - However, if the number
foo=\d* greater, the regular expression will be discarded by the generator for a common [^#] match on the right on [?&] To foo . This is not good, because he will continue to match! Therefore, before looking for a common query string ( [^#] ), you should make sure that you are not looking at foo (which should be handled by the first rotation). It is useful to use a negative lookhhead (?![?&]foo=) . - This will work with multiple
foo keys, since they will all have equal non-negative integers. This allows foo be optional (or equal to null ).
Denial of responsibility. Most Regex101 demos use PHP to improve syntax highlighting and include \n in negative character classes, as there are several lines of examples.