Regex matching only a portion of string - regex

I would like to match a portion of a URL in this order.
First the domain name will remain static. So, nothing check with regex.
$domain_name = "http://foo.com/";
What I would like to validate is what comes after the last /.
So, my AIM is to create something like.
$stings_only = "[\w+]";
$number_only = "[\d+]";
$numbers_and_strings = "[0-9][a-z][A-Z]";
Now, I would like to just use the above variables to check if a URL confirms to the patterns mentioned.
$example_url = "http://foo.com/some-title-with-id-1";
var_dump(preg_match({$domain_name}{$strings_only}, $example_url));
The above should return false, because title is NOT $string_only.
$example_url = "http://foo.com/foobartar";
var_dump(preg_match({$domain_name}{$strings_only}, $example_url));
The above should return true, because title is $string_only.

Update:
~^http://foo\.com/[a-z]+/?$~i
~^http://foo\.com/[0-9]+/?$~
~^http://foo\.com/[a-z0-9]+/?$~i
These would be your three expressions to match alphabetical URLs, numeric URLS, and alphanumeric. A couple notes, \w matches [a-zA-Z0-9_] so I don't think it is what you expected. The + inside of your character class ([]) does not have any special meaning, like you may expect. \w and \d are "shorthand character classes" and do not need to be within the [] syntax (however they can be, e.g. [\w.,]). Notice the i modifier, this makes the expressions case-insensitive so we do not need to use [a-zA-Z].
$strings_only = '~^http://foo\.com/[a-z]+/?$~i';
$url = 'http://foo.com/some-title-with-id-1';
var_dump(preg_match($strings_only, $url)); // int(0)
$url = 'http://foo.com/foobartar';
var_dump(preg_match($strings_only, $url)); // int(1)
Test/tweak all of my above expressions with Regex101.
. matches any character, but only once. Use .* for 0+ or .+ for 1+. However, these will be greedy and match your whole string and can potentially cause problems. You can make it lazy by adding ? to the end of them (meaning it will stop as soon as it sees the next character /). Or, you can specify anything but a / using a negative character class [^/].
My final regex of choice would be:
~^https://stolak\.ru/([^/]+)/?$~
Notice the ~ delimiters, so that you don't need to escape every /. Also, you need to escape the . with \ since it has a special meaning. I threw the [^/]+ URI parameter into a capture group and made the trailing slash optional by using /?. Finally, I anchored this to the beginning and the end of the strings (^ and $, respectively).
Your question was somewhat vague, so I tried to interpret what you wanted to match. If I was wrong, let me know and I can update it. However, I tried to explain it all so that you could learn and tweak it to your needs. Also, play with my Regex101 link -- it will make testing easier.
Implementation:
$pattern = '~^https://stolak\.ru/([^/]+)/?$~';
$url = 'https://stolak.ru/car-type-b1';
preg_match($pattern, $url, $matches);
var_dump($matches);
// array(2) {
// [0]=>
// string(29) "https://stolak.ru/car-type-b1"
// [1]=>
// string(11) "car-type-b1"
// }

Related

Regex to match(extract) string between dot(.)

I want to select some string combination (with dots(.)) from a very long string (sql). The full string could be a single line or multiple line with new line separator, and this combination could be in start (at first line) or a next line (new line) or at both place.
I need help in writing a regex for it.
Examples:
String s = I am testing something like test.test.test in sentence.
Expected output: test.test.test
Example2 (real usecase):
UPDATE test.table
SET access = 01
WHERE access IN (
SELECT name FROM project.dataset.tablename WHERE name = 'test' GROUP BY 1 )
Expected output: test.table and project.dataset.tablename
, can I also add some prefix or suffix words or space which should be present where ever this logic gets checked. In above case if its update regex should pick test.table, but if the statement is like select test.table regex should not pick it up this combinations and same applies for suffix.
Example3: This is to illustrate the above theory.
INS INTO test.table
SEL 'abcscsc', wu_id.Item_Nbr ,1
FROM test.table as_t
WHERE as_t.old <> 0 AND as_t.date = 11
AND (as_t.numb IN ('11') )
Expected Output: test.table, test.table (Key words are INTO and FROM)
Things Not Needed in selection:as_t.numb, as_t.old, as_t.date
If I get the regex I can use in program to extract this word.
Note: Before and after string words to the combination could be anything like update, select { or(, so we have to find the occurrence of words which are joined together with .(dot) and all the number of such occurrence.
I tried something like this:
(?<=.)(.?)(?=.)(.?) -: This only selected the word between two .dot and not all.
.(?<=.)(.?)(?=.)(.?). - This everything before and after.
To solve your initial problem, we can just use some negation. Here's the pattern I came up with:
[^\s]+\.[^\s]+
[^ ... ] Means to make a character class including everything except for what's between the brackets. In this case, I put \s in there, which matches any whitespace. So [^\s] matches anything that isn't whitespace.
+ Is a quantifier. It means to find as many of the preceding construct as you can without breaking the match. This would happily match everything that's not whitespace, but I follow it with a \., which matches a literal .. The \ is necessary because . means to match any character in regex, so we need to escape it so it only has its literal meaning. This means there has to be a . in this group of non-whitespace characters.
I end the pattern with another [^\s]+, which matches everything after the . until the next whitespace.
Now, to solve your secondary problem, you want to make this match only work if it is preceded by a given keyword. Luckily, regex has a construct almost specifically for this case. It's called a lookbehind. The syntax is (?<= ... ) where the ... is the pattern you want to look for. Using your example, this will only match after the keywords INTO and FROM:
(?<=(?:INTO|FROM)\s)[^\s]+\.[^\s]+
Here (?:INTO|FROM) means to match either the text INTO or the text FROM. I then specify that it should be followed by a whitespace character with \s. One possible problem here is that it will only match if the keywords are written in all upper case. You can change this behavior by specifying the case insensitive flag i to your regex parser. If your regex parser doesn't have a way to specify flags, you can usually still specify it inline by putting (?i) in front of the pattern, like so:
(?i)(?<=(?:INTO|FROM)\s)[^\s]+\.[^\s]+
If you are new to regex, I highly recommend using the www.regex101.com website to generate regex and learn how it works. Don't forget to check out the code generator part for getting the regex code based on the programming language you are using, that's a cool feature.
For your question, you need a regex that understands any word character \w that matches between 0 and unlimited times, followed by a dot, followed by another series of word character that repeats between 0 and unlimited times.
So here is my solution to your question:
Your regex in JavaScript:
const regex = /([\w][.][\w])+/gm;
in Java:
final String regex = "([\w][.][\w])+";
in Python:
regex = r"([\w][.][\w])+"
in PHP:
$re = '/([\w][.][\w])+/m';
Note that: this solution is written for your use case (to be used for SQL strings), because now if you have something like '.word' or 'word..word', it will still catch it which I assume you don't have a string like that.
See this screenshot for more details

Regex to match alphanumerics, URL operators except forward slashes

I've been trying for the past couple of hours to get this regex right but unfortunately, I still can't get it. Tried searching through existing threads too but no dice. :(
I'd like a regex to match the following possible strings:
userprofile?id=123
profile
search?type=player&gender=male
someotherpage.htm
but not
userprofile/
helloworld/123
Basically, I'd like the regex to match alphanumerics, URL operators such as ?, = and & but not forward slashes. (i.e. As long as the string contains a forward slash, the regex should just return 0 matches.)
I've tried the following regexes but none seem to work:
([0-9a-z?=.]+)
(^[^\/]*$[0-9a-z?=.]+)
([0-9a-z?=.][^\/]+)
([0-9a-z?=.][\/$]+)
Any help will be greatly appreciated. Thank you so much!
The reason they all match is that your regexp matches part of the string and you've not told it that it needs to match the entire string. You need to make sure that it doesn't allow any other characters anywhere in the string, e.g.
^[0-9a-z&?=.]+$
Here's a small perl script to test it:
#!/usr/bin/perl
my #testlines = (
"userprofile?id=123",
"userprofile",
"userprofile?type=player&gender=male",
"userprofile.htm",
"userprofile/",
"userprofile/123",
);
foreach my $testline(#testlines) {
if ($testline =~ /^[0-9a-z&?=.]+$/) {
print "$testline matches\n";
} else {
print "$testline doesn't match - bad regexp, no cookie\n";
}
}
This should do the trick:
/\w+(\.htm|\?\w+=\w*(&\w+=\w*)*)?$/i
To break this down:
\w+ // Match [a-z0-9_] (1 or more), to specify resource
( // Alternation group (i.e., a OR b)
\.htm // Match ".htm"
| // OR
\? // Match "?"
\w+=\w* // Match first term of query string (e.g., something=foo)
(&\w+=\w*)* // Match remaining terms of query string (zero or more)
)
? // Make alternation group optional
$ // Anchor to end of string
The i flag is for case-insensitivity.

regex string does not contain substring

I am trying to match a string which does not contain a substring
My string always starts "http://www.domain.com/"
The substring I want to exclude from matches is ".a/" which comes after the string (a folder name in the domain name)
There will be characters in the string after the substring I want to exclude
For example:
"http://www.domain.com/.a/test.jpg" should not be matched
But "http://www.domain.com/test.jpg" should be
Use a negative lookahead assertion as:
^http://www\.domain\.com/(?!\.a/).*$
Rubular Link
The part (?!\.a/) fails the match if the URL is immediately followed with a .a/ string.
My advise in such cases is not to construct overly complicated regexes whith negative lookahead assertions or such stuff.
Keep it simple and stupid!
Do 2 matches, one for the positives, and sort out later the negatives (or the other way around). Most of the time, the regexes become easier, if not trivial.
And your program gets clearer.
For example, to extract all lines with foo, but not foobar, I use:
grep foo | grep -v foobar
I would try with
^http:\/\/www\.domain\.com\/([^.]|\.[^a]).*$
You want to match your domain, plus everything that do not continue with a . and everything that do continue with a . but not a a. (Eventually you can add you / if needed after)
If you don't use look ahead, but just simple regex, you can just say, if it matches your domain but doesn't match with a .a/
<?php
function foo($s) {
$regexDomain = '{^http://www.domain.com/}';
$regexDomainBadPath = '{^http://www.domain.com/\.a/}';
return preg_match($regexDomain, $s) && !preg_match($regexDomainBadPath, $s);
}
var_dump(foo('http://www.domain.com/'));
var_dump(foo('http://www.otherdomain.com/'));
var_dump(foo('http://www.domain.com/hello'));
var_dump(foo('http://www.domain.com/hello.html'));
var_dump(foo('http://www.domain.com/.a'));
var_dump(foo('http://www.domain.com/.a/hello'));
var_dump(foo('http://www.domain.com/.b/hello'));
var_dump(foo('http://www.domain.com/da/hello'));
?>
note that http://www.domain.com/.a will pass the test, because it doesn't end with /.

Regex to test if string begins with http:// or https://

I'm trying to set a regexp which will check the start of a string, and if it contains either http:// or https:// it should match it.
How can I do that? I'm trying the following which isn't working:
^[(http)(https)]://
Your use of [] is incorrect -- note that [] denotes a character class and will therefore only ever match one character. The expression [(http)(https)] translates to "match a (, an h, a t, a t, a p, a ), or an s." (Duplicate characters are ignored.)
Try this:
^https?://
If you really want to use alternation, use this syntax instead:
^(http|https)://
Case insensitive:
var re = new RegExp("^(http|https)://", "i");
var str = "My String";
var match = re.test(str);
^https?://
You might have to escape the forward slashes though, depending on context.
^https?:\/\/(.*) where (.*) is match everything else after https://
This should work
^(http|https)://
^ for start of the string pattern,
? for allowing 0 or 1 time repeat. ie., s? s can exist 1 time or no need to exist at all.
/ is a special character in regex so it needs to be escaped by a backslash \/
/^https?:\/\//.test('https://www.bbc.co.uk/sport/cricket'); // true
/^https?:\/\//.test('http://www.bbc.co.uk/sport/cricket'); // true
/^https?:\/\//.test('ftp://www.bbc.co.uk/sport/cricket'); // false
(http|https)?:\/\/(\S+)
This works for me
Not a regex specialist, but i will try to explain the awnser.
(http|https) : Parenthesis indicates a capture group, "I" a OR statement.
\/\/ : "\" allows special characters, such as "/"
(\S+) : Anything that is not whitespace until the next whitespace
This will work for URL encoded strings too.
^(https?)(:\/\/|(\%3A%2F%2F))
Making this case insensitive wasn't working in asp.net so I just specified each of the letters.
Here's what I had to do to get it working in an asp.net RegularExpressionValidator:
[Hh][Tt][Tt][Pp][Ss]?://(.*)
Notes:
(?i) and using /whatever/i didn't work probably because javascript hasn't brought in all case sensitive functionality
Originally had ^ at beginning but it didn't matter, but the (.*) did (Expression didn't work without (.*) but did work without ^)
Didn't need to escape the // though might be a good idea.
Here's the full RegularExpressionValidator if you need it:
<asp:RegularExpressionValidator ID="revURLHeaderEdit" runat="server"
ControlToValidate="txtURLHeaderEdit"
ValidationExpression="[Hh][Tt][Tt][Pp][Ss]?://(.*)"
ErrorMessage="URL should begin with http:// or https://" >
</asp:RegularExpressionValidator>

How to ignore whitespace in a regular expression subject string?

Is there a simple way to ignore the white space in a target string when searching for matches using a regular expression pattern? For example, if my search is for "cats", I would want "c ats" or "ca ts" to match. I can't strip out the whitespace beforehand because I need to find the begin and end index of the match (including any whitespace) in order to highlight that match and any whitespace needs to be there for formatting purposes.
You can stick optional whitespace characters \s* in between every other character in your regex. Although granted, it will get a bit lengthy.
/cats/ -> /c\s*a\s*t\s*s/
While the accepted answer is technically correct, a more practical approach, if possible, is to just strip whitespace out of both the regular expression and the search string.
If you want to search for "my cats", instead of:
myString.match(/m\s*y\s*c\s*a\*st\s*s\s*/g)
Just do:
myString.replace(/\s*/g,"").match(/mycats/g)
Warning: You can't automate this on the regular expression by just replacing all spaces with empty strings because they may occur in a negation or otherwise make your regular expression invalid.
Addressing Steven's comment to Sam Dufel's answer
Thanks, sounds like that's the way to go. But I just realized that I only want the optional whitespace characters if they follow a newline. So for example, "c\n ats" or "ca\n ts" should match. But wouldn't want "c ats" to match if there is no newline. Any ideas on how that might be done?
This should do the trick:
/c(?:\n\s*)?a(?:\n\s*)?t(?:\n\s*)?s/
See this page for all the different variations of 'cats' that this matches.
You can also solve this using conditionals, but they are not supported in the javascript flavor of regex.
You could put \s* inbetween every character in your search string so if you were looking for cat you would use c\s*a\s*t\s*s\s*s
It's long but you could build the string dynamically of course.
You can see it working here: http://www.rubular.com/r/zzWwvppSpE
If you only want to allow spaces, then
\bc *a *t *s\b
should do it. To also allow tabs, use
\bc[ \t]*a[ \t]*t[ \t]*s\b
Remove the \b anchors if you also want to find cats within words like bobcats or catsup.
This approach can be used to automate this
(the following exemplary solution is in python, although obviously it can be ported to any language):
you can strip the whitespace beforehand AND save the positions of non-whitespace characters so you can use them later to find out the matched string boundary positions in the original string like the following:
def regex_search_ignore_space(regex, string):
no_spaces = ''
char_positions = []
for pos, char in enumerate(string):
if re.match(r'\S', char): # upper \S matches non-whitespace chars
no_spaces += char
char_positions.append(pos)
match = re.search(regex, no_spaces)
if not match:
return match
# match.start() and match.end() are indices of start and end
# of the found string in the spaceless string
# (as we have searched in it).
start = char_positions[match.start()] # in the original string
end = char_positions[match.end()] # in the original string
matched_string = string[start:end] # see
# the match WITH spaces is returned.
return matched_string
with_spaces = 'a li on and a cat'
print(regex_search_ignore_space('lion', with_spaces))
# prints 'li on'
If you want to go further you can construct the match object and return it instead, so the use of this helper will be more handy.
And the performance of this function can of course also be optimized, this example is just to show the path to a solution.
The accepted answer will not work if and when you are passing a dynamic value (such as "current value" in an array loop) as the regex test value. You would not be able to input the optional white spaces without getting some really ugly regex.
Konrad Hoffner's solution is therefore better in such cases as it will strip both the regest and test string of whitespace. The test will be conducted as though both have no whitespace.