RegExp to Get N words before and after - php

I want to get the "context" of a given search string. For example, for search string myself in the following line
Me, my dog and myself are going on a vacation.
I want to get dog and myself are going for N=2. So 2 words before match and 2 after.
Currently I match whole lines like this:
$lines = file($file->getFilename());
$lines = preg_grep('/'.$_POST['query'].'/', $lines);

preg_grep() is supposed to act like that, but it sounds like you would need preg_match() and in case you can have multiple instances of searched word in the text and want to find all of them preg_match_all()
The RegEx you're looking for is: (?:[^ ]+ ){0,2}myself(?: [^ ]+){0,2}
Explained demo here: http://regex101.com/r/pB3eW0
I designed it to match 2 words before and after if it can otherwise 1 word or even none.
The code allowing a variable N could look like this:
$fileData=file_get_contents($file->getFilename());
$n=2;
$query='myself';
preg_match_all('/(?:[^ ]+ ){0,'.$n.'}'.$query.'(?: [^ ]+){0,'.$n.'}/i',$fileData,$matches);
print_r($matches);
Remember to validate and escape user input and not just use it in functions as given!

Related

preg_replace - similar patterns

I have a string that contains something like "LAB_FF, LAB_FF12" and I'm trying to use preg_replace to look for both patterns and replace them with different strings using a pattern match of;
/LAB_[0-9A-F]{2}|LAB_[0-9A-F]{4}/
So input would be
LAB_FF, LAB_FF12
and the output would need to be
DAB_FF, HAD_FF12
Problem is, for the second string, it interprets it as "LAB_FF" instead of "LAB_FF12" and so the output is
DAB_FF, DAB_FF
I've tried splitting the input line out using 2 different preg_match statements, the first looking for the {2} pattern and the second looking for the {4} pattern. This sort of works in that I can get the correct output into 2 separate strings but then can't combine the two strings to give the single amended output.
\b is word boundary. Meaning it will look at where the word ends and not only pattern match.
https://regex101.com/r/upY0gn/1
$pattern = "/\bLAB_[0-9A-F]{2}\b|\bLAB_[0-9A-F]{4}\b/";
Seeing the comment on the other answer about how to replace the string.
This is one way.
The pattern will create empty entries in the output array for each pattern that fails.
In this case one (the first).
Then it's just a matter of substr.
$re = '/(\bLAB_[0-9A-F]{2}\b)|(\bLAB_[0-9A-F]{4}\b)/';
$str = 'LAB_FF12';
preg_match($re, $str, $matches);
var_dump($matches);
$substitutes = ["", "DAB", "HAD"];
For($i=1; $i<count($matches); $i++){
If($matches[$i] != ""){
$result = $substitutes[$i] . substr($matches[$i],3);
Break;
}
}
Echo $result;
https://3v4l.org/gRvHv
You can specify exact amounts in one set of curly braces, e.g. `{2,4}.
Just tested this and seems to work:
/LAB_[0-9A-F]{2,4}/
LAB_FF, LAB_FFF, LAB_FFFF
EDIT: My mistake, that actually matches between 2 and 4. If you change the order of your selections it matches the first it comes to, e.g.
/LAB_([0-9A-F]{4}|[0-9A-F]{2})/
LAB_FF, LAB_FFFF
EDIT2: The following will match LAB_even_amount_of_characters:
/LAB_([0-9A-F]{2})+/
LAB_FF, LAB_FFFF, LAB_FFFFFF...

Move multiple letters in string using regex

Using a regular expression I want to move two letters in a string.
W28
L36
W29-L32
Should be changed to:
28W
36L
29W-32L
The numbers vary between 25 and 44. The letters that need to be moved are always "W" and/or "L" and the "W" is always first when they both exist in the string.
I need to do this with a single regular expression using PHP. Any ideas would be awesome!
EDIT:
I'm new to regular expressions and tried a lot of things without success. The closest I came was using "/\b(W34)\b/" for each possibility. I also found something about using variables in the replace function but had no luck using these.
Your regex \b(W34)\b matches exactly W34 as a whole word. You need a character class to match W or L, and some alternatives to match the numeric range, and use the most of capturing groups.
You can use the following regex replacement:
$re = '/\b([WL])(2[5-9]|3[0-9]|4[0-4])\b/';
$str = "W28\nL36\nW29-L32";
$result = preg_replace($re, "$2$1", $str);
echo $result;
See IDEONE demo
Here, ([WL]) matches and captures either W or L into group 1, and (2[5-9]|3[0-9]|4[0-4]) matches integer numbers from 25 till 44 and captures into group 2. Backreferences are used to reverse the order of the groups in the replacement string.
And here is a regex demo in case you want to adjust it later.

preg_replace with Regex - find number-sequence in URL

I'm a regex-noobie, so sorry for this "simple" question:
I've got an URL like following:
http://stellenanzeige.monster.de/COST-ENGINEER-AUTOMOTIVE-m-w-Job-Mainz-Rheinland-Pfalz-Deutschland-146370543.aspx
what I'm going to archieve is getting the number-sequence (aka Job-ID) right before the ".aspx" with preg_replace.
I've already figured out that the regex for finding it could be
(?!.*-).*(?=\.)
Now preg_replace needs the opposite of that regular expression. How can I archieve that? Also worth mentioning:
The URL can have multiple numbers in it. I only need the sequence right before ".aspx". Also, there could be some php attributes behind the ".aspx" like "&mobile=true"
Thank you for your answers!
You can use:
$re = '/[^-.]+(?=\.aspx)/i';
preg_match($re, $input, $matches);
//=> 146370543
This will match text not a hyphen and not a dot and that is followed by .aspx using a lookahead (?=\.aspx).
RegEx Demo
You can just use preg_match (you don't need preg_replace, as you don't want to change the original string) and capture the number before the .aspx, which is always at the end, so the simplest way, I could think of is:
<?php
$string = "http://stellenanzeige.monster.de/COST-ENGINEER-AUTOMOTIVE-m-w-Job-Mainz-Rheinland-Pfalz-Deutschland-146370543.aspx";
$regex = '/([0-9]+)\.aspx$/';
preg_match($regex, $string, $results);
print $results[1];
?>
A short explanation:
$result contains an array of results; as the whole string, that is searched for is the complete regex, the first element contains this match, so it would be 146370543.aspx in this example. The second element contains the group captured by using the parentheeses around [0-9]+.
You can get the opposite by using this regex:
(\D*)\d+(.*)
Working demo
MATCH 1
1. [0-100] `http://stellenanzeige.monster.de/COST-ENGINEER-AUTOMOTIVE-m-w-Job-Mainz-Rheinland-Pfalz-Deutschland-`
2. [109-114] `.aspx`
Even if you just want the number for that url you can use this regex:
(\d+)

regex to match string that only has one uppercase letter

I am curling an page and getting the output
however what is happening is that the html encoding is being removed so new lines are being skipped,
so it looks like this
This is Bob. He lives in an boatBut he only has one oar to row with.
in order to detect new lines I figure it was easier to just check for strings that only have One upper case letter and spaces inbetween, so far I have this
(\s\w+\s\w+.\s\D+[a-z][A-Z])
However this does not seem to work
as it only matches this
is Bob. He lives in an boatB
see here http://regex101.com/r/gH0lW1
how to match all strings that have spaces and match all strings up to one Uppercase letter
Update: this will split on the condition without losing any characters
<?php
$string = "This is Bob. He lives in an boatBut he only has one oar to row with.He also does stuff, it is cool.";
$array = preg_split('/(?<=[a-z.])(?=[A-Z])/', $string);
print_r($array);
?>
Use a positive lookbehind to ensure you capture a capital after a lowercase:
(?<=[a-z])[A-Z]
http://regex101.com/r/cB7bD8
You could use php's preg_split if you want, to explode the result on this regex.
(.*?(?:\w+(?=[A-Z]))|\1)
This regex has a recursive part that will match more than 1 sentence in a whole text. So you can check the Live demo and see the matched groups.
But,
If you wanna include a newline on each sentence begins after a period (.) as well, then I modify above regex to this:
(.*?(?:(?:\w+|\. *)(?=[A-Z]))|\1)
and now you can compare results with the first regex HERE

preg_match returning weird results

I am searching a string for urls...and my preg_match is giving me an incorrect amount of matches for my demo string.
String:
Hey there, come check out my site at www.example.com
Function:
preg_match("#(^|[\n ])([\w]+?://[\w]+[^ \"\n\r\t<]*)#ise", $string, $links);
echo count($links);
The result comes out as 3.
Can anybody help me solve this? I'm new to REGEX.
$links is the array of sub matches:
If matches is provided, then it is filled with the results of search. $matches[0] will contain the text that matched the full pattern, $matches[1] will have the text that matched the first captured parenthesized subpattern, and so on.
The matches of the two groups plus the match of the full regular expression results in three array items.
Maybe you rather want all matches using preg_match_all.
If you use preg_match_pattern, (as Gumbo suggested), please note that if you run your regex against this string, it will both match the value of your anchor attribute "href" as well as the linked Text which in this case happens to comtain an url. This makes TWO matches.
It would be wise to run an array_unique on your resultset :)
In addition to the advice on how to use preg_match, I believe there is something seriously wrong with the regular expression you are using. You may want to trying something like this instead:
preg_match("_([a-zA-Z]+://)?([0-9a-zA-Z$-\_.+!*'(),]+\.)?([0-9a-zA-Z]+)+\.([a-zA-Z]+)_", $string, $links);
This should handle most cases (although it wouldn't work if there was a query string after the top-level domain). In the future, when writing regular expressions, I recommend the following web-sites to help: http://www.regular-expressions.info/ and especially http://regexpal.com/ for testing them as you're writing them.

Categories