I need a regex that can actually get any number that is inserted after "ab" and "cr". For example, I have a string like this:
rw200-208-ab66
fg200-cr30-201
I need to print ab66 and cr30.
I have tried using strpos:
if (strpos($part,'ab') !== false) {
$a = explode("ab", $part);
echo 'ab'.$a[1];
}
That does not work for the second item.
You could use \K to discard the previously matched chars from printing at the final. The below regex would give you the number which exists next to ab
or cr.
(?:ab|cr)\K\d+
To get the number with alphabets also, use
preg_match_all('~(?:ab|cr)\d+~', $str, $match);
Use this regex:
(?>ab|cr)\d+
See IDEONE demo:
$re = "#(?>ab|cr)\d+#";
$str = "rw200-208-ab66\nfg200-cr30-201";
preg_match_all($re, $str, $matches);
print_r($matches[0]);
Output:
Array
(
[0] => ab66
[1] => cr30
)
Related
I want to select all text before and after a specific substring, I used the following expression to do that, but it not selecting all the needed text:
/^(?:(?!\<\?php echo[\s?](.*?)\;[\s?]\?\>).)*/
for example:
$re = '/^(?:(?!\<\?php echo[\s?](.*?)\;[\s?]\?\>).)*/';
$str = 'customFields[<?php echo $field["id"]; ?>][type]';
preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);
it will select only this part customFields[, while the expected result should be customFields[ and ][type]
check this link for debugging
The pattern ^(?:(?!\<\?php echo[\s?](.*?)\;[\s?]\?\>).)* uses a tempered greedy token which matches any character except a newline from the start of the string ^ that fulfills the assertion of the negative lookahead.
That will only match customFields[
For your example data you could make use of a tempered greedy token regex demo, but instead you could also just make use of a negated character class and SKIP FAIL:
^[^[]+\[|<\?php echo\s(.*?)\;\s\?\>(*SKIP)(*FAIL)|\]\[[^]]*\]
Regex demo | Php demo
For example
$re = '/^[^[]+\[|<\?php echo\s(.*?)\;\s\?\>(*SKIP)(*FAIL)|\]\[[^]]*\]/';
$str = 'customFields[<?php echo $field["id"]; ?>][type]';
preg_match_all($re, $str, $matches, PREG_SET_ORDER);
print_r($matches);
Result
Array
(
[0] => Array
(
[0] => customFields[
)
[1] => Array
(
[0] => ][type]
)
)
To get a more exact match you might also use capturing groups:
^((?:(?!<\?php echo[\s?](?:.*?)\;\s\?>).)*)<\?php echo\s(?:.*?)\;[\s?]\?>(.*)$
regex demo | Php demo
What about using positive lookarounds:
(.*)(?=\<\?php echo)|(?<=\?\>)(.*)
Demo
I'm using preg_match_all to perform all match in a String
$match_this = '/cola/';
$sentence = 'cola this cola is a nice cola';
if(preg_match_all($match_this, $sentence, $matches)){
echo 'match found'.'<br>';
print_r($matches[0]);
}
But I want this match performing operation to stop when I encounter the word nice and $matches array shouldn't store any more matched word after that.
How the code can be modified for this ?
There can be multiple times 'cola' comes before 'nice'. This is just
an example sentence. Again 'cola' and 'nice' are just example words.
The words to match and where to stop are randomly picked from
database. This code is for a word game.
You could use positive lookahead:
$match_this = '\bcola\d\b';
$until = '\bnice\b';
$sentence = 'cola1 this cola2 is a nice cola3';
if(preg_match_all("/$match_this(?=.*$until)/", $sentence, $matches)){
print_r($matches[0]);
}
Output:
Array
(
[0] => cola1
[1] => cola2
)
I've added a number at the end of each cola to be sure it matches only the ones that are before the word nice.
I've also added word boudaries arround the words to match.
Finally the code is:
$match_this = '\bcola\b';
$until = '\bnice\b';
$sentence = 'cola this cola is a nice cola';
if(preg_match_all("/$match_this(?=.*$until)/", $sentence, $matches)){
print_r($matches[0]);
}
First get the offset of nice, then run the preg match on the substring before it.
$sentence = 'cola this cola is a nice cola';
$match_this = '/nice/';
if(preg_match($match_this, $sentence, $matches, PREG_OFFSET_CAPTURE)){
$niceOffset = $matches[0][1];
$match_this = '/cola/';
if(preg_match_all($match_this, substr($sentence, 0, $niceOffset), $matches2, PREG_OFFSET_CAPTURE)){
var_dump($matches2);
}
}
I have a file name where information has to be replaced. Here is a subject sample :
FileA-2014-11-01_K_1_A2_383.xxx
As many files are to be processed, this filename is first matched by a regex, say :
/[a-zA-Z]*-\d{4}-\d{2}-\d{2}_(\w)_(\d)_A2_(\d*)\.xxx$/
This regex will give me, using preg_match, the values to be replaced, here :
K=>A
1=>2
383=>666
My first try was to naively use "str_replace", but it fails when patterns are repeated in the string : here i will get :
FileA-2024-22-02_A_2_A2_666.xxx
So the date is also modified by the str_replace (as it was told to do..)
So, i wonder if there is a way to know where is a given match in the string to have a clean replacement.
I'm now trying to revert the regex to be able to capture non-replacement blocks, and then insert replaced data. That regex would be :
/([a-zA-Z]*-\d{4}-\d{2}-\d{2}_)\w(_)\d(_A2_)\d*(\.xxx)$/
With that one, i'm able to keep non-replaced parts. I now have to find a kind of index to know the replacement position in the string. I guess I can achieve this way, but is seems somewhat complicated and error prone.
Given I only have the initial regex and the map for to=>from replacement, is there a way to do that in a better way?
[EDIT : solution]
<?php
$filename = "FileA-2014-11-01_K_1_A2_383.xxx";
$expected = "FileA-2014-11-01_A_2_A2_666.xxx";
$regex = "/[a-zA-Z]*-\d{4}-\d{2}-\d{2}_(\w)_(\d)_A2_(\d*)\.xxx$/";
global $replacements;
$replacements["K"] = "A";
$replacements["1"] = "2";
$replacements["383"] = "666";
$result = preg_replace_callback($regex, function($matches){
global $replacements;
print_r($matches);
// ended here. no way.
}, $filename);
if(strcmp($result,$expected)==0)
echo "preg_replace_callback() : Yep\n";
else
echo "preg_replace_callback() : Nop\n";
preg_match($regex, $filename, $matches, PREG_OFFSET_CAPTURE);
// remove useless global string match
array_shift($matches);
$result = $filename;
foreach($matches as $matchInfo){
$match = $matchInfo[0];
$position = $matchInfo[1];
$matchLength= strlen($match);
$beforeReplacementPart = substr($result, 0, $position);
$afterReplacementPart = substr($result, ($position + $matchLength));
$result = $beforeReplacementPart . $replacements[$match] . $afterReplacementPart;
}
if(strcmp($result,$expected)==0)
echo "preg_match() and substr game : Yep\n";
else
echo "preg_match() and substr game : Nop\n";
A regex that matches that filename:
$re = '/[a-zA-Z]*-\d{4}-\d{2}-\d{2}_(\w)_(\d)_A2_(\d*)\.xxx$/';
$str = 'FileA-2014-11-01_K_1_A2_383.xxx';
If you add PREG_OFFSET_CAPTURE as the fourth parameter ($flags) to the call to preg_match(), it will also return the offset of each captured string in the third parameter:
preg_match($re, $str, $matches, PREG_OFFSET_CAPTURE);
A print_r($matches) will reveal:
Array
(
[0] => Array
(
[0] => FileA-2014-11-01_K_1_A2_383.xxx
[1] => 0
)
[1] => Array
(
[0] => K
[1] => 17
)
[2] => Array
(
[0] => 1
[1] => 19
)
[3] => Array
(
[0] => 383
[1] => 24
)
)
$matches[0] is the part that matched the entire regex. $matches[1] is the first capturing sub-expression, $matches[2] is the second and so on.
$matches[1][0] is the fragment from the input string that matched the first regex sub-expression (\w) and $matches[1][1] is the offset in the input string where it was found. The same for $matches[N][0] and $matches[N][1] for the Nth sub-expression.
If you need to do a simple replacement then you don't need to bother about offsets but use preg_replace() or, if the replacement expression is complex or dynamic, preg_replace_callback().
Using preg_replace() you need to capture the parts you want to keep:
$re = '/([a-zA-Z]*-\d{4}-\d{2}-\d{2}_)\w_\d_A2_\d*(\.xxx)$/';
$str = 'FileA-2014-11-01_K_1_A2_383.xxx';
$new = preg_replace($re, '$1A_2_A2_666$2', $str);
echo($new."\n");
In the replacement string, $1 and $2 denote the sub-expressions from the regex. We marked them for capturing in order to re-use them in the replacement string.
At least preg_match_all() offers the option
PREG_OFFSET_CAPTURE
If this flag is passed, for every occurring match the appendant string offset will also be returned. Note that this changes the value of matches into an array where every element is an array consisting of the matched string at offset 0 and its string offset into subject at offset 1.
You could try the below regex.
([a-zA-Z]*-\d{4}-\d{2}-\d{2}(?:-\d*)?_)\w_\d(_A2)_\d*(\.xxx)$
Then replace the match with
\1A_2\2_666\3
DEMO
$re = "~([a-zA-Z]*-\\d{4}-\\d{2}-\\d{2}(?:-\\d*)?_)\\w_\\d(_A2)_\\d*(\\.xxx)$~m";
$str = "FileA-2014-11-01_K_1_A2_383.xxx";
$subst = "\1A_2\2_666\3";
$result = preg_replace($re, $subst, $str);
You can use:
$re = "/([a-zA-Z]+-\\d{4}-\\d{2}-\\d{2}_)\\w+_\\d+(_A2_)\\d+(\\.xxx)$/m";
$str = "FileA-2014-11-01_K_1_A2_383.xxx";
$subst = "${1}A_2${2}666${3}";
$result = preg_replace($re, $subst, $str);
//=> FileA-2014-11-01_A_2_A2_666.xxx
RegEx Demo
Perhaps it is possible to use this in your case:
$str = strtr($str, array('_K_1_'=>'_A_2_', '_383.'=>'_666.'));
or
$str = str_replace('_K_1_A2_383.xxx', '_A_2_A2_666.xxx', $str);
So there is no more ambiguity and the replacement is fast.
I have a word Hello How are you :chinu i am :good i want to get the word which contains : like :chinu and :good
My code:
<?php
//$string='Hello How are you :chinu i am :good';
//echo strtok($string, ':');
$string='Hello How are you :chinu i am :good';
preg_match('/:([:^]*)/', $string, $matches);
print_r($matches);
?>
Above code i am getting Array ( [0] => : [1] => ) But not getting the exact text. Please help me.
Thanks
Chinu
To get all matches you need to use preg_match_all(). As far as your regular expression goes your negated class is backwards; matching any character of: :, ^ "zero or more" times and will not match what you expect.
You stated in the comments about the "records" being printed twice, this is because you print the $matches array itself instead of printing the group index which only displays the match results.
preg_match_all('/:\S+/', $string, $matches);
print_r($matches[0]);
:\S+
Try this.See demo.
http://regex101.com/r/tF5fT5/43
$re = "/:\\S+/im";
$str = "Hello How are you :chinu i am :good";
preg_match_all($re, $str, $matches);
So you would need to do something like the following to match the characters up to the space:
preg_match_all('/:[^ ]+/', $string, $matches);
or if you're looking for alpha-only characters you might use the following:
preg_match_all('/:[A-Za-z]+/', $string, $matches);
The array you would look for would be $matches[0] at this point.
print_r($matches)
print_r($matches[0])
You can always reassign the matches sub array with something like this:
$matchesArray = $matches[0]
I have:
stackoverflow.com/.../link/Eee_666/9_uUU/66_99U
What regex for /Eee_666/9_uUU/66_99U?
Eee_666, 9_uUU, and 66_99U is a random value
How can I solve it?
As simple as that:
$link = "stackoverflow.com/.../link/Eee_666/9_uUU/66_99U";
$regex = '~link/([^/]+)/([^/]+)/([^/]+)~';
# captures anything that is not a / in three different groups
preg_match_all($regex, $link, $matches);
print_r($matches);
Be aware though that it eats up any character expect the / (including newlines), so you either want to exclude other characters as well or feed the engine only strings with your format.
See a demo on regex101.com.
You can use \K here to makei more thorough.
stackoverflow\.com/.*?/link/\K([^/\s]+)/([^/\s]+)/([^/\s]+)
See demo.
https://regex101.com/r/jC8mZ4/2
In the case you don't how the length of the String:
$string = stackoverflow.com/.../link/Eee_666/9_uUU/66_99U
$regexp = ([^\/]+$)
result:
group1 = 66_99U
be careful it may also capture the end line caracter
For this kind of requirement, it's simpler to use preg_split combined with array_slice:
$url = 'stackoverflow.com/.../link/Eee_666/9_uUU/66_99U';
$elem = array_slice(preg_split('~/~', $url), -3);
print_r($elem);
Output:
Array
(
[0] => Eee_666
[1] => 9_uUU
[2] => 66_99U
)