str_replace matches incorrect part of string - php

I'm having some issues with str_replace, when trying to automatically put backticks around table- and fieldnames.
Assuming i have the following arrays:
$match = array('rooms.roomID','r_rooms.roomID');
$replace = array('`rooms`.`roomID`','`r_rooms`.`roomID`');
$subject = 'rooms.roomID = r_rooms.roomID';
str_replace($match,$replace,$subject);
The result that I expect is:
`rooms`.`roomID` = `r_rooms`.`roomID`
But instead I'm getting this:
`rooms`.`roomID` = r_`rooms`.`roomID`
However if i change r_rooms to r_ooms, my result is as expected
`rooms`.`roomID` = `r_ooms`.`roomID`
I've tried the same precedure, using preg_replace, but this gives me the same output aswell.

Quick fix would be reordering $match and $replace arrays like this...
$match = array('r_rooms.roomID', 'rooms.roomID');
$replace = array('`r_rooms`.`roomID`', '`rooms`.`roomID`');
The problem of the original approach is that str_replace processes $match array element by element, at each step trying to cover the whole string - and replaces the found parts immediately.
As rooms.roomID string 'matches' both [rooms.roomID] and r_[rooms.roomID], and replaces these accordingly, the second iteration will have nothing to do.
As I said, that's only a quick fix. In this case I'd try to use preg_replace instead, surrounding the actual search with \b (word boundary anchors).
Then again, with all due respect I smell XY problem here. Aren't you trying to make your own routine for quoteIdentifier? That was already solved (and asked here a lot of times).

It is correct. First replaced value is rooms.roomID to rooms.roomID (2 times)
Change order of $match and $replace tables to get expected result
$match = array('r_rooms.roomID','rooms.roomID');
$replace = array('`r_rooms`.`roomID`','`rooms`.`roomID`');

Related

RegEx for capturing digits in a string (PHP)

I am pulling in job numbers and matching them to data in a mysql database, then retrieving the matching data.
If my job number is 123456 then it matches up fine and I get results.
Some are 123-456 some are 12-text, while some are 12-text-345
$variable = $variable
I tried matching the variable but that's what's not effective.
I tried changing the SQL within PHPMyAdmin and it doesn't even work smoothly there.
I googled and think I should be using RegExp. I tried. I can add a slash and make it work on individual items, however, I do not know where the hyphen will be amidst a massive array. It might be the third or fourth character.
I tried pregmatch but I don't think I know what I'm doing with that.
I'm looking for a few lines of code to analyze a PHP variable and both detect and escape any meta characters if there are any. A tutorial link would be fine too, I appreciate any assistance
Here, if we wish to only get the numbers, on way would be to collect our digits in a capturing group and then collect everything else, then replace it with just $1, with an expression similar to:
(\d+)|\D+
Test
$re = '/(\d+)|\D+/m';
$str = 'text-12-text-345';
$subst = '$1';
$result = preg_replace($re, $subst, $str);
echo $result;
Output
12345
DEMO

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...

How to get a number from a html source page?

I'm trying to retrieve the followed by count on my instagram page. I can't seem to get the Regex right and would very much appreciate some help.
Here's what I'm looking for:
y":{"count":
That's the beginning of the string, and I want the 4 numbers after that.
$string = preg_replace("{y"\"count":([0-9]+)\}","",$code);
Someone suggested this ^ but I can't get the formatting right...
You haven't posted your strings so it is a guess to what the regex should be... so I'll answer on why your codes fail.
preg_replace('"followed_by":{"count":\d')
This is very far from the correct preg_replace usage. You need to give it the replacement string and the string to search on. See http://php.net/manual/en/function.preg-replace.php
Your second usage:
$string = preg_replace(/^y":{"count[0-9]/","",$code);
Is closer but preg_replace is global so this is searching your whole file (or it would if not for the anchor) and will replace the found value with nothing. What your really want (I think) is to use preg_match.
$string = preg_match('/y":\{"count(\d{4})/"', $code, $match);
$counted = $match[1];
This presumes your regex was kind of correct already.
Per your update:
Demo: https://regex101.com/r/aR2iU2/1
$code = 'y":{"count:1234';
$string = preg_match('/y":\{"count:(\d{4})/', $code, $match);
$counted = $match[1];
echo $counted;
PHP Demo: https://eval.in/489436
I removed the ^ which requires the regex starts at the start of your string, escaped the { and made the\d be 4 characters long. The () is a capture group and stores whatever is found inside of it, in this case the 4 numbers.
Also if this isn't just for learning you should be prepared for this to stop working at some point as the service provider may change the format. The API is a safer route to go.
This regexp should capture value you're looking for in the first group:
\{"count":([0-9]+)\}
Use it with preg_match_all function to easily capture what you want into array (you're using preg_replace which isn't for retrieving data but for... well replacing it).
Your regexp isn't working because you didn't escaped curly brackets. And also you didn't put count quantifier (plus sign in my example) so it would only capture first digit anyway.

Multiple preg_replace

I have many strings that all start with #and a pseudo and I want to change these pseudo via regex to the real name.
I haven't many pseudo (maybe 5 to 10) so I can go with a simple regex like:
$find = array('#alex', '#donald');
$replace = array('Alex A.', 'Donald B.' );
$result= preg_replace($find, $replace, $feed->itemTitle);
My problem is that I already have a pre_replace on these string, that removes the link. So far this is my regex:
<?php echo preg_replace('#(https?://([-\w\.]+[-\w])+(:\d+)?(/([\w/_\.#-]*(\?\S+)?[^\.\s])?)?).....#',' ',$feed->itemTitle); ?>
I can't come up with a solution that will mix the two regex. (regex is something I am not confortable with).
To have already a preg_replace for the links isn't a problem, don't bother about that.
If you want you can build a giant pattern with capture groups to be used with preg_replace_callback that allows the callback function to choose which is the replacement string to return according to the capture group number. However, this isn't the good way.
Since, you want to replace fixed strings (#alex, #donald are fixed strings) the best and fastest way is to use strtr (even if you parse the string a second time):
$trans = array('#alex' => 'Alex A.',
'#donald' => 'Donald B.');
$result = strtr($feed->itemTitle, $trans);

preg_match_all not working with mysql database results variables?

-- update --
Ok, I've narrowed this down to the keywords being checked, The keywords will only match with spaces between them if they are hard coded in to the array. If the keywords with spaces are placed in to the array are results from a database then the preg_match_all fails with 0 results found.
So if I hard code the array in php like
$myarray = array("This is my Phrase","This is my Second Phrase");
and then check it against the texttoscan the preg_match_all will find both phases, but
if i do this to create the array:
$result1 = mysql_result($result,$i,"firstphrase");
$result2 = mysql_result($result,$i,"secondphrase");
$myarray = array($result1,$result2);
The preg_match_all below will fail and not find the phrases, but if I populate the array with single words instead of phrases it will work. So I assume I have to prepare the strings that contain spaces that are returned from the database, but I'm not exactly sure how to do it, either that or I need to reformat the regex pattern?
foreach ($myarray as $K) {
$pattern = "/\b($K)\b/";
$count = preg_match_all($pattern, $texttoscan, $matches);
if($count > 0){ echo "matched"; }
}
Is it possible that the database text contains line breaks, where the hard-coded text didn't? If so, you would want to use the m modifier to allow multi-line matching. That would make the regular expression:
$pattern = "/\b($K)\b/m";
Hope that helps. Also, unless you are trying to specifically match UTF words/characters you shouldn't have any problem with that.

Categories