Consider my few input strings.
http://local.app.com/local/frontend/v12/#/abcde/
http://local.app.com/local/frontend/v12/#/abcde/!/fghij/
http://local.app.com/local/frontend/v12/#/abcde/!/ghijk/!/klmno/
I have written this regex which works fine for input string 1.
(?:([a-zA-Z0-9.://_]*)(/#/(?=([a-zA-Z0-9]{5})/)))
Output:
http://local.app.com/local/frontend/v12/#/,http://local.app.com/local/frontend/v12,/#/,abcde
But when I extend it to support repetitive !/.../ place holder for input string 1,2 and 3, it doesn't work and gives empty string rather than token.
(?:([a-zA-Z0-9.://_]*)(/#/(?=([a-zA-Z0-9]{5})/))(!/(?=([a-zA-Z0-9]{5})/))*)
Output:
http://local.app.com/local/frontend/v12/#/,http://local.app.com/local/frontend/v12,/#/,abcde,,
?= captures in fact a position defined by what you specify after the ?=
It does not (also) capture whatever may match the specification of the lookaround (?=).
Try
(.+? # (/[a-zA-Z0-9]{5}/) (!/([a-zA-Z0-9]{5})/)* )
(hope I didn't make a typo, can't test it right now.)
This should capture the complete input, but the various captures inside give you access to the captured "tokens".
You can, in addition, give names to the various captures inside, making it easier to identify them in the match:
(.+?#(/(?<tokenFirst>[a-zA-Z0-9]{5})/)(!/(?<tokenMore>[a-zA-Z0-9]{5})/)*)
Success
Hope this will clarify my comment and earlier remarks.
Related
I have the following string that will occur repeatedly in a larger string:
[SM_g]word[SM_h].[SM_l] "
Notice in this string after the phrase "[SM_g]word[Sm_h]" there are three components:
A period (.) This could also be a comma (,)
[SM_l]
"
Zero to all three of these components will always appear after "[SM_g]word[SM_h]". However, they can also appear in any order after "[SM_g]word[SM_h]". For example, the string could also be:
[SM_g]word[SM_h][SM_l]"
or
[SM_g]word[SM_h]"[SM_l].
or
[SM_g]word[SM_h]".
or
[SM_g]word[SM_h][SM_1].
or
[SM_g]word[SM_h].
or simply just
[SM_g]word[SM_h]
These are just some of the examples. The point is that there are three different components (more if you consider the period can also be a comma) that can appear after "[SM_h]word[SM_g]" where these three components can be in any order and sometimes one, two, or all three of the components will be missing.
Not only that, sometimes there will be up to one space before " and the previous component/[SM_g]word[SM_h].
For example:
[SM_g]word[SM_h] ".
or
[SM_g]word[SM_h][SM_l] ".
etc. etc.
I am trying to process this string by moving each of the three components inside of the core string (and preserving the space, in case there is a space before &\quot; and the previous component/[SM_g]word[SM_h]).
For example, [SM_g]word[SM_h].[SM_l]" would turn into
[SM_g]word.[SM_l]"[SM_h]
or
[SM_g]word[SM_h]"[SM_l]. would turn into
[SM_g]word"[SM_l].[SM_h]
or, to simulate having a space before "
[SM_g]word[SM_h] ".
would turn into
[SM_g]word ".[SM_h]
and so on.
I've tried several combinations of regex expressions, and none of them have worked.
Does anyone have advice?
You need to put each component within an alternation in a grouping construct with maximum match try of 3 if it is necessary:
\[SM_g]word(\[SM_h])((?:\.|\[SM_l]| ?"){0,3})
You may replace word with .*? if it is not a constant or specific keyword.
Then in replacement string you should do:
$1$3$2
var re = /(\[SM_g]word)(\[SM_h])((?:\.|\[SM_l]| ?"){0,3})/g;
var str = `[SM_g]word[SM_h][SM_l] ".`;
console.log(str.replace(re, `$1$3$2`));
This seems applicable for your process, in other word, changing sub-string position.
(\[SM_g])([^[]*)(\[SM_h])((?=([,\.])|(\[SM_l])|( ?&\\?quot;)).*)?
Demo,,, in which all sub-strings are captured to each capture group respectively for your post processing.
[SM_g] is captured to group1, word to group2, [SM_h] to group3, and string of all trailing part is to group4, [,\.] to group5, [SM_l] to group6, " ?&\\?quot;" to group7.
Thus, group1~3 are core part, group4 is trailing part for checking if trailing part exists, and group5~7 are sub-parts of group4 for your post processing.
Therefore, you can get easily matched string's position changed output string in the order of what you want by replacing with captured groups like follows.
\1\2\7\3 or $1$2$7$3 etc..
For replacing in Javascript, please refer to this post. JS Regex, how to replace the captured groups only?
But above regex is not sufficiently precise because it may allow any repeatitions of the sub-part of the trailing string, for example, \1\2\3\5\5\5\5 or \1\2\3\6\7\7\7\7\5\5\5, etc..
To avoid this situation, it needs to adopt condition which accepts only the possible combinations of the sub-parts of the trailing string. Please refer to this example. https://regex101.com/r/6aM4Pv/1/ for the possible combinations in the order.
But if the regex adopts the condition of allowing only possible combinations, the regex will be more complicated so I leave the above simplified regex to help you understand about it. Thank you:-)
I've racked my brain over this JS regex and have so far only managed to get parts of it to work or the whole thing to work in certain circumstances.
I have a string like this:
Some string<br>http://anysubdomain.particulardomain.com<br>Rest of string
The goal is to move the domain part to the end of the string, if it's there. The http part is also optional and can also be https. The TLD is always particulardomain.com, the subdomain can be anything.
I've managed to get everything into capture groups when the domain with protocol is present with this regex:
(.*)(https?\:\/\/[a-z\d\-]*\.particulardomain\.com)(.*)
But any attempt at making the domain part and the protocol part within it optional has resulted in no or the wrong matches.
The end result I'm looking for is to have the three parts of the string – beginning, domain, end – in separate capture groups so I can move capture group 2 (the domain part) to the end, or, if there's no domain present, the whole string in the first capture group.
To clarify, here are some examples with the expected output/capture groups:
INPUT:
Some string<br>http://anysubdomain.particulardomain.com<br>Rest of string
OR (no protocol):
Some string<br>anysubdomain.particulardomain.com<br>Rest of string
OUTPUT:
$1: Some string<br>
$2: http://anysubdomain.particulardomain.com
$3: <br>Rest of string
INPUT:
Some string<br>Rest of string
OUTPUT:
$1: Some string<br>Rest of string
$2: empty
$3: empty
One mistake in your regex is that it contains only particular whereas
the source text contains particulardomain, but this is a detail.
Now let's move to the protocol part. You put only one ? (after s),
which means that only s is optional, but both http and :
are still required.
To make the whole protocol optional, you must:
enclose it with a group (either capturing or not),
make this group optional (put ? after it).
And now maybe the most important thing: Your regex starts with (.*).
Note that it is greedy version, which:
initially tries to capture the whole rest of source string,
then moves back one char by one, to allow matching by the
following part of regex.
Change it to reluctant version (.*?) and then optional
group (https?:)? will match as expected.
Another detail: \ before : is not needed. It does not do
any harm either, but due to the principle "Keep It Simple...",
I recommend to delete it (as I did above).
One more detail: After [a-z\d\-] (subdomain part) you should put
+, not *, as this part may not be empty.
So the whole regex can be:
(.*?)((https?:)?\/\/[a-z\d\-]+\.particulardomain\.com)(.*)
And the last remark: I am in doubt, whether you really need three
capturing groups. Maybe it would be enough to leave only the content
of the middle capturing group, i.e.:
(https?:)?\/\/[a-z\d\-]+\.particulardomain\.com
Found a solution. Since, as stated, the goal is to move the domain to the end of the string, if it's present, I'm just matching the domain and anything after it. If there's no domain, nothing matches and hence nothing gets replaced. The problem was the two .* both at the beginning and the end of the regex. Only the one at the end is needed.
REGEX:
([a-z\d\-:\/]+\.particulardomain\.com)(.*)
Works for the following strings:
Domain present:
Start of string 1234<br>https://subdomain.particulardomain.com<br>End of string 999
Domain without protocol:
Start of string 1234<br>subdomain.particulardomain.com<br>End of string 999
No domain:
Start of string 1234<br>End of string 999
Thanks everyone for helping me rethink the problem!
I see good answer here, as you explained you need three group and set the domain to the back of the string(to be clear the entire url or only the domain e.g particulardomain.com)
You can do this:
//Don't know if the <br> tag matter for you problem, suppose it not
//this is you input
let str = "Start of string 1234<br>https://subdomain.particulardomain.com<br>End of string 99";
let group = str.split(<br>);
let indexOfDomain;
/*moere code like a for loop or work with a in-build funcion of the array with the regExp you made /[a-z\d\-:\/]+\.particulardomain\.com/ you can validated the domain separately.
}
TO HAVE IN MIND:
With your solution will not work at 100%, why?
your regExp:
([a-z\d\-:\/]+\.particulardomain\.com)(.*)
will mach a http, https, *(any other thing that is not a protocol) and will not work for this input you can test if you like and do a comment
Start of string 1234<br>End of string 999
The regExp that #Valdi_Bo answer:
(.*?)((https?:)?\/\/[a-z\d\-]+\.particulardomain\.com)(.*)
will fit to the what you described in the question
This regExp don't fit all yours input maybe he did not test it for all your input as you did not explained in your question like you did in your own answer
In conclusion at the end you need to extract the domain (wich don't know if is the entire url as you mix up the idea). If you are not going to use the do a split and then validated the regExp it will be more easy
I want to get all the words, except one, from a string using JS regex match function. For example, for a string testhello123worldtestWTF, excluding the word test, the result would be helloworldWTF.
I realize that I have to do it using look-ahead functions, but I can't figiure out how exactly. I came up with the following regex (?!test)[a-zA-Z]+(?=.*test), however, it work only partially.
http://refiddle.com/refiddles/59511c2075622d324c090000
IMHO, I would try to replace the incriminated word with an empty string, no?
Lookarounds seem to be an overkill for it, you can just replace the test with nothing:
var str = 'testhello123worldtestWTF';
var res = str.replace(/test/g, '');
Plugging this into your refiddle produces the results you're looking for:
/(test)/g
It matches all occurrences of the word "test" without picking up unwanted words/letters. You can set this to whatever variable you need to hold these.
WORDS OF CAUTION
Seeing that you have no set delimiters in your inputted string, I must say that you cannot reliably exclude a specific word - to a certain extent.
For example, if you want to exclude test, this might create a problem if the input was protester or rotatestreet. You don't have clear demarcations of what a word is, thus leading you to exclude test when you might not have meant to.
On the other hand, if you just want to ignore the string test regardless, just replace test with an empty string and you are good to go.
I've got a regex written to the best of my ability that allows the latin character set only with the option of a '-' that, if included MUST be followed by at least one other latin character.
My RegEx:
[\u00BF-\u1FFF\u2C00-\uD7FFA-Za-z]+(?:[-]?[\u00BF-\u1FFF\u2C00-\uD7FFA-Za-z]+)
I came to this after reading a few posts and rereading the manual to figure out the best way to approach this. This check is attached to a text field where a user types only their first name and then submits.
It works okay but there is certainly room for improvement.
Examples:
Tom // passes
Éve // passes
John-Paul // passes
2pac // passes and removes numbers (not really what I want)
John316 // passes and removes numbers (not really what I want)
What I would REALLY want to happen is a fail on those last two checks.
How would I revise it to get the outcome I'd like?
You need to anchor the regex by adding ^ at the start and $ at the end. That way you will not let any other symbols in the input string.
I also suggest enhancing the pattern by moving ? from after hyphen to the end (that will make regex execution linear as the hyphen has no quantifier and is required, thus, limiting backtracking):
^[\u00BF-\u1FFF\u2C00-\uD7FFA-Za-z]+(?:-[\u00BF-\u1FFF\u2C00-\uD7FFA-Za-z]+)?$
See regex demo.
JS snippet:
console.log(/^[\u00BF-\u1FFF\u2C00-\uD7FFA-Za-z]+(?:-[\u00BF-\u1FFF\u2C00-\uD7FFA-Za-z]+)?$/.test('Éve')); //=> true
console.log(/^[\u00BF-\u1FFF\u2C00-\uD7FFA-Za-z]+(?:-[\u00BF-\u1FFF\u2C00-\uD7FFA-Za-z]+)?$/.test('John-Paul')); // => true
console.log(/^[\u00BF-\u1FFF\u2C00-\uD7FFA-Za-z]+(?:-[\u00BF-\u1FFF\u2C00-\uD7FFA-Za-z]+)?$/.test('John316')); // => false
While writing an API service for my site, I realized that String.split() won't do it much longer, and decided to try my luck with regular expressions. I have almost done it but I can't find the last bit. Here is what I want to do:
The URL represents a function call:
/api/SECTION/FUNCTION/[PARAMS]
This last part, including the slash, is optional. Some functions display a JSON reply without having to receive any arguments. Example: /api/sounds/getAllSoundpacks prints a list of available sound packs. Though, /api/sounds/getPack/8Bit prints the detailed information.
Here is the expression I have tried:
req.url.match(/\/(.*)\/(.*)\/?(.*)/);
What am I missing to make the last part optional - or capture it in whole?
This will capture everything after FUNCTION/ in your URL, independent of the appearance of any further / after FUNCTION/:
FUNCTION\/(.+)$
The RegExp will not match if there is no part after FUNCTION.
This regex should work by making last slash and part after optional:
/^\/[^/]*\/[^/]*(?:\/.*)?$/
This matches all of these strings:
/api/SECTION/FUNCTION/abc
/api/SECTION
/api/SECTION/
/api/SECTION/FUNCTION
Your pattern /(.*)/(.*)/?(.*) was almost correct, it's just a bit too short - it allows 2 or 3 slashes, but you want to accept anything with 3 or 4 slashes. And if you want to capture the last (optional) slash AND any text behind it as a whole, you simply need to create a group around that section and make it optional:
/.*/.*/.*(?:/.+)?
should do the trick.
Demo. (The pattern looks different because multiline mode is enabled, but it still works. It's also a little "better" because it won't match garbage like "///".)